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