Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Unified Diff: ppapi/shared_impl/proxy_lock.h

Issue 19678028: PAPI: Fix bug in RunWhileLocked, add support for params (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add the unit test Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ppapi/ppapi_tests.gypi ('k') | ppapi/shared_impl/proxy_lock.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ppapi/shared_impl/proxy_lock.h
diff --git a/ppapi/shared_impl/proxy_lock.h b/ppapi/shared_impl/proxy_lock.h
index e0e97e4e38f4071ed592a4b673a4578265fadf17..b73498e1a34c1b07972058ad50f8f2b0ed7b5ad5 100644
--- a/ppapi/shared_impl/proxy_lock.h
+++ b/ppapi/shared_impl/proxy_lock.h
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/threading/thread_checker.h"
#include "ppapi/shared_impl/ppapi_shared_export.h"
@@ -27,6 +28,11 @@ namespace ppapi {
// tracker, etc.
class PPAPI_SHARED_EXPORT ProxyLock {
public:
+ // Return the globally unique ProxyLock. Normally, you should not access this
+ // directly but instead use ProxyAutoLock or ProxyAutoUnlock. But sometimes
+ // you need access to the ProxyLock for e.g. a condition variable.
teravest 2013/07/24 16:38:44 /for e.g./for example/
dmichael (off chromium) 2013/07/24 22:30:11 Done.
+ static base::Lock* Get();
+
// Acquire the proxy lock. If it is currently held by another thread, block
// until it is available. If the lock has not been set using the 'Set' method,
// this operation does nothing. That is the normal case for the host side;
@@ -40,7 +46,6 @@ class PPAPI_SHARED_EXPORT ProxyLock {
// process). Does nothing when running in-process (or in the host process).
static void AssertAcquired();
- private:
yzshen1 2013/07/24 18:45:19 Out of curiosity: Why removing "private:"?
dmichael (off chromium) 2013/07/24 22:30:11 Oops, that was an accident when I was deleting stu
DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock);
};
@@ -132,21 +137,153 @@ ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3, P4, P5),
}
void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure);
-// CallWhileLocked locks the ProxyLock and runs the given closure immediately.
-// The lock is released when CallWhileLocked returns. This function assumes the
-// lock is not held. This is mostly for use in RunWhileLocked; see below.
-void PPAPI_SHARED_EXPORT CallWhileLocked(const base::Closure& closure);
+namespace internal {
-// RunWhileLocked binds the given closure with CallWhileLocked and returns the
-// new Closure. This is for cases where you want to run a task, but you want to
-// ensure that the ProxyLock is acquired for the duration of the task.
-// Example usage:
+template <typename RunType>
+class RunWhileLockedHelper;
+
+template <>
+class RunWhileLockedHelper<void ()> {
+ public:
+ typedef base::Callback<void ()> CallbackType;
+ explicit RunWhileLockedHelper(const CallbackType& callback)
+ : callback_(new CallbackType(callback)) {
+ // Copying |callback| may adjust reference counts for bound Vars or
+ // Resources; we should have the lock already.
+ ProxyLock::AssertAcquired();
+ // CallWhileLocked and destruction might happen on a different thread from
+ // creation.
+ thread_checker_.DetachFromThread();
+ }
+ void CallWhileLocked() {
+ // Bind thread_checker_ to this thread so we can check in the destructor.
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ProxyAutoLock lock;
+ {
+ // Use a scope and local Callback to ensure that the callback is cleared
+ // before the lock is released, even in the unlikely event that Run()
+ // throws an exception.
+ scoped_ptr<CallbackType> temp_callback(callback_.Pass());
+ temp_callback->Run();
+ }
+ }
+
+ private:
+ scoped_ptr<CallbackType> callback_;
+
+ // Used to ensure that the Callback is run and deleted on the same thread.
+ base::ThreadChecker thread_checker_;
+};
+
+template <typename P1>
+class RunWhileLockedHelper<void (P1)> {
+ public:
+ typedef base::Callback<void (P1)> CallbackType;
+ explicit RunWhileLockedHelper(const CallbackType& callback)
+ : callback_(new CallbackType(callback)) {
+ ProxyLock::AssertAcquired();
+ thread_checker_.DetachFromThread();
+ }
+ void CallWhileLocked(P1 p1) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ProxyAutoLock lock;
+ {
+ scoped_ptr<CallbackType> temp_callback(callback_.Pass());
+ temp_callback->Run(p1);
+ }
+ }
+
+ private:
+ scoped_ptr<CallbackType> callback_;
+ base::ThreadChecker thread_checker_;
+};
+
+template <typename P1, typename P2>
+class RunWhileLockedHelper<void (P1, P2)> {
+ public:
+ typedef base::Callback<void (P1, P2)> CallbackType;
+ explicit RunWhileLockedHelper(const CallbackType& callback)
+ : callback_(new CallbackType(callback)) {
+ ProxyLock::AssertAcquired();
+ thread_checker_.DetachFromThread();
+ }
+ void CallWhileLocked(P1 p1, P2 p2) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ProxyAutoLock lock;
+ {
+ scoped_ptr<CallbackType> temp_callback(callback_.Pass());
+ temp_callback->Run(p1, p2);
+ }
+ }
+
+ private:
+ scoped_ptr<CallbackType> callback_;
+ base::ThreadChecker thread_checker_;
+};
+
+template <typename P1, typename P2, typename P3>
+class RunWhileLockedHelper<void (P1, P2, P3)> {
+ public:
+ typedef base::Callback<void (P1, P2, P3)> CallbackType;
+ explicit RunWhileLockedHelper(const CallbackType& callback)
+ : callback_(new CallbackType(callback)) {
+ ProxyLock::AssertAcquired();
+ thread_checker_.DetachFromThread();
+ }
+ void CallWhileLocked(P1 p1, P2 p2, P3 p3) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ProxyAutoLock lock;
+ {
+ scoped_ptr<CallbackType> temp_callback(callback_.Pass());
+ temp_callback->Run(p1, p2, p3);
+ }
+ }
+
+ private:
+ scoped_ptr<CallbackType> callback_;
+ base::ThreadChecker thread_checker_;
+};
+
+} // namespace internal
+
+// RunWhileLocked wraps the given Callback in a new Callback that, when invoked:
+// 1) Locks the ProxyLock.
+// 2) Runs the original Callback (forwarding arguments, if any).
+// 3) Clears the original Callback (while the lock is held).
+// 4) Unlocks the ProxyLock.
+// Note that it's important that the callback is cleared in step (3), in case
+// clearing the Callback causes a destructor (e.g., for a Resource) to run,
+// which should hold the ProxyLock to avoid data races.
+//
+// This is for cases where you want to run a task or store a Callback, but you
+// want to ensure that the ProxyLock is acquired for the duration of the task.
+// EXAMPLE USAGE:
// GetMainThreadMessageLoop()->PostDelayedTask(
// FROM_HERE,
// RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
// delay_in_ms);
-inline base::Closure RunWhileLocked(const base::Closure& closure) {
- return base::Bind(CallWhileLocked, closure);
+//
+// Note that the returned Callback must be:
yzshen1 2013/07/24 18:45:19 I think the comment is still pretty hard to unders
+// - Posted to a MessageLoop.
+// - Copied to another Callback (e.g. a member variable).
+// or
+// - Run().
+// E.g., code like the following:
+// {
+// base::Callback<...> callback_a = RunWhileLocked(callback_b);
+// // Do nothing about callback_a and let it go out of scope.
+// }
+// Will fail when the callback is destroyed, because the constructor expects the
teravest 2013/07/24 16:38:44 What do you mean by fail here? It'd be good if you
+// proxy lock to already be acquired, while the destructor expects to need to
+// acquire the lock (if the callback has not been run, like in the above case).
+template <class FunctionType>
+inline base::Callback<FunctionType>
+RunWhileLocked(const base::Callback<FunctionType>& callback) {
+ internal::RunWhileLockedHelper<FunctionType>* helper =
+ new internal::RunWhileLockedHelper<FunctionType>(callback);
+ return base::Bind(
+ &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked,
+ base::Owned(helper));
}
} // namespace ppapi
« no previous file with comments | « ppapi/ppapi_tests.gypi ('k') | ppapi/shared_impl/proxy_lock.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698