]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | #ifndef CEPH_REFCOUNTEDOBJ_H | |
16 | #define CEPH_REFCOUNTEDOBJ_H | |
17 | ||
11fdf7f2 | 18 | #include "common/ceph_mutex.h" |
7c673cae FG |
19 | #include "common/ceph_context.h" |
20 | #include "common/valgrind.h" | |
11fdf7f2 TL |
21 | #include "common/debug.h" |
22 | ||
23 | #include <boost/smart_ptr/intrusive_ptr.hpp> | |
7c673cae | 24 | |
7c673cae | 25 | // re-include our assert to clobber the system one; fix dout: |
11fdf7f2 | 26 | #include "include/ceph_assert.h" |
7c673cae FG |
27 | |
28 | struct RefCountedObject { | |
29 | private: | |
31f18b77 | 30 | mutable std::atomic<uint64_t> nref; |
7c673cae FG |
31 | CephContext *cct; |
32 | public: | |
33 | RefCountedObject(CephContext *c = NULL, int n=1) : nref(n), cct(c) {} | |
34 | virtual ~RefCountedObject() { | |
11fdf7f2 | 35 | ceph_assert(nref == 0); |
7c673cae FG |
36 | } |
37 | ||
38 | const RefCountedObject *get() const { | |
31f18b77 | 39 | int v = ++nref; |
7c673cae FG |
40 | if (cct) |
41 | lsubdout(cct, refs, 1) << "RefCountedObject::get " << this << " " | |
42 | << (v - 1) << " -> " << v | |
43 | << dendl; | |
44 | return this; | |
45 | } | |
46 | RefCountedObject *get() { | |
31f18b77 | 47 | int v = ++nref; |
7c673cae FG |
48 | if (cct) |
49 | lsubdout(cct, refs, 1) << "RefCountedObject::get " << this << " " | |
50 | << (v - 1) << " -> " << v | |
51 | << dendl; | |
52 | return this; | |
53 | } | |
54 | void put() const { | |
55 | CephContext *local_cct = cct; | |
31f18b77 | 56 | int v = --nref; |
11fdf7f2 TL |
57 | if (local_cct) |
58 | lsubdout(local_cct, refs, 1) << "RefCountedObject::put " << this << " " | |
59 | << (v + 1) << " -> " << v | |
60 | << dendl; | |
7c673cae FG |
61 | if (v == 0) { |
62 | ANNOTATE_HAPPENS_AFTER(&nref); | |
63 | ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(&nref); | |
64 | delete this; | |
65 | } else { | |
66 | ANNOTATE_HAPPENS_BEFORE(&nref); | |
67 | } | |
7c673cae FG |
68 | } |
69 | void set_cct(CephContext *c) { | |
70 | cct = c; | |
71 | } | |
72 | ||
73 | uint64_t get_nref() const { | |
31f18b77 | 74 | return nref; |
7c673cae FG |
75 | } |
76 | }; | |
77 | ||
11fdf7f2 TL |
78 | #ifndef WITH_SEASTAR |
79 | ||
7c673cae FG |
80 | /** |
81 | * RefCountedCond | |
82 | * | |
83 | * a refcounted condition, will be removed when all references are dropped | |
84 | */ | |
85 | ||
86 | struct RefCountedCond : public RefCountedObject { | |
87 | bool complete; | |
11fdf7f2 TL |
88 | ceph::mutex lock = ceph::make_mutex("RefCountedCond::lock"); |
89 | ceph::condition_variable cond; | |
7c673cae FG |
90 | int rval; |
91 | ||
11fdf7f2 | 92 | RefCountedCond() : complete(false), rval(0) {} |
7c673cae FG |
93 | |
94 | int wait() { | |
11fdf7f2 | 95 | std::unique_lock l(lock); |
7c673cae | 96 | while (!complete) { |
11fdf7f2 | 97 | cond.wait(l); |
7c673cae FG |
98 | } |
99 | return rval; | |
100 | } | |
101 | ||
102 | void done(int r) { | |
11fdf7f2 | 103 | std::lock_guard l(lock); |
7c673cae FG |
104 | rval = r; |
105 | complete = true; | |
11fdf7f2 | 106 | cond.notify_all(); |
7c673cae FG |
107 | } |
108 | ||
109 | void done() { | |
110 | done(0); | |
111 | } | |
112 | }; | |
113 | ||
114 | /** | |
115 | * RefCountedWaitObject | |
116 | * | |
117 | * refcounted object that allows waiting for the object's last reference. | |
118 | * Any referrer can either put or put_wait(). A simple put() will return | |
119 | * immediately, a put_wait() will return only when the object is destroyed. | |
120 | * e.g., useful when we want to wait for a specific event completion. We | |
121 | * use RefCountedCond, as the condition can be referenced after the object | |
122 | * destruction. | |
123 | * | |
124 | */ | |
125 | struct RefCountedWaitObject { | |
31f18b77 | 126 | std::atomic<uint64_t> nref = { 1 }; |
7c673cae FG |
127 | RefCountedCond *c; |
128 | ||
31f18b77 | 129 | RefCountedWaitObject() { |
7c673cae FG |
130 | c = new RefCountedCond; |
131 | } | |
132 | virtual ~RefCountedWaitObject() { | |
133 | c->put(); | |
134 | } | |
135 | ||
136 | RefCountedWaitObject *get() { | |
31f18b77 | 137 | nref++; |
7c673cae FG |
138 | return this; |
139 | } | |
140 | ||
141 | bool put() { | |
142 | bool ret = false; | |
143 | RefCountedCond *cond = c; | |
144 | cond->get(); | |
31f18b77 | 145 | if (--nref == 0) { |
7c673cae FG |
146 | cond->done(); |
147 | delete this; | |
148 | ret = true; | |
149 | } | |
150 | cond->put(); | |
151 | return ret; | |
152 | } | |
153 | ||
154 | void put_wait() { | |
155 | RefCountedCond *cond = c; | |
156 | ||
157 | cond->get(); | |
31f18b77 | 158 | if (--nref == 0) { |
7c673cae FG |
159 | cond->done(); |
160 | delete this; | |
161 | } else { | |
162 | cond->wait(); | |
163 | } | |
164 | cond->put(); | |
165 | } | |
166 | }; | |
167 | ||
11fdf7f2 TL |
168 | #endif // WITH_SEASTAR |
169 | ||
170 | static inline void intrusive_ptr_add_ref(const RefCountedObject *p) { | |
171 | p->get(); | |
172 | } | |
173 | static inline void intrusive_ptr_release(const RefCountedObject *p) { | |
174 | p->put(); | |
175 | } | |
176 | ||
177 | using RefCountedPtr = boost::intrusive_ptr<RefCountedObject>; | |
7c673cae FG |
178 | |
179 | #endif |