| OLD | NEW |
| (Empty) | |
| 1 /* -*- c++ -*- */ |
| 2 /* |
| 3 * Copyright (c) 2011 The Chromium 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 #ifndef NATIVE_CLIENT_SRC_UNTRUSTED_NACL_PPAPI_UTIL_NACL_PPAPI_UTIL_H_ |
| 9 #define NATIVE_CLIENT_SRC_UNTRUSTED_NACL_PPAPI_UTIL_NACL_PPAPI_UTIL_H_ |
| 10 |
| 11 #include "ppapi/cpp/instance.h" |
| 12 #include "ppapi/cpp/module.h" |
| 13 #include "ppapi/cpp/var.h" |
| 14 |
| 15 #include "native_client/src/include/nacl_base.h" |
| 16 #include "native_client/src/include/nacl_scoped_ptr.h" |
| 17 #include "native_client/src/shared/platform/nacl_sync.h" |
| 18 #include "native_client/src/shared/platform/nacl_sync_checked.h" |
| 19 #include "native_client/src/shared/platform/nacl_sync_raii.h" |
| 20 |
| 21 // TODO(bsy): move weak_ref module to the shared directory |
| 22 #include "native_client/src/trusted/weak_ref/weak_ref.h" |
| 23 #include "native_client/src/trusted/weak_ref/call_on_main_thread.h" |
| 24 |
| 25 // The nomenclature used in this file is intended to clarify thinking |
| 26 // about the Pepper "main thread". The "main thread" is really an |
| 27 // interrupt service thread, or an event handler thread, since it is |
| 28 // bad to do blocking operations or execute code that runs for a long |
| 29 // time on it. Event handlers should complete quickly -- possibly |
| 30 // just enqueuing the event for processing by some worker thread -- |
| 31 // and return, so that additional event dispatch can occur. |
| 32 |
| 33 // Code that does real work (and tests) should run in a separate, |
| 34 // worker thread. The main event handler thread is where the |
| 35 // post-message handler runs via a pp::Module virtual member function |
| 36 // (HandleMessage), which represents the plugin instance. This plugin |
| 37 // instance can go away at any time, e.g., due to surf-away. Thus, |
| 38 // other threads should not use pointers to the pp::Module, since the |
| 39 // object isn't reference counted (and probably shouldn't be, since |
| 40 // it really have to shut down / clean up when Pepper tells it to), |
| 41 // and main thread-only operations such as PostMessage or |
| 42 // GetOSFileDescriptor on the FileIO_Dev PP_Resource must not be done |
| 43 // from the worker threads. |
| 44 |
| 45 // Our solution to this is as follows: |
| 46 // |
| 47 // The plugin instance object holds a reference to a WeakRefAnchor |
| 48 // object, and the plugin instance object's dtor invokes the Abandon |
| 49 // method on the anchor. Since the nacl::WeakRefAnchor object is |
| 50 // thread-safe and is reference counted, the anchor pointer may be |
| 51 // passed to worker threads. Worker threads are responsible for |
| 52 // maintaining the anchor refcount: each thread would hold a |
| 53 // reference, and must Unref prior to thread exit. The worker threads |
| 54 // can use plugin::WeakRefCallOnMainThread to enqueue continuation |
| 55 // callbacks to run on the main thread -- these will get cancelled if |
| 56 // the WeakRefAnchor was abandoned, which only occurs in the module |
| 57 // object's dtor, which can only run in the main thread. Since the |
| 58 // continuation won't run if the plugin instance is still valid, the |
| 59 // continuation can safely use pointers to the instance to perform |
| 60 // main-thread operations or to run member functions in the test |
| 61 // object or in the module object. The worker thread may hold a |
| 62 // pointer to the plugin instance object in order to schedule |
| 63 // callbacks via plugin::WeakRefCallOnMainThread using a method |
| 64 // pointer, but should not otherwise use the pointer. |
| 65 // |
| 66 // So, an operation (test) running on a worker thread must be broken |
| 67 // into separate computation phases according to which thread is |
| 68 // appropriate for invoking which operations. For compute-only phases |
| 69 // or manifest RPCs (which block and also invoke CallOnMainThread), |
| 70 // the computation should occur on the worker thread. When the worker |
| 71 // thread needs to invoke a main-thread-only operation such as |
| 72 // PostMessage, it should use its WeakRefAnchor objecct to schedule a |
| 73 // main thread callback and then wait on a condition variable for the |
| 74 // operation to complete. The main thread callback can invoke the |
| 75 // main-thread-only operation, then signal the condition variable to |
| 76 // wake up the worker thread prior to returning. After the worker |
| 77 // thread wakes up, it can use other synchronization methods to |
| 78 // determine if the worker thread should continue to run or exit |
| 79 // (e.g., if the worker thread is associated with the plugin instance, |
| 80 // then if the main thread work result is NULL, the worker thread |
| 81 // should probably Unref its anchor (and do other cleanup) and exit. |
| 82 |
| 83 namespace nacl_ppapi { |
| 84 |
| 85 template <typename R> class EventThreadWorkStateWrapper; // fwd |
| 86 |
| 87 // the worker thread should own the EventThreadWorkState<R> object |
| 88 template <typename R> |
| 89 class EventThreadWorkState { |
| 90 public: |
| 91 EventThreadWorkState() |
| 92 : done_(false), |
| 93 result_(NULL) { |
| 94 NaClXMutexCtor(&mu_); |
| 95 NaClXCondVarCtor(&cv_); |
| 96 } |
| 97 |
| 98 virtual ~EventThreadWorkState() { |
| 99 NaClMutexDtor(&mu_); |
| 100 NaClCondVarDtor(&cv_); |
| 101 } |
| 102 |
| 103 // Pass ownership of result into the EventThreadWorkState. The value |
| 104 // of result should be non-NULL to distinguish between |
| 105 // completion/abandonment. |
| 106 void SetResult(R *result) { |
| 107 nacl::MutexLocker take(&mu_); |
| 108 result_.reset(result); |
| 109 } |
| 110 |
| 111 // Returns result if callback completed, NULL if abandoned |
| 112 R *WaitForCompletion() { |
| 113 nacl::MutexLocker take(&mu_); |
| 114 while (!done_) { |
| 115 NaClXCondVarWait(&cv_, &mu_); |
| 116 } |
| 117 return result_.release(); |
| 118 } |
| 119 |
| 120 private: |
| 121 friend class EventThreadWorkStateWrapper<R>; |
| 122 void EventThreadWorkDone() { |
| 123 nacl::MutexLocker take(&mu_); |
| 124 done_ = true; |
| 125 NaClXCondVarBroadcast(&cv_); |
| 126 } |
| 127 |
| 128 NaClMutex mu_; |
| 129 NaClCondVar cv_; |
| 130 bool done_; |
| 131 nacl::scoped_ptr<R> result_; |
| 132 |
| 133 DISALLOW_COPY_AND_ASSIGN(EventThreadWorkState); |
| 134 }; |
| 135 |
| 136 |
| 137 // Wrapper around EventThreadWorkState<R> or subclass thereof. The |
| 138 // wrapper object should be created by a worker thread and the |
| 139 // ownership passed into the COMT machinery, to be used and deleted on |
| 140 // the main thread. This object is automatically deleted by the |
| 141 // WeakRef machinery when the callback fires, and the dtor will just |
| 142 // signal completion. If the anchor corresponding to the callback had |
| 143 // not been abandoned, then the callback function should invoke |
| 144 // SetResult before returning to pass ownership of a result object (R) |
| 145 // from the main thread to the worker thread. |
| 146 // |
| 147 // Subclasses of EventThreadWorkStateWrapper may be used, so that |
| 148 // contained input arguments are automatically deleted when the |
| 149 // callback fires, or input arguments may be stashed in subclasses of |
| 150 // EventThreadWorkState<R>. |
| 151 template <typename R> |
| 152 class EventThreadWorkStateWrapper { |
| 153 public: |
| 154 explicit EventThreadWorkStateWrapper(EventThreadWorkState<R> *ws): |
| 155 ws_(ws) {} |
| 156 virtual ~EventThreadWorkStateWrapper() { |
| 157 ws_->EventThreadWorkDone(); |
| 158 }; |
| 159 |
| 160 void SetResult(R *result) { |
| 161 ws_->SetResult(result); |
| 162 } |
| 163 private: |
| 164 EventThreadWorkState<R> *ws_; |
| 165 |
| 166 DISALLOW_COPY_AND_ASSIGN(EventThreadWorkStateWrapper); |
| 167 }; |
| 168 |
| 169 class VoidResult; |
| 170 |
| 171 extern VoidResult *const g_void_result; |
| 172 |
| 173 class VoidResult { |
| 174 public: |
| 175 VoidResult() {} |
| 176 void *operator new(size_t size) { return g_void_result; } |
| 177 void operator delete(void *p) {} |
| 178 private: |
| 179 DISALLOW_COPY_AND_ASSIGN(VoidResult); |
| 180 }; |
| 181 |
| 182 // Canonical pointer return value used with SetResult when the main |
| 183 // thread operation does not return a result. The class declaration |
| 184 // is private, so the compiler should refuse to allow the use of the |
| 185 // delete operator. |
| 186 |
| 187 // A plugin instance object should be referred to only from the main |
| 188 // thread. Pointers to the anchor object can be given to worker |
| 189 // thread so they can schedule work on the main thread via COMT. |
| 190 class NaClPpapiPluginInstance : public pp::Instance { |
| 191 public: |
| 192 explicit NaClPpapiPluginInstance(PP_Instance instance); |
| 193 virtual ~NaClPpapiPluginInstance(); |
| 194 nacl::WeakRefAnchor* anchor() const { return anchor_; } |
| 195 protected: |
| 196 nacl::WeakRefAnchor* anchor_; |
| 197 DISALLOW_COPY_AND_ASSIGN(NaClPpapiPluginInstance); |
| 198 }; |
| 199 |
| 200 } // namespace nacl_ppapi |
| 201 |
| 202 #endif |
| OLD | NEW |