| Index: ppapi/shared_impl/tracked_callback.h
|
| diff --git a/ppapi/shared_impl/tracked_callback.h b/ppapi/shared_impl/tracked_callback.h
|
| index 294c9b99b4e3b89492e0c5d5c9fe438b6f078c3e..8bf7a4b33737549005dd14a82ce3e75d19e84585 100644
|
| --- a/ppapi/shared_impl/tracked_callback.h
|
| +++ b/ppapi/shared_impl/tracked_callback.h
|
| @@ -13,6 +13,7 @@
|
| #include "base/memory/ref_counted.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/synchronization/condition_variable.h"
|
| +#include "base/synchronization/lock.h"
|
| #include "ppapi/c/pp_completion_callback.h"
|
| #include "ppapi/c/pp_instance.h"
|
| #include "ppapi/c/pp_resource.h"
|
| @@ -52,13 +53,14 @@ class EnterBase;
|
| // 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.
|
| +// A note on threading:
|
| +// TrackedCallback is usable on any thread. It is *mostly* only used when
|
| +// ppapi::ProxyLock is held. However, it's necessary that Run() can be called
|
| +// without the ProxyLock. This is used to allow running the callback from
|
| +// the IO thread. In particular, blocking callbacks may not have a message loop
|
| +// to which we could post, so Run() must be able to signal the condition
|
| +// variable to wake up the thread that's waiting on the blocking callback, and
|
| +// Run() must be able to do this while not holding the ProxyLock.
|
| class PPAPI_SHARED_EXPORT TrackedCallback
|
| : public base::RefCountedThreadSafe<TrackedCallback> {
|
| public:
|
| @@ -80,6 +82,7 @@ class PPAPI_SHARED_EXPORT TrackedCallback
|
| // (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);
|
| + void AcquireProxyLockAndRun(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.
|
| @@ -93,25 +96,26 @@ class PPAPI_SHARED_EXPORT TrackedCallback
|
| typedef base::Callback<int32_t(int32_t /* result */)> CompletionTask;
|
|
|
| // Sets a task that is run just before calling back into the plugin. This
|
| - // should only be called once.
|
| + // should only be called once. Note that the CompletionTask always runs while
|
| + // holding the ppapi::ProxyLock.
|
| void set_completion_task(const CompletionTask& completion_task);
|
|
|
| // 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_; }
|
| -
|
| // Returns true if this is a blocking callback.
|
| - bool is_blocking() { return !callback_.func; }
|
| + bool is_blocking() const {
|
| + // This is set on construction and never changes after that, so there is
|
| + // no need to lock.
|
| + return !callback_.func;
|
| + }
|
|
|
| - MessageLoopShared* target_loop() const { return target_loop_.get(); }
|
| + MessageLoopShared* target_loop() const {
|
| + // This is set on construction and never changes after that, so there is
|
| + // no need to lock.
|
| + return target_loop_.get();
|
| + }
|
|
|
| // Determines if the given callback is pending. A callback is pending if it
|
| // has not completed and has not been aborted. When receiving a plugin call,
|
| @@ -127,21 +131,26 @@ class PPAPI_SHARED_EXPORT TrackedCallback
|
| // message loop.
|
| static bool IsScheduledToRun(const scoped_refptr<TrackedCallback>& callback);
|
|
|
| - protected:
|
| + private:
|
| 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_.get() == 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.
|
| + // Same as PostRun(), but lock_ must already be held.
|
| + void PostRunWithLock(int32_t result);
|
| +
|
| + void SignalBlockingCallback(int32_t result);
|
| +
|
| + // TrackedCallback and EnterBase work together to provide appropriate behavior
|
| + // for callbacks. Pepper interface implementations and proxies should
|
| + // usually not have to check whether callbacks are required, optional, or
|
| + // blocking. Nor should interface and proxy implementations have to worry
|
| + // about blocking on a callback or marking them complete explicitly.
|
| + //
|
| + // (There are exceptions; e.g. FileIO checks is_blocking() in order to do
|
| + // some operations directly on the calling thread if possible.)
|
| friend class ppapi::thunk::subtle::EnterBase;
|
|
|
| // Block until the associated operation has completed. Returns the result.
|
| @@ -152,10 +161,13 @@ class PPAPI_SHARED_EXPORT TrackedCallback
|
| // 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();
|
| + void MarkAsCompletedWithLock();
|
|
|
| // This class is ref counted.
|
| friend class base::RefCountedThreadSafe<TrackedCallback>;
|
| - virtual ~TrackedCallback();
|
| + ~TrackedCallback();
|
| +
|
| + mutable base::Lock lock_;
|
|
|
| // Flag used by |PostAbort()| and |PostRun()| to check that we don't schedule
|
| // the callback more than once.
|
|
|