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// EXAMPLE USAGE 9// 10// class PluginReverseInterface { 11// public: 12// PluginReverseInterface(...) : anchor_(new nacl::WeakRefAnchor); 13// ~PluginReverseInterface() { anchor_->Abandon(); } 14// void Log(nacl::string message) { 15// LogContinuation* continuation = new LogContinuation(message); 16// plugin::WeakRefCallOnMainThread(anchor_, 0 /* ms delay */, 17// this, &PluginReverseInterface::Log_cont, 18// continuation); 19// } 20// void Log_cont(LogContinuation* cont, int32_t result) { 21// plugin_->browser_interface()->AddToConsole(plugin_->instance_id(), 22// cont->message); 23// delete cont; 24// } 25// private: 26// nacl::WeakRefAnchor* anchor_; 27// } 28 29#ifndef NATIVE_CLIENT_SRC_TRUSTED_WEAK_REF_CALL_ON_MAIN_THREAD_H_ 30#define NATIVE_CLIENT_SRC_TRUSTED_WEAK_REF_CALL_ON_MAIN_THREAD_H_ 31 32#include "native_client/src/trusted/weak_ref/weak_ref.h" 33 34#include "native_client/src/include/nacl_scoped_ptr.h" 35#include "native_client/src/include/nacl_compiler_annotations.h" 36#include "native_client/src/include/portability.h" 37 38#include "ppapi/c/pp_errors.h" // for PP_OK 39#include "ppapi/cpp/completion_callback.h" // for pp::CompletionCallback 40#include "ppapi/cpp/core.h" // for pp:: 41#include "ppapi/cpp/module.h" // for pp::Module 42 43namespace plugin { 44 45// A typesafe utility to schedule a completion callback using weak 46// references. The callback function callback_fn is invoked 47// regardless of whether the anchor has been abandoned, since 48// callback_fn takes a WeakRef<R>* as argument. The intention is that 49// such callbacks, even deprived of any of its arguments (which has 50// been deleted), may wish to do some cleanup / log a message. 51 52static char const* const kPpWeakRefModuleName = "pp_weak_ref"; 53 54template <typename R> pp::CompletionCallback WeakRefNewCallback( 55 nacl::WeakRefAnchor* anchor, 56 void callback_fn(nacl::WeakRef<R>* weak_data, int32_t err), 57 R* raw_data) { 58 nacl::WeakRef<R>* wp = anchor->MakeWeakRef<R>(raw_data); 59 // TODO(bsy): explore using another template to eliminate the 60 // following cast, making things completely typesafe. 61 pp::CompletionCallback cc_nrvo( 62 reinterpret_cast<void (*)(void*, int32_t)>( 63 callback_fn), 64 reinterpret_cast<void*>(wp)); 65 return cc_nrvo; 66} 67 68template <typename R> void WeakRefCallOnMainThread( 69 nacl::WeakRefAnchor* anchor, 70 int32_t delay_in_milliseconds, 71 void callback_fn(nacl::WeakRef<R>* weak_data, int32_t err), 72 R* raw_data) { 73 pp::CompletionCallback cc = 74 WeakRefNewCallback(anchor, callback_fn, raw_data, &cc); 75 76 pp::Module::Get()->core()->CallOnMainThread( 77 delay_in_milliseconds, 78 cc, 79 PP_OK); 80} 81 82template <typename R> class WeakRefAutoAbandonWrapper { 83 public: 84 WeakRefAutoAbandonWrapper(void (*callback_fn)(R* raw_data, 85 int32_t err), 86 R* raw_data) 87 : orig_callback_fn(callback_fn), 88 orig_data(raw_data) {} 89 90 void (*orig_callback_fn)(R* raw_data, int32_t err); 91 nacl::scoped_ptr<R> orig_data; 92}; 93 94/* 95 * It would be nice if the function had the right type signature, 96 * i.e., void WeakRefAutoAbandoner(void *wr_data, int32_t) but then 97 * the formal argument list would not use the typename template 98 * argument R, making template resolution impossible. 99 */ 100template <typename R> void WeakRefAutoAbandoner( 101 nacl::WeakRef<WeakRefAutoAbandonWrapper<R> >* wr, 102 int32_t err) { 103 nacl::scoped_ptr<WeakRefAutoAbandonWrapper<R> > p; 104 wr->ReleaseAndUnref(&p); 105 if (p == NULL) { 106 NaClLog2(kPpWeakRefModuleName, 4, 107 "WeakRefAutoAbandoner: weak ref NULL, anchor was abandoned\n"); 108 return; 109 } 110 NaClLog2(kPpWeakRefModuleName, 4, 111 "WeakRefAutoAbandoner: weak ref okay, invoking callback\n"); 112 (*p->orig_callback_fn)(p->orig_data.get(), err); 113 return; 114} 115 116// A typesafe utility to schedule a completion callback using weak 117// references. The callback function raw_callback_fn takes an R* as 118// argument, and is not invoked if the anchor has been abandoned. 119template <typename R> pp::CompletionCallback WeakRefNewCallback( 120 nacl::WeakRefAnchor* anchor, 121 void (*raw_callback_fn)(R* raw_data, int32_t err), 122 R* raw_data) { 123 124 WeakRefAutoAbandonWrapper<R>* wref_auto_wrapper = 125 new WeakRefAutoAbandonWrapper<R>(raw_callback_fn, raw_data); 126 127 CHECK(wref_auto_wrapper != NULL); 128 129 nacl::WeakRef<WeakRefAutoAbandonWrapper<R> >* wp = 130 anchor->MakeWeakRef<WeakRefAutoAbandonWrapper<R> >( 131 wref_auto_wrapper); 132 void (*weak_ref_auto_abandoner_ptr)( 133 nacl::WeakRef<WeakRefAutoAbandonWrapper<R> >* wr, 134 int32_t err) = WeakRefAutoAbandoner<R>; 135 // TODO(bsy): see above 136 pp::CompletionCallback cc_nrvo( 137 reinterpret_cast<void (*)(void*, int32_t)>(weak_ref_auto_abandoner_ptr), 138 reinterpret_cast<void*>(wp)); 139 return cc_nrvo; 140} 141 142template <typename R> void WeakRefCallOnMainThread( 143 nacl::WeakRefAnchor* anchor, 144 int32_t delay_in_milliseconds, 145 void raw_callback_fn(R* raw_data, int32_t err), 146 R* raw_data) { 147 pp::CompletionCallback cc = 148 WeakRefNewCallback(anchor, raw_callback_fn, raw_data, &cc); 149 pp::Module::Get()->core()->CallOnMainThread( 150 delay_in_milliseconds, 151 cc, 152 PP_OK); 153} 154 155 156template <typename R, typename E> 157class WeakRefMemberFuncBinder { 158 public: 159 WeakRefMemberFuncBinder(E* object, 160 void (E::*raw_callback_fn)(R* raw_data, 161 int32_t err), 162 R* raw_data) 163 : object_(object), 164 raw_callback_fn_(raw_callback_fn), 165 data_(raw_data) {} 166 void Invoke(int32_t err) { 167 NaClLog2(kPpWeakRefModuleName, 4, 168 ("WeakRefMemberFuncBinder: Invoke obj 0x%" NACL_PRIxPTR 169 ", err%" NACL_PRId32 "\n"), 170 reinterpret_cast<uintptr_t>(object_), err); 171 (object_->*raw_callback_fn_)(data_.get(), err); 172 NaClLog2(kPpWeakRefModuleName, 4, 173 "WeakRefMemberFuncBinder: done\n"); 174 } 175 private: 176 E* object_; 177 void (E::*raw_callback_fn_)(R* raw_data, int32_t err); 178 nacl::scoped_ptr<R> data_; 179}; 180 181template <typename R, typename E> 182void WeakRefMemberFuncInvoker( 183 WeakRefMemberFuncBinder<R, E> *binder, int32_t err) { 184 NaClLog2(kPpWeakRefModuleName, 4, 185 "WeakRefMemberFuncInvoker: %" NACL_PRIxPTR " %" NACL_PRId32 "\n", 186 (uintptr_t) binder, 187 err); 188 binder->Invoke(err); 189 // delete binder not needed, since WeakRefAutoAbandoner holds binder 190 // in a scoped_ptr and will automatically delete on scope exit. 191} 192 193 194// A typesafe utility to schedule a completion callback using weak 195// references, where the callback function is a member function. The 196// member function must take only a raw argument data pointer and a 197// completion status as formal parameters. The lifetime of the 198// |object| and |raw_callback_fn| must be at least that of |anchor|. 199// Typically |object| is just the object that controls the |anchor|, 200// though it may be some sub-object that is contained within the 201// actual controlling object. If the |anchor| is abandoned, the 202// |raw_data| argument is deleted and the |raw_callback_fn| will not 203// be invoked. 204template <typename R, typename E> 205pp::CompletionCallback WeakRefNewCallback( 206 nacl::WeakRefAnchor* anchor, 207 E* object, 208 void (E::*raw_callback_fn)(R* raw_data, int32_t err), 209 R* raw_data) { 210 NaClLog2(kPpWeakRefModuleName, 4, 211 "Entered WeakRefNewCallback\n"); 212 NaClLog2(kPpWeakRefModuleName, 4, 213 "object 0x%" NACL_PRIxPTR "\n", 214 reinterpret_cast<uintptr_t>(object)); 215 WeakRefMemberFuncBinder<R, E>* binder = 216 new WeakRefMemberFuncBinder<R, E>(object, 217 raw_callback_fn, 218 raw_data); 219 CHECK(binder != NULL); 220 NaClLog2(kPpWeakRefModuleName, 4, 221 "WeakRefNewCallback: binder %" NACL_PRIxPTR "\n", 222 (uintptr_t) binder); 223 void (*weak_ref_member_func_invoker_ptr)( 224 WeakRefMemberFuncBinder<R, E>* binder, 225 int32_t err) = WeakRefMemberFuncInvoker<R, E>; 226 return WeakRefNewCallback(anchor, weak_ref_member_func_invoker_ptr, 227 binder); 228} 229 230template <typename R, typename E> void WeakRefCallOnMainThread( 231 nacl::WeakRefAnchor* anchor, 232 int32_t delay_in_milliseconds, 233 E* object, 234 void (E::*raw_callback_fn)(R* raw_data, int32_t err), 235 R* raw_data) { 236 NaClLog2(kPpWeakRefModuleName, 4, 237 "Entered WeakRefCallOnMainThread\n"); 238 pp::CompletionCallback cc = 239 WeakRefNewCallback(anchor, object, raw_callback_fn, raw_data); 240 NaClLog2(kPpWeakRefModuleName, 4, 241 "WeakRefCallOnMainThread: got cc\n"); 242 pp::Module::Get()->core()->CallOnMainThread( 243 delay_in_milliseconds, 244 cc, 245 PP_OK); 246 NaClLog2(kPpWeakRefModuleName, 4, 247 "WeakRefCallOnMainThread: invoked PP_CallOnMainThread\n"); 248} 249 250} // namespace plugin 251 252#endif 253