summaryrefslogtreecommitdiffstats
path: root/ppapi/shared_impl/tracked_callback.h
blob: 03bf1626e30882cf09b986c8f7f61f28388cce3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef PPAPI_SHARED_IMPL_TRACKED_CALLBACK_H_
#define PPAPI_SHARED_IMPL_TRACKED_CALLBACK_H_

#include <map>
#include <set>

#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/condition_variable.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/shared_impl/ppapi_shared_export.h"
#include "ppapi/shared_impl/ppb_message_loop_shared.h"

namespace ppapi {

class CallbackTracker;
class MessageLoopShared;
class Resource;

namespace thunk {
namespace subtle {
// For a friend declaration below.
class EnterBase;
}
}

// |TrackedCallback| represents a tracked Pepper callback (from the browser to
// the plugin), typically still pending. Such callbacks have the standard Pepper
// callback semantics. Execution (i.e., completion) of callbacks happens through
// objects of subclasses of |TrackedCallback|. Two things are ensured: (1) that
// the callback is executed at most once, and (2) once a callback is marked to
// be aborted, any subsequent completion is abortive (even if a non-abortive
// completion had previously been scheduled).
//
// The details of non-abortive completion depend on the type of callback (e.g.,
// different parameters may be required), but basic abort functionality is core.
// The ability to post aborts is needed in many situations to ensure that the
// plugin is not re-entered into. (Note that posting a task to just run
// |Abort()| is different and not correct; calling |PostAbort()| additionally
// guarantees that all subsequent completions will be abortive.)
//
// This class is reference counted so that different things can hang on to it,
// and not worry too much about ensuring Pepper callback semantics. Note that
// the "owning" |CallbackTracker| will keep a reference until the callback is
// completed.
//
// Subclasses must do several things:
//  - They must ensure that the callback is executed at most once (by looking at
//    |completed()| before running the callback).
//  - They must ensure that the callback is run abortively if it is marked as to
//    be aborted (by looking at |aborted()| before running the callback).
//  - They must call |MarkAsCompleted()| immediately before actually running the
//    callback; see the comment for |MarkAsCompleted()| for a caveat.
class PPAPI_SHARED_EXPORT TrackedCallback
    : public base::RefCountedThreadSafe<TrackedCallback> {
 public:
  // Create a tracked completion callback and register it with the tracker. The
  // resource pointer is not stored. If |resource| is NULL, this callback will
  // not be added to the callback tracker.
  TrackedCallback(Resource* resource, const PP_CompletionCallback& callback);

  // These run the callback in an abortive manner, or post a task to do so (but
  // immediately marking the callback as to be aborted).
  void Abort();
  void PostAbort();

  // Run the callback with the given result. If the callback had previously been
  // marked as to be aborted (by |PostAbort()|), |result| will be ignored and
  // the callback will be run with result |PP_ERROR_ABORTED|.
  //
  // Run() will invoke the call immediately, if invoked from the target thread
  // (as determined by target_loop_). If invoked on a different thread, the
  // callback will be scheduled to run later on target_loop_.
  void Run(int32_t result);
  // PostRun is like Run(), except it guarantees that the callback will be run
  // later. In particular, if you invoke PostRun on the same thread on which the
  // callback is targeted to run, it will *not* be run immediately.
  void PostRun(int32_t result);

  void BlockUntilRun();

  // Returns the ID of the resource which "owns" the callback, or 0 if the
  // callback is not associated with any resource.
  PP_Resource resource_id() const { return resource_id_; }

  // Returns true if the callback was completed (possibly aborted).
  bool completed() const { return completed_; }

  // Returns true if the callback was or should be aborted; this will be the
  // case whenever |Abort()| or |PostAbort()| is called before a non-abortive
  // completion.
  bool aborted() const { return aborted_; }

  // Helper to determine if the given callback is set and not yet completed.
  // The normal pattern is to use a scoped_refptr to hold a callback. This
  // function tells you if the operation is currently in progress by checking
  // both the null-ness of the scoped_refptr, as well as the completion state
  // of the callback (which may still be out-standing via a PostAbort).
  static bool IsPending(const scoped_refptr<TrackedCallback>& callback);

 protected:
  bool is_blocking() {
    return !callback_.func;
  }
  bool is_required() {
    return (callback_.func &&
            !(callback_.flags & PP_COMPLETIONCALLBACK_FLAG_OPTIONAL));
  }
  bool is_optional() {
    return (callback_.func &&
            (callback_.flags & PP_COMPLETIONCALLBACK_FLAG_OPTIONAL));
  }
  bool has_null_target_loop() const {
    return target_loop_ == NULL;
  }

 private:
  // TrackedCallback and EnterBase manage dealing with how to invoke callbacks
  // appropriately. Pepper interface implementations and proxies should not have
  // to check the type of callback, block, or mark them complete explicitly.
  friend class ppapi::thunk::subtle::EnterBase;

  // Block until the associated operation has completed. Returns the result.
  // This must only be called on a non-main thread on a blocking callback.
  int32_t BlockUntilComplete();

  // Mark this object as complete and remove it from the tracker. This must only
  // be called once. Note that running this may result in this object being
  // deleted (so keep a reference if it'll still be needed).
  void MarkAsCompleted();

  // This class is ref counted.
  friend class base::RefCountedThreadSafe<TrackedCallback>;
  virtual ~TrackedCallback();

  // Flag used by |PostAbort()| and |PostRun()| to check that we don't schedule
  // the callback more than once.
  bool is_scheduled_;

  scoped_refptr<CallbackTracker> tracker_;
  PP_Resource resource_id_;
  bool completed_;
  bool aborted_;
  PP_CompletionCallback callback_;

  // The MessageLoopShared on which this callback should be run. This will be
  // NULL if we're in-process.
  scoped_refptr<MessageLoopShared> target_loop_;

  int32_t result_for_blocked_callback_;
  // Used for pausing/waking the blocked thread if this is a blocking completion
  // callback. Note that in-process, there is no lock, blocking callbacks are
  // not allowed, and therefore this pointer will be NULL.
  scoped_ptr<base::ConditionVariable> operation_completed_condvar_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(TrackedCallback);
};

}  // namespace ppapi

#endif  // PPAPI_SHARED_IMPL_TRACKED_CALLBACK_H_