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