]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/RefCountedObj.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / common / RefCountedObj.h
CommitLineData
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 */
43namespace TOPNSPC::common {
44class RefCountedObject {
7c673cae 45public:
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
64protected:
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
74private:
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
86class RefCountedObjectSafe : public RefCountedObject {
87public:
88 RefCountedObject *get() = delete;
89 const RefCountedObject *get() const = delete;
90 void put() const = delete;
91protected:
92template<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 104struct 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
127private:
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 */
145struct 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
190static inline void intrusive_ptr_add_ref(const RefCountedObject *p) {
191 p->get();
192}
193static inline void intrusive_ptr_release(const RefCountedObject *p) {
194 p->put();
195}
20effc67
TL
196struct 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}
205using RefCountedPtr = ceph::ref_t<TOPNSPC::common::RefCountedObject>;
7c673cae
FG
206
207#endif