reland 121901, PPAPI: Add unlocking for PPP calls and callbacks...

"""
With this patch, ppapi_tests pass locally when building with enable_pepper_threading=1. (They didn't before).

TODO: Test more calls off the main thread, make sync completion callbacks work.

BUG=92909
TEST=


Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=121901
"""
[email protected]

Review URL: http://codereview.chromium.org/9361065

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122001 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ppapi/shared_impl/ppp_instance_combined.cc b/ppapi/shared_impl/ppp_instance_combined.cc
index d27c2a0..e5b7998 100644
--- a/ppapi/shared_impl/ppp_instance_combined.cc
+++ b/ppapi/shared_impl/ppp_instance_combined.cc
@@ -1,8 +1,9 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
 
 #include "ppapi/shared_impl/ppp_instance_combined.h"
+#include "ppapi/shared_impl/proxy_lock.h"
 
 namespace ppapi {
 
@@ -26,31 +27,36 @@
                                          uint32_t argc,
                                          const char* argn[],
                                          const char* argv[]) {
-  return instance_1_1_.DidCreate(instance, argc, argn, argv);
+  return CallWhileUnlocked(instance_1_1_.DidCreate, instance, argc, argn, argv);
 }
 
 void PPP_Instance_Combined::DidDestroy(PP_Instance instance) {
-  return instance_1_1_.DidDestroy(instance);
+  return CallWhileUnlocked(instance_1_1_.DidDestroy, instance);
 }
 
 void PPP_Instance_Combined::DidChangeView(PP_Instance instance,
                                           PP_Resource view_changed_resource,
                                           const struct PP_Rect* position,
                                           const struct PP_Rect* clip) {
-  if (instance_1_1_.DidChangeView)
-    instance_1_1_.DidChangeView(instance, view_changed_resource);
-  else
-    did_change_view_1_0_(instance, position, clip);
+  if (instance_1_1_.DidChangeView) {
+    CallWhileUnlocked(instance_1_1_.DidChangeView,
+                      instance,
+                      view_changed_resource);
+  } else {
+    CallWhileUnlocked(did_change_view_1_0_, instance, position, clip);
+  }
 }
 
 void PPP_Instance_Combined::DidChangeFocus(PP_Instance instance,
                                            PP_Bool has_focus) {
-  instance_1_1_.DidChangeFocus(instance, has_focus);
+  CallWhileUnlocked(instance_1_1_.DidChangeFocus, instance, has_focus);
 }
 
 PP_Bool PPP_Instance_Combined::HandleDocumentLoad(PP_Instance instance,
                                                   PP_Resource url_loader) {
-  return instance_1_1_.HandleDocumentLoad(instance, url_loader);
+  return CallWhileUnlocked(instance_1_1_.HandleDocumentLoad,
+                           instance,
+                           url_loader);
 }
 
 }  // namespace ppapi
diff --git a/ppapi/shared_impl/proxy_lock.cc b/ppapi/shared_impl/proxy_lock.cc
index 226c51f..7ef652b 100644
--- a/ppapi/shared_impl/proxy_lock.cc
+++ b/ppapi/shared_impl/proxy_lock.cc
@@ -23,4 +23,9 @@
     lock->Release();
 }
 
+void CallWhileLocked(const base::Closure& closure) {
+  ProxyAutoLock lock;
+  closure.Run();
+}
+
 }  // namespace ppapi
diff --git a/ppapi/shared_impl/proxy_lock.h b/ppapi/shared_impl/proxy_lock.h
index c5571f39..20e907be 100644
--- a/ppapi/shared_impl/proxy_lock.h
+++ b/ppapi/shared_impl/proxy_lock.h
@@ -6,6 +6,8 @@
 #define PPAPI_SHARED_IMPL_PROXY_LOCK_H_
 
 #include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
 
 #include "ppapi/shared_impl/ppapi_shared_export.h"
 
@@ -34,6 +36,7 @@
   // Relinquish the proxy lock. If the lock has not been set, this does nothing.
   static void Release();
 
+ private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock);
 };
 
@@ -68,6 +71,78 @@
   DISALLOW_COPY_AND_ASSIGN(ProxyAutoUnlock);
 };
 
+// A set of function template overloads for invoking a function pointer while
+// the ProxyLock is unlocked. This assumes that the luck is held.
+// CallWhileUnlocked unlocks the ProxyLock just before invoking the given
+// function. The lock is immediately re-acquired when the invoked function
+// function returns. CallWhileUnlocked returns whatever the given function
+// returned.
+//
+// Example usage:
+//   *result = CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent,
+//                               instance,
+//                               resource->pp_resource());
+template <class ReturnType>
+ReturnType CallWhileUnlocked(ReturnType (*function)()) {
+  ProxyAutoUnlock unlock;
+  return function();
+}
+template <class ReturnType, class P1>
+ReturnType CallWhileUnlocked(ReturnType (*function)(P1), const P1& p1) {
+  ProxyAutoUnlock unlock;
+  return function(p1);
+}
+template <class ReturnType, class P1, class P2>
+ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2),
+                             const P1& p1,
+                             const P2& p2) {
+  ProxyAutoUnlock unlock;
+  return function(p1, p2);
+}
+template <class ReturnType, class P1, class P2, class P3>
+ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3),
+                             const P1& p1,
+                             const P2& p2,
+                             const P3& p3) {
+  ProxyAutoUnlock unlock;
+  return function(p1, p2, p3);
+}
+template <class ReturnType, class P1, class P2, class P3, class P4>
+ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3, P4),
+                             const P1& p1,
+                             const P2& p2,
+                             const P3& p3,
+                             const P4& p4) {
+  ProxyAutoUnlock unlock;
+  return function(p1, p2, p3, p4);
+}
+template <class ReturnType, class P1, class P2, class P3, class P4, class P5>
+ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3, P4, P5),
+                             const P1& p1,
+                             const P2& p2,
+                             const P3& p3,
+                             const P4& p4,
+                             const P5& p5) {
+  ProxyAutoUnlock unlock;
+  return function(p1, p2, p3, p4, p5);
+}
+
+// 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);
+
+// 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:
+//   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);
+}
 
 }  // namespace ppapi
 
diff --git a/ppapi/shared_impl/tracked_callback.cc b/ppapi/shared_impl/tracked_callback.cc
index a49f4ff9..f97acfd 100644
--- a/ppapi/shared_impl/tracked_callback.cc
+++ b/ppapi/shared_impl/tracked_callback.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -12,6 +12,7 @@
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/shared_impl/callback_tracker.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/proxy_lock.h"
 #include "ppapi/shared_impl/resource.h"
 
 namespace ppapi {
@@ -49,8 +50,8 @@
     if (!abort_impl_factory_.HasWeakPtrs()) {
       MessageLoop::current()->PostTask(
           FROM_HERE,
-          base::Bind(&TrackedCallback::Abort,
-                     abort_impl_factory_.GetWeakPtr()));
+          RunWhileLocked(base::Bind(&TrackedCallback::Abort,
+                                    abort_impl_factory_.GetWeakPtr())));
     }
   }
 }
@@ -69,7 +70,7 @@
     // Do this before running the callback in case of reentrancy (which
     // shouldn't happen, but avoid strange failures).
     MarkAsCompleted();
-    PP_RunCompletionCallback(&callback, result);
+    CallWhileUnlocked(PP_RunCompletionCallback, &callback, result);
   }
 }