1 : /* -*- c++ -*- */
2 : /*
3 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : // A form of weak reference for use by CallOnMainThread (COMT) and
9 : // other callback situations. This class is essentially a thread-safe
10 : // refcounted class that is used to hold pointers to resources that
11 : // may "go away" due to the plugin instance being destroyed.
12 : // Generally resource cleanup should be handled by the contained
13 : // class's dtor.
14 : //
15 : // Here is the intended use case. Every plug-in instance contains a
16 : // reference to a WeakRefAnchor object. Callbacks must use only
17 : // resources pointed to by a WeakRef object -- when COMT is invoked,
18 : // the COMT-queue owns a reference to the WeakRef object. When a
19 : // WeakRefAnchor object is abandoned (typically in the plug-in dtor),
20 : // it ensures that all associated callbacks will either not be called
21 : // (if the callback takes a resource pointer) or will be invoked with
22 : // a WeakRef<Resource>* object which yields NULL when the
23 : // ReleaseAndUnref method is invoked on it. After the callback fires,
24 : // the resource associated with the callback is deleted. This is
25 : // required when, for example, the completion callback resource is the
26 : // I/O buffer into which a Read operation is writing; we must wait for
27 : // the Read completion event before we can deallocate the destination
28 : // buffer.
29 : //
30 : // In the normal execution, the callback data is present, and the
31 : // callback function should or save its contents elsewhere if needed;
32 : // the callback data is deleted after the callback function returns.
33 :
34 :
35 : // EXAMPLE USAGE
36 : //
37 : // class Foo {
38 : // Foo() : anchor_(new WeakRefAnchor);
39 : // ~Foo() {
40 : // anchor_->Abandon();
41 : // }
42 : // static void DoOperation_MainThread(void* vargs, int32_t result) {
43 : // WeakRef<OpArgument>* args =
44 : // reinterpret_cast<WeakRef<OpArgument>*>(vargs);
45 : // scoped_ptr<OpArgument> p;
46 : // args->ReleaseAndUnref(&p);
47 : // if (p != NULL) {
48 : // ... stash away elements of p...
49 : // }
50 : // }
51 : // ScheduleOperation() {
52 : // OpArgument* args = new OpArgument(...);
53 : // pp::CompletionCallback cc(DoOperation_MainThread,
54 : // WeakRefAnchor* anchor_;
55 : // };
56 : //
57 : // Improved syntactic sugar makes this even simpler in
58 : // <call_on_main_thread.h>.
59 :
60 :
61 : // This class operates much like CompletionCallbackFactory (if
62 : // instantiated with a thread-safe RefCount class), except that
63 : // appropriate memory barriers are included to ensure that partial
64 : // memory writes are not seen by other threads. Here is the memory
65 : // consistency issue:
66 : //
67 : // In <completion_callback.h>'s CompletionCallbackFactory<T>, the only
68 : // memory barriers are with the refcount adjustment. In
69 : // ResetBackPointer, we follow DropFactory() immediately by Release().
70 : // Imagine another thread that reads the factory_ value via
71 : // back_pointer_->GetObject(). The assignment of NULL to
72 : // back_pointer_->factory_ may result in more than one bus cycle. That
73 : // means a read from another thread may yield a garbled value,
74 : // comprised of some combination of the original pointer bits and
75 : // zeros -- this may occur even on Intel architectures where any
76 : // visible memory changes must be in the original write order, if the
77 : // pointer were to span cache lines (e.g., packed attribute used).
78 :
79 : #ifndef NATIVE_CLIENT_SRC_TRUSTED_WEAK_REF_WEAK_REF_H_
80 : #define NATIVE_CLIENT_SRC_TRUSTED_WEAK_REF_WEAK_REF_H_
81 :
82 : #include "native_client/src/include/portability.h"
83 : #include "native_client/src/include/nacl_base.h"
84 : #include "native_client/src/include/nacl_scoped_ptr.h"
85 : #include "native_client/src/shared/platform/refcount_base.h"
86 : #include "native_client/src/shared/platform/nacl_check.h"
87 : #include "native_client/src/shared/platform/nacl_log.h"
88 : #include "native_client/src/shared/platform/nacl_sync.h"
89 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
90 : #include "native_client/src/shared/platform/nacl_sync_raii.h"
91 :
92 : namespace nacl {
93 :
94 : static char const* const kWeakRefModuleName = "weak_ref";
95 :
96 : class WeakRefAnchor;
97 :
98 : class AnchoredResource : public RefCountBase {
99 : public:
100 : explicit AnchoredResource(WeakRefAnchor* anchor);
101 :
102 : virtual ~AnchoredResource();
103 :
104 : // covariant impl of Ref()
105 : AnchoredResource* Ref() {
106 : return reinterpret_cast<AnchoredResource*>(RefCountBase::Ref());
107 : }
108 :
109 : protected:
110 : friend class WeakRefAnchor;
111 :
112 : WeakRefAnchor* anchor_;
113 : NaClMutex mu_;
114 :
115 : DISALLOW_COPY_AND_ASSIGN(AnchoredResource);
116 : };
117 :
118 : template <typename R> class WeakRef; // fwd
119 :
120 : // Plugin instance should hold a reference, and pass new references to
121 : // the WeakRefAnchor to any threads that may need to create callbacks.
122 : // The plugin instance should invoke Abandon before Unref'ing its
123 : // pointer to its WeakRefAnchor object. When all threads that may
124 : // want to invoke COMT have exited (through some unspecified
125 : // notification mechanism, e.g., RPC channel closure, then the
126 : // WeakRefAnchor will get reclaimed.
127 :
128 : class WeakRefAnchor : public RefCountBase {
129 : public:
130 : WeakRefAnchor();
131 :
132 : // covariant impl of Ref()
133 0 : WeakRefAnchor* Ref() {
134 0 : return reinterpret_cast<WeakRefAnchor*>(RefCountBase::Ref());
135 : }
136 : bool is_abandoned();
137 :
138 : // Mark anchor as abandoned. Does not Unref(), so caller still has
139 : // to do that.
140 : void Abandon();
141 :
142 : // If MakeWeakRef fails, i.e., the WeakRefAnchor had been abandoned
143 : // in the main thread, then it returns NULL and the caller is
144 : // responsible for releasing the resource represented by
145 : // raw_resource; if MakeWeakRef succeeds, then it takes ownership of
146 : // raw_resource and has wrapped in in the WeakRef<R>* object, which
147 : // can be used as argument to the callback function for COMT. After
148 : // ownership passes, the caller must not continue to use the
149 : // raw_resource, since the main thread may Abandon the anchor at any
150 : // time and cause raw_resource to have its dtor invoked in
151 : // WeakRef<R>::reset_mu.
152 : template <typename R>
153 0 : WeakRef<R>* MakeWeakRef(R* raw_resource) {
154 0 : WeakRef<R>* rp = NULL;
155 0 : NaClLog2(kWeakRefModuleName, 4,
156 : "Entered WeakRef<R>::MakeWeakRef, raw 0x%"NACL_PRIxPTR"\n",
157 : (uintptr_t) raw_resource);
158 0 : CHECK(raw_resource != NULL);
159 0 : rp = new WeakRef<R>(this, raw_resource);
160 : // If the WeakRefAnchor was already abandoned, we make a WeakRef anyway,
161 : // and the use of the WeakRef will discover this.
162 0 : CHECK(rp != NULL);
163 0 : NaClLog2(kWeakRefModuleName, 4,
164 : "Leaving WeakRef<R>::MakeWeakRef, weak_ref 0x%"NACL_PRIxPTR"\n",
165 : (uintptr_t) rp);
166 0 : return rp;
167 : }
168 :
169 : protected:
170 : ~WeakRefAnchor();
171 :
172 : private:
173 : NaClMutex mu_;
174 :
175 : bool abandoned_;
176 :
177 : DISALLOW_COPY_AND_ASSIGN(WeakRefAnchor);
178 : };
179 :
180 : // The resource type R should contain everything that a callback
181 : // function needs. In particular, it may contain a reference to a
182 : // WeakRefAnchor object if the callback function may in turn want to
183 : // schedule more callbacks -- and the WeakRefAnchor refcount should be
184 : // properly managed (releasing when R is destroyed, incremented when a
185 : // reference is passed to another resource R' for the chained
186 : // callback). If a reference to the plugin or other associated object
187 : // is needed, that can be a "naked" pointer in the callback use case
188 : // since the callback is only invoked on the main thread, and the
189 : // plugin can only be shut down in the main thread (it cannot go
190 : // away). In general, for use cases where the WeakRef resource might
191 : // be used in an arbitrary other thread, no naked, non-refcounted
192 : // objects should be referred to from WeakRef wrapped resources.
193 : //
194 : template <typename R>
195 : class WeakRef : public AnchoredResource {
196 : // public base class, needed for win64_newlib_dbg. why?
197 : public:
198 : // Single use! Invoked only from main thread, so anchor will not be
199 : // doing Abandon() at the same time. After ReleaseAndUnref, caller
200 : // must not use the pointer to the WeakRef object further.
201 0 : void ReleaseAndUnref(scoped_ptr<R>* out_ptr) {
202 0 : NaClLog2(kWeakRefModuleName, 4,
203 : "Entered WeakRef<R>::ReleaseAndUnref: this 0x%"NACL_PRIxPTR"\n",
204 : (uintptr_t) this);
205 : do {
206 0 : nacl::MutexLocker take(&mu_);
207 0 : if (anchor_->is_abandoned()) {
208 0 : delete resource_.release();
209 0 : out_ptr->reset();
210 : } else {
211 0 : out_ptr->reset(resource_.release());
212 : }
213 : } while (0);
214 0 : NaClLog2(kWeakRefModuleName, 4,
215 : "Leaving ReleaseAndUnref: raw: out_ptr->get() 0x%"NACL_PRIxPTR"\n",
216 : (uintptr_t) out_ptr->get());
217 0 : Unref(); // release ref associated with the callback
218 : }
219 :
220 : protected:
221 0 : virtual ~WeakRef() {}
222 :
223 : private:
224 : friend class WeakRefAnchor;
225 :
226 0 : WeakRef(WeakRefAnchor* anchor, R* resource)
227 : : AnchoredResource(anchor),
228 0 : resource_(resource) {
229 0 : CHECK(resource != NULL);
230 : }
231 :
232 : scoped_ptr<R> resource_; // NULL when anchor object is destroyed.
233 :
234 : DISALLOW_COPY_AND_ASSIGN(WeakRef);
235 : };
236 :
237 : } // namespace nacl
238 :
239 : #endif
|