1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #ifndef NATIVE_CLIENT_SRC_TRUSTED_NACL_BASE_NACL_REFCOUNT_H_
8 : #define NATIVE_CLIENT_SRC_TRUSTED_NACL_BASE_NACL_REFCOUNT_H_
9 :
10 : #include "native_client/src/include/nacl_base.h"
11 : #include "native_client/src/include/portability.h"
12 :
13 : #include "native_client/src/shared/platform/nacl_sync.h"
14 :
15 : #ifdef __cplusplus
16 : # include "native_client/src/include/nacl_scoped_ptr.h"
17 : # define NACL_IS_REFCOUNT_SUBCLASS ; typedef char is_refcount_subclass
18 : #else
19 : # define NACL_IS_REFCOUNT_SUBCLASS
20 : #endif
21 :
22 : EXTERN_C_BEGIN
23 :
24 : /*
25 : * Yields an lvalue of the vtable pointer, when given a subclass of
26 : * NaClRefCount and a pointer to an instance -- with the convention
27 : * that the vtable pointer is at the first word.
28 : *
29 : * Since we have the naming convention that struct Type contains an
30 : * element of type struct TypeVtbl *, we make it so that less typing
31 : * is required for the use of the macro and automatically constructing
32 : * the vtable type name from the subclass name.
33 : */
34 : #define NACL_VTBL(type, ptr) \
35 : (*(struct type ## Vtbl const **) (void *) ptr)
36 :
37 : struct NaClRefCountVtbl;
38 :
39 : struct NaClRefCount {
40 : struct NaClRefCountVtbl const *vtbl NACL_IS_REFCOUNT_SUBCLASS;
41 : /* private */
42 : struct NaClMutex mu;
43 : size_t ref_count;
44 : };
45 :
46 : struct NaClRefCountVtbl {
47 : void (*Dtor)(struct NaClRefCount *vself);
48 : };
49 :
50 : /*
51 : * Placement new style ctor; creates w/ ref_count of 1.
52 : *
53 : * The subclasses' ctor must call this base class ctor during their
54 : * contruction.
55 : */
56 : int NaClRefCountCtor(struct NaClRefCount *nrcp) NACL_WUR;
57 :
58 : struct NaClRefCount *NaClRefCountRef(struct NaClRefCount *nrcp);
59 :
60 : /* when ref_count reaches zero, will call dtor and free */
61 : void NaClRefCountUnref(struct NaClRefCount *nrcp);
62 :
63 : /*
64 : * NaClRefCountSafeUnref is just like NaCRefCountUnref, except that
65 : * nrcp may be NULL (in which case this is a noop).
66 : *
67 : * Used in failure cleanup of initialization code, esp in Ctors that
68 : * can fail.
69 : */
70 : void NaClRefCountSafeUnref(struct NaClRefCount *nrcp);
71 :
72 : extern struct NaClRefCountVtbl const kNaClRefCountVtbl;
73 :
74 : EXTERN_C_END
75 :
76 : #ifdef __cplusplus
77 :
78 : namespace nacl {
79 :
80 : // syntactic glucose to handle transferring responsibility to release
81 : // uninitialized memory from a scoped_ptr_malloc to a scoped pointer
82 : // that handles dereferencing a refcounted object.
83 :
84 : class NaClScopedRefCountNaClDescDtor {
85 : public:
86 0 : inline void operator()(NaClRefCount* x) const {
87 0 : NaClRefCountUnref(x);
88 0 : }
89 : };
90 :
91 : // RC must be a NaClRefCount subclass. unfortunately we can only
92 : // enforce this by checking that the RC struct contains a common
93 : // attribute -- the NACL_IS_REFCOUNT_SUBCLASS macro must be included
94 : // for every subclass that wants to use this template
95 : template <typename RC, typename DtorProc = NaClScopedRefCountNaClDescDtor>
96 : class scoped_ptr_nacl_refcount {
97 : public:
98 : // standard ctor
99 5 : scoped_ptr_nacl_refcount(nacl::scoped_ptr_malloc<RC>* p, int ctor_fn_result)
100 5 : : ptr_(NULL) {
101 : enum { must_be_subclass = sizeof(typename RC::is_refcount_subclass) };
102 :
103 5 : if (ctor_fn_result) {
104 : // we are now responsible for calling the unref, which, if the
105 : // refcount drops to zero, will handle the free.
106 5 : ptr_ = p->release();
107 : }
108 : }
109 :
110 : // copy ctor
111 : scoped_ptr_nacl_refcount(scoped_ptr_nacl_refcount const& other) {
112 : ptr_ = NaClRefCountRef(other.ptr_);
113 : }
114 :
115 : // assign
116 : scoped_ptr_nacl_refcount& operator=(scoped_ptr_nacl_refcount const& other) {
117 : if (this != &other) { // exclude self-assignment, which should be no-op
118 : if (NULL != ptr_) {
119 : deref_(reinterpret_cast<NaClRefCount*>(ptr_));
120 : }
121 : ptr_ = NaClRefCountRef(other.ptr_);
122 : }
123 : return *this;
124 : }
125 :
126 5 : ~scoped_ptr_nacl_refcount() {
127 5 : if (NULL != ptr_) {
128 0 : deref_(reinterpret_cast<NaClRefCount*>(ptr_));
129 : }
130 : }
131 :
132 5 : bool constructed() { return NULL != ptr_; }
133 :
134 : void reset(nacl::scoped_ptr_malloc<RC>* p = NULL, int ctor_fn_result = 0) {
135 : if (NULL != ptr_) {
136 : deref_(reinterpret_cast<NaClRefCount*>(ptr_));
137 : ptr_ = NULL;
138 : }
139 : if (0 != ctor_fn_result) {
140 : ptr_ = p->release();
141 : }
142 : }
143 :
144 : // Accessors
145 : RC& operator*() const {
146 : return *ptr_;
147 : }
148 :
149 : RC* operator->() const {
150 : return ptr_;
151 : }
152 :
153 : RC* get() const { return ptr_; }
154 :
155 : /*
156 : * ptr eq, so same pointer, and not equality testing on contents.
157 : */
158 : bool operator==(nacl::scoped_ptr_malloc<RC> const& p) const {
159 : return ptr_ == p.get();
160 : }
161 : bool operator==(RC const* p) const { return ptr_ == p; }
162 :
163 : bool operator!=(nacl::scoped_ptr_malloc<RC> const& p) const {
164 : return ptr_ != p.get();
165 : }
166 : bool operator!=(RC const* p) const { return ptr_ != p; }
167 :
168 : void swap(scoped_ptr_nacl_refcount& p2) {
169 : RC* tmp = ptr_;
170 : ptr_ = p2.ptr_;
171 : p2.ptr_ = tmp;
172 : }
173 :
174 5 : RC* release() {
175 5 : RC* tmp = ptr_;
176 5 : ptr_ = NULL;
177 5 : return tmp;
178 : }
179 :
180 : private:
181 : RC* ptr_;
182 :
183 : static DtorProc const deref_;
184 : };
185 :
186 : template<typename RC, typename DP>
187 12 : DP const scoped_ptr_nacl_refcount<RC, DP>::deref_ = DP();
188 :
189 : template<typename RC, typename DP>
190 : void swap(scoped_ptr_nacl_refcount<RC, DP>& a,
191 : scoped_ptr_nacl_refcount<RC, DP>& b) {
192 : a.swap(b);
193 : }
194 :
195 : template<typename RC, typename DP> inline
196 : bool operator==(nacl::scoped_ptr_malloc<RC> const& a,
197 : scoped_ptr_nacl_refcount<RC, DP> const& b) {
198 : return a.get() == b.get();
199 : }
200 :
201 : template<class RC, typename DP> inline
202 : bool operator==(RC const* a,
203 : scoped_ptr_nacl_refcount<RC, DP> const& b) {
204 : return a == b.get();
205 : }
206 :
207 : template<typename RC, typename DP> inline
208 : bool operator!=(nacl::scoped_ptr_malloc<RC> const& a,
209 : scoped_ptr_nacl_refcount<RC, DP> const& b) {
210 : return a.get() != b.get();
211 : }
212 :
213 : template<typename RC, typename DP> inline
214 : bool operator!=(RC const* a,
215 : scoped_ptr_nacl_refcount<RC, DP> const& b) {
216 : return a != b.get();
217 : }
218 :
219 : } // namespace
220 :
221 : #endif
222 :
223 : #endif
|