]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/SimpleLock.h
update sources to v12.2.5
[ceph.git] / ceph / src / mds / SimpleLock.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15
16 #ifndef CEPH_SIMPLELOCK_H
17 #define CEPH_SIMPLELOCK_H
18
19 #include <boost/intrusive_ptr.hpp>
20
21 #include "MDSCacheObject.h"
22 #include "MDSContext.h"
23
24 // -- lock types --
25 // see CEPH_LOCK_*
26
27 inline const char *get_lock_type_name(int t) {
28 switch (t) {
29 case CEPH_LOCK_DN: return "dn";
30 case CEPH_LOCK_DVERSION: return "dversion";
31 case CEPH_LOCK_IVERSION: return "iversion";
32 case CEPH_LOCK_IFILE: return "ifile";
33 case CEPH_LOCK_IAUTH: return "iauth";
34 case CEPH_LOCK_ILINK: return "ilink";
35 case CEPH_LOCK_IDFT: return "idft";
36 case CEPH_LOCK_INEST: return "inest";
37 case CEPH_LOCK_IXATTR: return "ixattr";
38 case CEPH_LOCK_ISNAP: return "isnap";
39 case CEPH_LOCK_INO: return "ino";
40 case CEPH_LOCK_IFLOCK: return "iflock";
41 case CEPH_LOCK_IPOLICY: return "ipolicy";
42 default: ceph_abort(); return 0;
43 }
44 }
45
46 #include "include/memory.h"
47
48 struct MutationImpl;
49 typedef boost::intrusive_ptr<MutationImpl> MutationRef;
50
51 extern "C" {
52 #include "locks.h"
53 }
54
55
56 #define CAP_ANY 0
57 #define CAP_LONER 1
58 #define CAP_XLOCKER 2
59
60 struct LockType {
61 int type;
62 const sm_t *sm;
63
64 explicit LockType(int t) : type(t) {
65 switch (type) {
66 case CEPH_LOCK_DN:
67 case CEPH_LOCK_IAUTH:
68 case CEPH_LOCK_ILINK:
69 case CEPH_LOCK_IXATTR:
70 case CEPH_LOCK_ISNAP:
71 case CEPH_LOCK_IFLOCK:
72 case CEPH_LOCK_IPOLICY:
73 sm = &sm_simplelock;
74 break;
75 case CEPH_LOCK_IDFT:
76 case CEPH_LOCK_INEST:
77 sm = &sm_scatterlock;
78 break;
79 case CEPH_LOCK_IFILE:
80 sm = &sm_filelock;
81 break;
82 case CEPH_LOCK_DVERSION:
83 case CEPH_LOCK_IVERSION:
84 sm = &sm_locallock;
85 break;
86 default:
87 sm = 0;
88 }
89 }
90
91 };
92
93
94 class SimpleLock {
95 public:
96 LockType *type;
97
98 const char *get_state_name(int n) const {
99 switch (n) {
100 case LOCK_UNDEF: return "UNDEF";
101 case LOCK_SYNC: return "sync";
102 case LOCK_LOCK: return "lock";
103
104 case LOCK_PREXLOCK: return "prexlock";
105 case LOCK_XLOCK: return "xlock";
106 case LOCK_XLOCKDONE: return "xlockdone";
107 case LOCK_XLOCKSNAP: return "xlocksnap";
108 case LOCK_LOCK_XLOCK: return "lock->xlock";
109
110 case LOCK_SYNC_LOCK: return "sync->lock";
111 case LOCK_LOCK_SYNC: return "lock->sync";
112 case LOCK_REMOTEXLOCK: return "remote_xlock";
113 case LOCK_EXCL: return "excl";
114 case LOCK_EXCL_SYNC: return "excl->sync";
115 case LOCK_EXCL_LOCK: return "excl->lock";
116 case LOCK_SYNC_EXCL: return "sync->excl";
117 case LOCK_LOCK_EXCL: return "lock->excl";
118
119 case LOCK_XSYN: return "xsyn";
120 case LOCK_XSYN_EXCL: return "xsyn->excl";
121 case LOCK_EXCL_XSYN: return "excl->xsyn";
122 case LOCK_XSYN_SYNC: return "xsyn->sync";
123 case LOCK_XSYN_LOCK: return "xsyn->lock";
124 case LOCK_XSYN_MIX: return "xsyn->mix";
125
126 case LOCK_SYNC_MIX: return "sync->mix";
127 case LOCK_SYNC_MIX2: return "sync->mix(2)";
128 case LOCK_LOCK_TSYN: return "lock->tsyn";
129
130 case LOCK_MIX_LOCK: return "mix->lock";
131 case LOCK_MIX_LOCK2: return "mix->lock(2)";
132 case LOCK_MIX: return "mix";
133 case LOCK_MIX_TSYN: return "mix->tsyn";
134
135 case LOCK_TSYN_MIX: return "tsyn->mix";
136 case LOCK_TSYN_LOCK: return "tsyn->lock";
137 case LOCK_TSYN: return "tsyn";
138
139 case LOCK_MIX_SYNC: return "mix->sync";
140 case LOCK_MIX_SYNC2: return "mix->sync(2)";
141 case LOCK_EXCL_MIX: return "excl->mix";
142 case LOCK_MIX_EXCL: return "mix->excl";
143
144 case LOCK_PRE_SCAN: return "*->scan";
145 case LOCK_SCAN: return "scan";
146
147 case LOCK_SNAP_SYNC: return "snap->sync";
148
149 default: ceph_abort(); return 0;
150 }
151 }
152
153
154 // waiting
155 static const uint64_t WAIT_RD = (1<<0); // to read
156 static const uint64_t WAIT_WR = (1<<1); // to write
157 static const uint64_t WAIT_XLOCK = (1<<2); // to xlock (** dup)
158 static const uint64_t WAIT_STABLE = (1<<2); // for a stable state
159 static const uint64_t WAIT_REMOTEXLOCK = (1<<3); // for a remote xlock
160 static const int WAIT_BITS = 4;
161 static const uint64_t WAIT_ALL = ((1<<WAIT_BITS)-1);
162
163
164 protected:
165 // parent (what i lock)
166 MDSCacheObject *parent;
167
168 // lock state
169 __s16 state;
170 __s16 state_flags;
171
172 enum {
173 LEASED = 1 << 0,
174 NEED_RECOVER = 1 << 1,
175 };
176
177 private:
178 int num_rdlock;
179
180 // XXX not in mempool
181 struct unstable_bits_t {
182 set<__s32> gather_set; // auth+rep. >= 0 is mds, < 0 is client
183
184 // local state
185 int num_wrlock = 0, num_xlock = 0;
186 MutationRef xlock_by;
187 client_t xlock_by_client = -1;
188 client_t excl_client = -1;
189
190 bool empty() {
191 return
192 gather_set.empty() &&
193 num_wrlock == 0 &&
194 num_xlock == 0 &&
195 xlock_by.get() == NULL &&
196 xlock_by_client == -1 &&
197 excl_client == -1;
198 }
199
200 unstable_bits_t() {}
201 };
202
203 mutable std::unique_ptr<unstable_bits_t> _unstable;
204
205 bool have_more() const { return _unstable ? true : false; }
206 unstable_bits_t *more() const {
207 if (!_unstable)
208 _unstable.reset(new unstable_bits_t);
209 return _unstable.get();
210 }
211 void try_clear_more() {
212 if (_unstable && _unstable->empty()) {
213 _unstable.reset();
214 }
215 }
216
217 public:
218
219 client_t get_excl_client() const {
220 return have_more() ? more()->excl_client : -1;
221 }
222 void set_excl_client(client_t c) {
223 if (c < 0 && !have_more())
224 return; // default is -1
225 more()->excl_client = c;
226 }
227
228 SimpleLock(MDSCacheObject *o, LockType *lt) :
229 type(lt),
230 parent(o),
231 state(LOCK_SYNC),
232 state_flags(0),
233 num_rdlock(0)
234 {}
235 virtual ~SimpleLock() {}
236
237 virtual bool is_scatterlock() const {
238 return false;
239 }
240 virtual bool is_locallock() const {
241 return false;
242 }
243
244 // parent
245 MDSCacheObject *get_parent() { return parent; }
246 int get_type() const { return type->type; }
247 const sm_t* get_sm() const { return type->sm; }
248
249 int get_wait_shift() const {
250 switch (get_type()) {
251 case CEPH_LOCK_DN: return 8;
252 case CEPH_LOCK_DVERSION: return 8 + 1*SimpleLock::WAIT_BITS;
253 case CEPH_LOCK_IAUTH: return 8 + 2*SimpleLock::WAIT_BITS;
254 case CEPH_LOCK_ILINK: return 8 + 3*SimpleLock::WAIT_BITS;
255 case CEPH_LOCK_IDFT: return 8 + 4*SimpleLock::WAIT_BITS;
256 case CEPH_LOCK_IFILE: return 8 + 5*SimpleLock::WAIT_BITS;
257 case CEPH_LOCK_IVERSION: return 8 + 6*SimpleLock::WAIT_BITS;
258 case CEPH_LOCK_IXATTR: return 8 + 7*SimpleLock::WAIT_BITS;
259 case CEPH_LOCK_ISNAP: return 8 + 8*SimpleLock::WAIT_BITS;
260 case CEPH_LOCK_INEST: return 8 + 9*SimpleLock::WAIT_BITS;
261 case CEPH_LOCK_IFLOCK: return 8 +10*SimpleLock::WAIT_BITS;
262 case CEPH_LOCK_IPOLICY: return 8 +11*SimpleLock::WAIT_BITS;
263 default:
264 ceph_abort();
265 }
266 }
267
268 int get_cap_shift() const {
269 switch (get_type()) {
270 case CEPH_LOCK_IAUTH: return CEPH_CAP_SAUTH;
271 case CEPH_LOCK_ILINK: return CEPH_CAP_SLINK;
272 case CEPH_LOCK_IFILE: return CEPH_CAP_SFILE;
273 case CEPH_LOCK_IXATTR: return CEPH_CAP_SXATTR;
274 default: return 0;
275 }
276 }
277 int get_cap_mask() const {
278 switch (get_type()) {
279 case CEPH_LOCK_IFILE: return (1 << CEPH_CAP_FILE_BITS) - 1;
280 default: return (1 << CEPH_CAP_SIMPLE_BITS) - 1;
281 }
282 }
283
284 struct ptr_lt {
285 bool operator()(const SimpleLock* l, const SimpleLock* r) const {
286 // first sort by object type (dn < inode)
287 if (!(l->type->type > CEPH_LOCK_DN) && (r->type->type > CEPH_LOCK_DN)) return true;
288 if ((l->type->type > CEPH_LOCK_DN) == (r->type->type > CEPH_LOCK_DN)) {
289 // then sort by object
290 if (l->parent->is_lt(r->parent)) return true;
291 if (l->parent == r->parent) {
292 // then sort by (inode) lock type
293 if (l->type->type < r->type->type) return true;
294 }
295 }
296 return false;
297 }
298 };
299
300 void decode_locked_state(bufferlist& bl) {
301 parent->decode_lock_state(type->type, bl);
302 }
303 void encode_locked_state(bufferlist& bl) {
304 parent->encode_lock_state(type->type, bl);
305 }
306 void finish_waiters(uint64_t mask, int r=0) {
307 parent->finish_waiting(mask << get_wait_shift(), r);
308 }
309 void take_waiting(uint64_t mask, list<MDSInternalContextBase*>& ls) {
310 parent->take_waiting(mask << get_wait_shift(), ls);
311 }
312 void add_waiter(uint64_t mask, MDSInternalContextBase *c) {
313 parent->add_waiter((mask << get_wait_shift()) | MDSCacheObject::WAIT_ORDERED, c);
314 }
315 bool is_waiter_for(uint64_t mask) const {
316 return parent->is_waiter_for(mask << get_wait_shift());
317 }
318
319
320
321 // state
322 int get_state() const { return state; }
323 int set_state(int s) {
324 state = s;
325 //assert(!is_stable() || gather_set.size() == 0); // gather should be empty in stable states.
326 return s;
327 }
328 void set_state_rejoin(int s, list<MDSInternalContextBase*>& waiters, bool survivor) {
329 assert(!get_parent()->is_auth());
330
331 // If lock in the replica object was not in SYNC state when auth mds of the object failed.
332 // Auth mds of the object may take xlock on the lock and change the object when replaying
333 // unsafe requests.
334 if (!survivor || state != LOCK_SYNC)
335 mark_need_recover();
336
337 state = s;
338
339 if (is_stable())
340 take_waiting(SimpleLock::WAIT_ALL, waiters);
341 }
342
343 bool is_stable() const {
344 return get_sm()->states[state].next == 0;
345 }
346 bool is_unstable_and_locked() const {
347 if (is_stable())
348 return false;
349 return is_rdlocked() || is_wrlocked() || is_xlocked();
350 }
351 int get_next_state() {
352 return get_sm()->states[state].next;
353 }
354
355
356 bool is_sync_and_unlocked() const {
357 return
358 get_state() == LOCK_SYNC &&
359 !is_rdlocked() &&
360 !is_leased() &&
361 !is_wrlocked() &&
362 !is_xlocked();
363 }
364
365
366 /*
367 bool fw_rdlock_to_auth() {
368 return get_sm()->states[state].can_rdlock == FW;
369 }
370 */
371 bool req_rdlock_from_auth() {
372 return get_sm()->states[state].can_rdlock == REQ;
373 }
374
375 // gather set
376 static set<int32_t> empty_gather_set;
377
378 // int32_t: <0 is client, >=0 is MDS rank
379 const set<int32_t>& get_gather_set() const {
380 return have_more() ? more()->gather_set : empty_gather_set;
381 }
382
383 void init_gather() {
384 for (const auto p : parent->get_replicas()) {
385 more()->gather_set.insert(p.first);
386 }
387 }
388 bool is_gathering() const {
389 return have_more() && !more()->gather_set.empty();
390 }
391 bool is_gathering(int32_t i) const {
392 return have_more() && more()->gather_set.count(i);
393 }
394 void clear_gather() {
395 if (have_more())
396 more()->gather_set.clear();
397 }
398 void remove_gather(int32_t i) {
399 if (have_more())
400 more()->gather_set.erase(i);
401 }
402
403
404
405 virtual bool is_dirty() const { return false; }
406 virtual bool is_stale() const { return false; }
407 virtual bool is_flushing() const { return false; }
408 virtual bool is_flushed() const { return false; }
409 virtual void clear_flushed() { }
410
411 // can_*
412 bool can_lease(client_t client) const {
413 return get_sm()->states[state].can_lease == ANY ||
414 (get_sm()->states[state].can_lease == AUTH && parent->is_auth()) ||
415 (get_sm()->states[state].can_lease == XCL && client >= 0 && get_xlock_by_client() == client);
416 }
417 bool can_read(client_t client) const {
418 return get_sm()->states[state].can_read == ANY ||
419 (get_sm()->states[state].can_read == AUTH && parent->is_auth()) ||
420 (get_sm()->states[state].can_read == XCL && client >= 0 && get_xlock_by_client() == client);
421 }
422 bool can_read_projected(client_t client) const {
423 return get_sm()->states[state].can_read_projected == ANY ||
424 (get_sm()->states[state].can_read_projected == AUTH && parent->is_auth()) ||
425 (get_sm()->states[state].can_read_projected == XCL && client >= 0 && get_xlock_by_client() == client);
426 }
427 bool can_rdlock(client_t client) const {
428 return get_sm()->states[state].can_rdlock == ANY ||
429 (get_sm()->states[state].can_rdlock == AUTH && parent->is_auth()) ||
430 (get_sm()->states[state].can_rdlock == XCL && client >= 0 && get_xlock_by_client() == client);
431 }
432 bool can_wrlock(client_t client) const {
433 return get_sm()->states[state].can_wrlock == ANY ||
434 (get_sm()->states[state].can_wrlock == AUTH && parent->is_auth()) ||
435 (get_sm()->states[state].can_wrlock == XCL && client >= 0 && (get_xlock_by_client() == client ||
436 get_excl_client() == client));
437 }
438 bool can_force_wrlock(client_t client) const {
439 return get_sm()->states[state].can_force_wrlock == ANY ||
440 (get_sm()->states[state].can_force_wrlock == AUTH && parent->is_auth()) ||
441 (get_sm()->states[state].can_force_wrlock == XCL && client >= 0 && (get_xlock_by_client() == client ||
442 get_excl_client() == client));
443 }
444 bool can_xlock(client_t client) const {
445 return get_sm()->states[state].can_xlock == ANY ||
446 (get_sm()->states[state].can_xlock == AUTH && parent->is_auth()) ||
447 (get_sm()->states[state].can_xlock == XCL && client >= 0 && get_xlock_by_client() == client);
448 }
449
450 // rdlock
451 bool is_rdlocked() const { return num_rdlock > 0; }
452 int get_rdlock() {
453 if (!num_rdlock)
454 parent->get(MDSCacheObject::PIN_LOCK);
455 return ++num_rdlock;
456 }
457 int put_rdlock() {
458 assert(num_rdlock>0);
459 --num_rdlock;
460 if (num_rdlock == 0)
461 parent->put(MDSCacheObject::PIN_LOCK);
462 return num_rdlock;
463 }
464 int get_num_rdlocks() const {
465 return num_rdlock;
466 }
467
468 // wrlock
469 void get_wrlock(bool force=false) {
470 //assert(can_wrlock() || force);
471 if (more()->num_wrlock == 0)
472 parent->get(MDSCacheObject::PIN_LOCK);
473 ++more()->num_wrlock;
474 }
475 void put_wrlock() {
476 --more()->num_wrlock;
477 if (more()->num_wrlock == 0) {
478 parent->put(MDSCacheObject::PIN_LOCK);
479 try_clear_more();
480 }
481 }
482 bool is_wrlocked() const {
483 return have_more() && more()->num_wrlock > 0;
484 }
485 int get_num_wrlocks() const {
486 return have_more() ? more()->num_wrlock : 0;
487 }
488
489 // xlock
490 void get_xlock(MutationRef who, client_t client) {
491 assert(get_xlock_by() == MutationRef());
492 assert(state == LOCK_XLOCK || is_locallock() ||
493 state == LOCK_LOCK /* if we are a slave */);
494 parent->get(MDSCacheObject::PIN_LOCK);
495 more()->num_xlock++;
496 more()->xlock_by = who;
497 more()->xlock_by_client = client;
498 }
499 void set_xlock_done() {
500 assert(more()->xlock_by);
501 assert(state == LOCK_XLOCK || is_locallock() ||
502 state == LOCK_LOCK /* if we are a slave */);
503 if (!is_locallock())
504 state = LOCK_XLOCKDONE;
505 more()->xlock_by.reset();
506 }
507 void put_xlock() {
508 assert(state == LOCK_XLOCK || state == LOCK_XLOCKDONE ||
509 state == LOCK_XLOCKSNAP || is_locallock() ||
510 state == LOCK_LOCK /* if we are a master of a slave */);
511 --more()->num_xlock;
512 parent->put(MDSCacheObject::PIN_LOCK);
513 if (more()->num_xlock == 0) {
514 more()->xlock_by.reset();
515 more()->xlock_by_client = -1;
516 try_clear_more();
517 }
518 }
519 bool is_xlocked() const {
520 return have_more() && more()->num_xlock > 0;
521 }
522 int get_num_xlocks() const {
523 return have_more() ? more()->num_xlock : 0;
524 }
525 client_t get_xlock_by_client() const {
526 return have_more() ? more()->xlock_by_client : -1;
527 }
528 bool is_xlocked_by_client(client_t c) const {
529 return have_more() ? more()->xlock_by_client == c : false;
530 }
531 MutationRef get_xlock_by() const {
532 return have_more() ? more()->xlock_by : MutationRef();
533 }
534
535 // lease
536 bool is_leased() const {
537 return state_flags & LEASED;
538 }
539 void get_client_lease() {
540 assert(!is_leased());
541 state_flags |= LEASED;
542 }
543 void put_client_lease() {
544 assert(is_leased());
545 state_flags &= ~LEASED;
546 }
547
548 bool is_used() const {
549 return is_xlocked() || is_rdlocked() || is_wrlocked() || is_leased();
550 }
551
552 bool needs_recover() const {
553 return state_flags & NEED_RECOVER;
554 }
555 void mark_need_recover() {
556 state_flags |= NEED_RECOVER;
557 }
558 void clear_need_recover() {
559 state_flags &= ~NEED_RECOVER;
560 }
561
562 // encode/decode
563 void encode(bufferlist& bl) const {
564 ENCODE_START(2, 2, bl);
565 ::encode(state, bl);
566 if (have_more())
567 ::encode(more()->gather_set, bl);
568 else
569 ::encode(empty_gather_set, bl);
570 ENCODE_FINISH(bl);
571 }
572 void decode(bufferlist::iterator& p) {
573 DECODE_START(2, p);
574 ::decode(state, p);
575 set<__s32> g;
576 ::decode(g, p);
577 if (!g.empty())
578 more()->gather_set.swap(g);
579 DECODE_FINISH(p);
580 }
581 void encode_state_for_replica(bufferlist& bl) const {
582 __s16 s = get_replica_state();
583 ::encode(s, bl);
584 }
585 void decode_state(bufferlist::iterator& p, bool is_new=true) {
586 __s16 s;
587 ::decode(s, p);
588 if (is_new)
589 state = s;
590 }
591 void decode_state_rejoin(bufferlist::iterator& p, list<MDSInternalContextBase*>& waiters, bool survivor) {
592 __s16 s;
593 ::decode(s, p);
594 set_state_rejoin(s, waiters, survivor);
595 }
596
597
598 // caps
599 bool is_loner_mode() const {
600 return get_sm()->states[state].loner;
601 }
602 int gcaps_allowed_ever() const {
603 return parent->is_auth() ? get_sm()->allowed_ever_auth : get_sm()->allowed_ever_replica;
604 }
605 int gcaps_allowed(int who, int s=-1) const {
606 if (s < 0) s = state;
607 if (parent->is_auth()) {
608 if (get_xlock_by_client() >= 0 && who == CAP_XLOCKER)
609 return get_sm()->states[s].xlocker_caps | get_sm()->states[s].caps; // xlocker always gets more
610 else if (is_loner_mode() && who == CAP_ANY)
611 return get_sm()->states[s].caps;
612 else
613 return get_sm()->states[s].loner_caps | get_sm()->states[s].caps; // loner always gets more
614 } else
615 return get_sm()->states[s].replica_caps;
616 }
617 int gcaps_careful() const {
618 if (get_num_wrlocks())
619 return get_sm()->careful;
620 return 0;
621 }
622
623
624 int gcaps_xlocker_mask(client_t client) const {
625 if (client == get_xlock_by_client())
626 return type->type == CEPH_LOCK_IFILE ? 0xf : (CEPH_CAP_GSHARED|CEPH_CAP_GEXCL);
627 return 0;
628 }
629
630 // simplelock specifics
631 int get_replica_state() const {
632 return get_sm()->states[state].replica_state;
633 }
634 void export_twiddle() {
635 clear_gather();
636 state = get_replica_state();
637 }
638
639 /** replicate_relax
640 * called on first replica creation.
641 */
642 void replicate_relax() {
643 assert(parent->is_auth());
644 assert(!parent->is_replicated());
645 if (state == LOCK_LOCK && !is_used())
646 state = LOCK_SYNC;
647 }
648 bool remove_replica(int from) {
649 if (is_gathering(from)) {
650 remove_gather(from);
651 if (!is_gathering())
652 return true;
653 }
654 return false;
655 }
656 bool do_import(int from, int to) {
657 if (!is_stable()) {
658 remove_gather(from);
659 remove_gather(to);
660 if (!is_gathering())
661 return true;
662 }
663 if (!is_stable() && !is_gathering())
664 return true;
665 return false;
666 }
667
668 void _print(ostream& out) const {
669 out << get_lock_type_name(get_type()) << " ";
670 out << get_state_name(get_state());
671 if (!get_gather_set().empty())
672 out << " g=" << get_gather_set();
673 if (is_leased())
674 out << " l";
675 if (is_rdlocked())
676 out << " r=" << get_num_rdlocks();
677 if (is_wrlocked())
678 out << " w=" << get_num_wrlocks();
679 if (is_xlocked()) {
680 out << " x=" << get_num_xlocks();
681 if (get_xlock_by())
682 out << " by " << get_xlock_by();
683 }
684 /*if (is_stable())
685 out << " stable";
686 else
687 out << " unstable";
688 */
689 }
690
691 /**
692 * Write bare values (caller must be in an object section)
693 * to formatter, or nothing if is_sync_and_unlocked.
694 */
695 void dump(Formatter *f) const;
696
697 virtual void print(ostream& out) const {
698 out << "(";
699 _print(out);
700 out << ")";
701 }
702 };
703 WRITE_CLASS_ENCODER(SimpleLock)
704
705 inline ostream& operator<<(ostream& out, const SimpleLock& l)
706 {
707 l.print(out);
708 return out;
709 }
710
711
712 #endif