]>
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" |
9f95a23c TL |
19 | #include "common/ref.h" |
20 | #include "include/common_fwd.h" | |
11fdf7f2 | 21 | |
9f95a23c | 22 | #include <atomic> |
7c673cae | 23 | |
9f95a23c TL |
24 | /* This class provides mechanisms to make a sub-class work with |
25 | * boost::intrusive_ptr (aka ceph::ref_t). | |
26 | * | |
27 | * Generally, you'll want to inherit from RefCountedObjectSafe and not from | |
28 | * RefCountedObject directly. This is because the ::get and ::put methods are | |
29 | * public and can be used to create/delete references outside of the | |
30 | * ceph::ref_t pointers with the potential to leak memory. | |
31 | * | |
32 | * It is also suggested that you make constructors and destructors private in | |
33 | * your final class. This prevents instantiation of the object with assignment | |
34 | * to a raw pointer. Consequently, you'll want to use ceph::make_ref<> to | |
35 | * create a ceph::ref_t<> holding your object: | |
36 | * | |
37 | * auto ptr = ceph::make_ref<Foo>(...); | |
38 | * | |
39 | * Use FRIEND_MAKE_REF(ClassName) to allow ceph::make_ref to call the private | |
40 | * constructors. | |
41 | * | |
42 | */ | |
43 | namespace TOPNSPC::common { | |
44 | class RefCountedObject { | |
7c673cae | 45 | public: |
9f95a23c TL |
46 | void set_cct(CephContext *c) { |
47 | cct = c; | |
48 | } | |
49 | ||
50 | uint64_t get_nref() const { | |
51 | return nref; | |
7c673cae | 52 | } |
9f95a23c | 53 | |
7c673cae | 54 | const RefCountedObject *get() const { |
9f95a23c | 55 | _get(); |
7c673cae FG |
56 | return this; |
57 | } | |
58 | RefCountedObject *get() { | |
9f95a23c | 59 | _get(); |
7c673cae FG |
60 | return this; |
61 | } | |
9f95a23c | 62 | void put() const; |
7c673cae | 63 | |
9f95a23c TL |
64 | protected: |
65 | RefCountedObject() = default; | |
66 | RefCountedObject(const RefCountedObject& o) : cct(o.cct) {} | |
67 | RefCountedObject& operator=(const RefCountedObject& o) = delete; | |
68 | RefCountedObject(RefCountedObject&&) = delete; | |
69 | RefCountedObject& operator=(RefCountedObject&&) = delete; | |
70 | RefCountedObject(CephContext* c) : cct(c) {} | |
71 | ||
72 | virtual ~RefCountedObject(); | |
73 | ||
74 | private: | |
75 | void _get() const; | |
76 | ||
77 | #if defined(WITH_SEASTAR) && !defined(WITH_ALIEN) | |
78 | // crimson is single threaded at the moment | |
79 | mutable uint64_t nref{1}; | |
80 | #else | |
81 | mutable std::atomic<uint64_t> nref{1}; | |
82 | #endif | |
83 | CephContext *cct{nullptr}; | |
84 | }; | |
85 | ||
86 | class RefCountedObjectSafe : public RefCountedObject { | |
87 | public: | |
88 | RefCountedObject *get() = delete; | |
89 | const RefCountedObject *get() const = delete; | |
90 | void put() const = delete; | |
91 | protected: | |
92 | template<typename... Args> | |
93 | RefCountedObjectSafe(Args&&... args) : RefCountedObject(std::forward<Args>(args)...) {} | |
94 | virtual ~RefCountedObjectSafe() override {} | |
7c673cae FG |
95 | }; |
96 | ||
9f95a23c | 97 | #if !defined(WITH_SEASTAR)|| defined(WITH_ALIEN) |
11fdf7f2 | 98 | |
7c673cae FG |
99 | /** |
100 | * RefCountedCond | |
101 | * | |
102 | * a refcounted condition, will be removed when all references are dropped | |
103 | */ | |
7c673cae | 104 | struct RefCountedCond : public RefCountedObject { |
9f95a23c TL |
105 | RefCountedCond() = default; |
106 | ~RefCountedCond() = default; | |
7c673cae FG |
107 | |
108 | int wait() { | |
11fdf7f2 | 109 | std::unique_lock l(lock); |
7c673cae | 110 | while (!complete) { |
11fdf7f2 | 111 | cond.wait(l); |
7c673cae FG |
112 | } |
113 | return rval; | |
114 | } | |
115 | ||
116 | void done(int r) { | |
11fdf7f2 | 117 | std::lock_guard l(lock); |
7c673cae FG |
118 | rval = r; |
119 | complete = true; | |
11fdf7f2 | 120 | cond.notify_all(); |
7c673cae FG |
121 | } |
122 | ||
123 | void done() { | |
124 | done(0); | |
125 | } | |
9f95a23c TL |
126 | |
127 | private: | |
128 | bool complete = false; | |
129 | ceph::mutex lock = ceph::make_mutex("RefCountedCond::lock"); | |
130 | ceph::condition_variable cond; | |
131 | int rval = 0; | |
7c673cae FG |
132 | }; |
133 | ||
134 | /** | |
135 | * RefCountedWaitObject | |
136 | * | |
137 | * refcounted object that allows waiting for the object's last reference. | |
138 | * Any referrer can either put or put_wait(). A simple put() will return | |
139 | * immediately, a put_wait() will return only when the object is destroyed. | |
140 | * e.g., useful when we want to wait for a specific event completion. We | |
141 | * use RefCountedCond, as the condition can be referenced after the object | |
142 | * destruction. | |
143 | * | |
144 | */ | |
145 | struct RefCountedWaitObject { | |
31f18b77 | 146 | std::atomic<uint64_t> nref = { 1 }; |
7c673cae FG |
147 | RefCountedCond *c; |
148 | ||
31f18b77 | 149 | RefCountedWaitObject() { |
7c673cae FG |
150 | c = new RefCountedCond; |
151 | } | |
152 | virtual ~RefCountedWaitObject() { | |
153 | c->put(); | |
154 | } | |
155 | ||
156 | RefCountedWaitObject *get() { | |
31f18b77 | 157 | nref++; |
7c673cae FG |
158 | return this; |
159 | } | |
160 | ||
161 | bool put() { | |
162 | bool ret = false; | |
163 | RefCountedCond *cond = c; | |
164 | cond->get(); | |
31f18b77 | 165 | if (--nref == 0) { |
7c673cae FG |
166 | cond->done(); |
167 | delete this; | |
168 | ret = true; | |
169 | } | |
170 | cond->put(); | |
171 | return ret; | |
172 | } | |
173 | ||
174 | void put_wait() { | |
175 | RefCountedCond *cond = c; | |
176 | ||
177 | cond->get(); | |
31f18b77 | 178 | if (--nref == 0) { |
7c673cae FG |
179 | cond->done(); |
180 | delete this; | |
181 | } else { | |
182 | cond->wait(); | |
183 | } | |
184 | cond->put(); | |
185 | } | |
186 | }; | |
187 | ||
9f95a23c | 188 | #endif // !defined(WITH_SEASTAR)|| defined(WITH_ALIEN) |
11fdf7f2 TL |
189 | |
190 | static inline void intrusive_ptr_add_ref(const RefCountedObject *p) { | |
191 | p->get(); | |
192 | } | |
193 | static inline void intrusive_ptr_release(const RefCountedObject *p) { | |
194 | p->put(); | |
195 | } | |
20effc67 TL |
196 | struct UniquePtrDeleter |
197 | { | |
198 | void operator()(RefCountedObject *p) const | |
199 | { | |
200 | // Don't expect a call to `get()` in the ctor as we manually set nref to 1 | |
201 | p->put(); | |
202 | } | |
203 | }; | |
9f95a23c TL |
204 | } |
205 | using RefCountedPtr = ceph::ref_t<TOPNSPC::common::RefCountedObject>; | |
7c673cae FG |
206 | |
207 | #endif |