PPAPI: Make blocking completion callbacks work.

This also makes scoped_refptr<TrackedCallback> the "new" way to pass completion callbacks in an API. This allows the Enter object to handle checking for blocking callbacks on the main thread to report error, and blocking if on the background thread. This way, interfaces don't have to write any special cases for blocking callbacks.

When built with enable_pepper_threading=1 locally, URLLoader tests all pass for blocking completion callbacks. I haven't updated all tests yet.

BUG=92909
TEST=


Review URL: https://chromiumcodereview.appspot.com/10081020

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@143806 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ppapi/proxy/enter_proxy.h b/ppapi/proxy/enter_proxy.h
index 6ee93a3..3832a13 100644
--- a/ppapi/proxy/enter_proxy.h
+++ b/ppapi/proxy/enter_proxy.h
@@ -1,4 +1,4 @@
-// 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.
 
@@ -45,8 +45,20 @@
     : public thunk::EnterResourceNoLock<ResourceT> {
  public:
   explicit EnterHostFromHostResource(const HostResource& host_resource)
-      : thunk::EnterResourceNoLock<ResourceT>(
-            host_resource.host_resource(), false) {
+      : thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(),
+                                              false) {
+    // Validate that we're in the host rather than the plugin. Otherwise this
+    // object will do the wrong thing. In the host, the instance should have
+    // a corresponding host disptacher (assuming the resource is valid).
+    DCHECK(this->failed() ||
+           HostDispatcher::GetForInstance(host_resource.instance()));
+  }
+
+  EnterHostFromHostResource(const HostResource& host_resource,
+                            const pp::CompletionCallback& callback)
+      : thunk::EnterResourceNoLock<ResourceT>(host_resource.host_resource(),
+                                              callback.pp_completion_callback(),
+                                              false) {
     // Validate that we're in the host rather than the plugin. Otherwise this
     // object will do the wrong thing. In the host, the instance should have
     // a corresponding host disptacher (assuming the resource is valid).
@@ -92,9 +104,8 @@
   EnterHostFromHostResourceForceCallback(
       const HostResource& host_resource,
       const pp::CompletionCallback& callback)
-      : EnterHostFromHostResource<ResourceT>(host_resource),
-        needs_running_(true),
-        callback_(callback) {
+      : EnterHostFromHostResource<ResourceT>(host_resource, callback),
+        needs_running_(true) {
   }
 
   // For callbacks that take no parameters except the "int32_t result". Most
@@ -104,9 +115,9 @@
       const HostResource& host_resource,
       CallbackFactory& factory,
       Method method)
-      : EnterHostFromHostResource<ResourceT>(host_resource),
-        needs_running_(true),
-        callback_(factory.NewOptionalCallback(method)) {
+      : EnterHostFromHostResource<ResourceT>(host_resource,
+            factory.NewOptionalCallback(method)),
+        needs_running_(true) {
     if (this->failed())
       RunCallback(PP_ERROR_BADRESOURCE);
   }
@@ -118,9 +129,9 @@
       CallbackFactory& factory,
       Method method,
       const A& a)
-      : EnterHostFromHostResource<ResourceT>(host_resource),
-        needs_running_(true),
-        callback_(factory.NewOptionalCallback(method, a)) {
+      : EnterHostFromHostResource<ResourceT>(host_resource,
+            factory.NewOptionalCallback(method, a)),
+        needs_running_(true) {
     if (this->failed())
       RunCallback(PP_ERROR_BADRESOURCE);
   }
@@ -133,9 +144,9 @@
       Method method,
       const A& a,
       const B& b)
-      : EnterHostFromHostResource<ResourceT>(host_resource),
-        needs_running_(true),
-        callback_(factory.NewOptionalCallback(method, a, b)) {
+      : EnterHostFromHostResource<ResourceT>(host_resource,
+            factory.NewOptionalCallback(method, a, b)),
+        needs_running_(true) {
     if (this->failed())
       RunCallback(PP_ERROR_BADRESOURCE);
   }
@@ -150,24 +161,24 @@
 
   void SetResult(int32_t result) {
     DCHECK(needs_running_) << "Don't call SetResult when there already is one.";
-    needs_running_ = false;
     if (result != PP_OK_COMPLETIONPENDING)
-      callback_.Run(result);
-  }
-
-  PP_CompletionCallback callback() {
-    return callback_.pp_completion_callback();
+      RunCallback(result);
+    needs_running_ = false;
+    // Either we already ran the callback, or it will be run asynchronously. We
+    // clear the callback so it isn't accidentally run again (and because
+    // EnterBase checks that the callback has been cleared).
+    this->ClearCallback();
   }
 
  private:
   void RunCallback(int32_t result) {
     DCHECK(needs_running_);
     needs_running_ = false;
-    callback_.Run(result);
+    this->callback()->Run(result);
+    this->ClearCallback();
   }
 
   bool needs_running_;
-  pp::CompletionCallback callback_;
 };
 
 }  // namespace proxy
diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc
index ad8c620..9cf606e2 100644
--- a/ppapi/proxy/plugin_dispatcher.cc
+++ b/ppapi/proxy/plugin_dispatcher.cc
@@ -45,17 +45,13 @@
 }  // namespace
 
 InstanceData::InstanceData()
-    : flash_fullscreen(PP_FALSE),
-      mouse_lock_callback(PP_BlockUntilComplete()) {
+    : flash_fullscreen(PP_FALSE) {
 }
 
 InstanceData::~InstanceData() {
   // Run any pending mouse lock callback to prevent leaks.
-  if (mouse_lock_callback.func) {
-    CallWhileUnlocked(PP_RunAndClearCompletionCallback,
-                      &mouse_lock_callback,
-                      static_cast<int32_t>(PP_ERROR_ABORTED));
-  }
+  if (mouse_lock_callback)
+    mouse_lock_callback->Abort();
 }
 
 PluginDispatcher::PluginDispatcher(PP_GetInterface_Func get_interface,
diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h
index 0639d29..5dd6725 100644
--- a/ppapi/proxy/plugin_dispatcher.h
+++ b/ppapi/proxy/plugin_dispatcher.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/hash_tables.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process.h"
 #include "build/build_config.h"
@@ -19,6 +20,7 @@
 #include "ppapi/proxy/dispatcher.h"
 #include "ppapi/shared_impl/ppapi_preferences.h"
 #include "ppapi/shared_impl/ppb_view_shared.h"
+#include "ppapi/shared_impl/tracked_callback.h"
 
 namespace ppapi {
 
@@ -41,8 +43,8 @@
 
   PP_Bool flash_fullscreen;  // Used for PPB_FlashFullscreen.
 
-  // When non-0, indicates the callback to execute when mouse lock is lost.
-  PP_CompletionCallback mouse_lock_callback;
+  // When non-NULL, indicates the callback to execute when mouse lock is lost.
+  scoped_refptr<TrackedCallback> mouse_lock_callback;
 };
 
 class PPAPI_PROXY_EXPORT PluginDispatcher
diff --git a/ppapi/proxy/ppb_audio_input_proxy.cc b/ppapi/proxy/ppb_audio_input_proxy.cc
index 32aa6b7..011e332 100644
--- a/ppapi/proxy/ppb_audio_input_proxy.cc
+++ b/ppapi/proxy/ppb_audio_input_proxy.cc
@@ -36,7 +36,7 @@
   virtual int32_t OpenTrusted(
       const std::string& device_id,
       PP_Resource config,
-      const PP_CompletionCallback& create_callback) OVERRIDE;
+      scoped_refptr<TrackedCallback> create_callback) OVERRIDE;
   virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
   virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
   virtual const std::vector<DeviceRefData>& GetDeviceRefData() const OVERRIDE;
@@ -45,11 +45,12 @@
   // PPB_AudioInput_Shared implementation.
   virtual int32_t InternalEnumerateDevices(
       PP_Resource* devices,
-      PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t InternalOpen(const std::string& device_id,
-                               PP_AudioSampleRate sample_rate,
-                               uint32_t sample_frame_count,
-                               PP_CompletionCallback callback) OVERRIDE;
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t InternalOpen(
+      const std::string& device_id,
+      PP_AudioSampleRate sample_rate,
+      uint32_t sample_frame_count,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual PP_Bool InternalStartCapture() OVERRIDE;
   virtual PP_Bool InternalStopCapture() OVERRIDE;
   virtual void InternalClose() OVERRIDE;
@@ -69,9 +70,10 @@
   Close();
 }
 
-int32_t AudioInput::OpenTrusted(const std::string& device_id,
-                                PP_Resource config,
-                                const PP_CompletionCallback& create_callback) {
+int32_t AudioInput::OpenTrusted(
+    const std::string& device_id,
+    PP_Resource config,
+    scoped_refptr<TrackedCallback> create_callback) {
   return PP_ERROR_NOTSUPPORTED;  // Don't proxy the trusted interface.
 }
 
@@ -89,10 +91,11 @@
   return result;
 }
 
-int32_t AudioInput::InternalEnumerateDevices(PP_Resource* devices,
-                                             PP_CompletionCallback callback) {
+int32_t AudioInput::InternalEnumerateDevices(
+    PP_Resource* devices,
+    scoped_refptr<TrackedCallback> callback) {
   devices_ = devices;
-  enumerate_devices_callback_ = new TrackedCallback(this, callback);
+  enumerate_devices_callback_ = callback;
   GetDispatcher()->Send(new PpapiHostMsg_PPBAudioInput_EnumerateDevices(
       API_ID_PPB_AUDIO_INPUT_DEV, host_resource()));
   return PP_OK_COMPLETIONPENDING;
@@ -101,8 +104,8 @@
 int32_t AudioInput::InternalOpen(const std::string& device_id,
                                  PP_AudioSampleRate sample_rate,
                                  uint32_t sample_frame_count,
-                                 PP_CompletionCallback callback) {
-  open_callback_ = new TrackedCallback(this, callback);
+                                 scoped_refptr<TrackedCallback> callback) {
+  open_callback_ = callback;
   GetDispatcher()->Send(new PpapiHostMsg_PPBAudioInput_Open(
       API_ID_PPB_AUDIO_INPUT_DEV, host_resource(), device_id, sample_rate,
       sample_frame_count));
@@ -154,7 +157,7 @@
 
   AudioInput* audio_input = new AudioInput(result);
   int32_t open_result = audio_input->Open("", config, audio_input_callback,
-      user_data, AudioInput::MakeIgnoredCompletionCallback());
+      user_data, AudioInput::MakeIgnoredCompletionCallback(audio_input));
   if (open_result != PP_OK && open_result != PP_OK_COMPLETIONPENDING) {
     delete audio_input;
     return 0;
diff --git a/ppapi/proxy/ppb_audio_proxy.cc b/ppapi/proxy/ppb_audio_proxy.cc
index 380bc39..7b2c015 100644
--- a/ppapi/proxy/ppb_audio_proxy.cc
+++ b/ppapi/proxy/ppb_audio_proxy.cc
@@ -47,8 +47,9 @@
   virtual PP_Resource GetCurrentConfig() OVERRIDE;
   virtual PP_Bool StartPlayback() OVERRIDE;
   virtual PP_Bool StopPlayback() OVERRIDE;
-  virtual int32_t OpenTrusted(PP_Resource config_id,
-                              PP_CompletionCallback create_callback) OVERRIDE;
+  virtual int32_t OpenTrusted(
+      PP_Resource config_id,
+      scoped_refptr<TrackedCallback> create_callback) OVERRIDE;
   virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
   virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
 
@@ -105,7 +106,7 @@
 }
 
 int32_t Audio::OpenTrusted(PP_Resource config_id,
-                           PP_CompletionCallback create_callback) {
+                           scoped_refptr<TrackedCallback> create_callback) {
   return PP_ERROR_NOTSUPPORTED;  // Don't proxy the trusted interface.
 }
 
diff --git a/ppapi/proxy/ppb_broker_proxy.cc b/ppapi/proxy/ppb_broker_proxy.cc
index b9549e0..9800d32 100644
--- a/ppapi/proxy/ppb_broker_proxy.cc
+++ b/ppapi/proxy/ppb_broker_proxy.cc
@@ -33,7 +33,8 @@
   virtual PPB_Broker_API* AsPPB_Broker_API() OVERRIDE;
 
   // PPB_Broker_API implementation.
-  virtual int32_t Connect(PP_CompletionCallback connect_callback) OVERRIDE;
+  virtual int32_t Connect(
+      scoped_refptr<TrackedCallback> connect_callback) OVERRIDE;
   virtual int32_t GetHandle(int32_t* handle) OVERRIDE;
 
   // Called by the proxy when the host side has completed the request.
@@ -67,18 +68,13 @@
   return this;
 }
 
-int32_t Broker::Connect(PP_CompletionCallback connect_callback) {
-  if (!connect_callback.func) {
-    // Synchronous calls are not supported.
-    return PP_ERROR_BLOCKS_MAIN_THREAD;
-  }
-
+int32_t Broker::Connect(scoped_refptr<TrackedCallback> connect_callback) {
   if (TrackedCallback::IsPending(current_connect_callback_))
     return PP_ERROR_INPROGRESS;
   else if (called_connect_)
     return PP_ERROR_FAILED;
 
-  current_connect_callback_ = new TrackedCallback(this, connect_callback);
+  current_connect_callback_ = connect_callback;
   called_connect_ = true;
 
   bool success = PluginDispatcher::GetForResource(this)->Send(
diff --git a/ppapi/proxy/ppb_core_proxy.cc b/ppapi/proxy/ppb_core_proxy.cc
index fc6da8f..ad8773bf 100644
--- a/ppapi/proxy/ppb_core_proxy.cc
+++ b/ppapi/proxy/ppb_core_proxy.cc
@@ -9,8 +9,6 @@
 #include "base/bind.h"
 #include "base/debug/trace_event.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/message_loop_proxy.h"
 #include "base/time.h"
 #include "ppapi/c/pp_completion_callback.h"
 #include "ppapi/c/pp_resource.h"
@@ -27,12 +25,6 @@
 
 namespace {
 
-base::MessageLoopProxy* GetMainThreadMessageLoop() {
-  CR_DEFINE_STATIC_LOCAL(scoped_refptr<base::MessageLoopProxy>, proxy,
-      (base::MessageLoopProxy::current()));
-  return proxy.get();
-}
-
 void AddRefResource(PP_Resource resource) {
   ppapi::ProxyAutoLock lock;
   PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(resource);
@@ -61,14 +53,18 @@
 void CallOnMainThread(int delay_in_ms,
                       PP_CompletionCallback callback,
                       int32_t result) {
-  GetMainThreadMessageLoop()->PostDelayedTask(
+  DCHECK(callback.func);
+  if (!callback.func)
+    return;
+  PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostDelayedTask(
       FROM_HERE,
       RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
       base::TimeDelta::FromMilliseconds(delay_in_ms));
 }
 
 PP_Bool IsMainThread() {
-  return PP_FromBool(GetMainThreadMessageLoop()->BelongsToCurrentThread());
+  return PP_FromBool(PpapiGlobals::Get()->
+      GetMainThreadMessageLoop()->BelongsToCurrentThread());
 }
 
 const PPB_Core core_interface = {
diff --git a/ppapi/proxy/ppb_file_chooser_proxy.cc b/ppapi/proxy/ppb_file_chooser_proxy.cc
index 8bf83da4c..26ab4304 100644
--- a/ppapi/proxy/ppb_file_chooser_proxy.cc
+++ b/ppapi/proxy/ppb_file_chooser_proxy.cc
@@ -46,18 +46,18 @@
 
   // PPB_FileChooser_API implementation.
   virtual int32_t Show(const PP_ArrayOutput& output,
-                       const PP_CompletionCallback& callback) OVERRIDE;
+                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t ShowWithoutUserGesture(
       PP_Bool save_as,
       PP_Var suggested_file_name,
       const PP_ArrayOutput& output,
-      const PP_CompletionCallback& callback);
-  virtual int32_t Show0_5(const PP_CompletionCallback& callback) OVERRIDE;
+      scoped_refptr<TrackedCallback> callback);
+  virtual int32_t Show0_5(scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual PP_Resource GetNextChosenFile() OVERRIDE;
   virtual int32_t ShowWithoutUserGesture0_5(
       PP_Bool save_as,
       PP_Var suggested_file_name,
-      const PP_CompletionCallback& callback) OVERRIDE;
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
 
   // Handles the choose complete notification from the host.
   void ChooseComplete(
@@ -68,7 +68,7 @@
   int32_t Show(bool require_user_gesture,
                PP_Bool save_as,
                PP_Var suggested_file_name,
-               const PP_CompletionCallback& callback);
+               scoped_refptr<TrackedCallback> callback);
 
   // When using v0.6 of the API, contains the array output info.
   ArrayWriter output_;
@@ -103,7 +103,7 @@
 }
 
 int32_t FileChooser::Show(const PP_ArrayOutput& output,
-                          const PP_CompletionCallback& callback) {
+                          scoped_refptr<TrackedCallback> callback) {
   int32_t result = Show(true, PP_FALSE, PP_MakeUndefined(), callback);
   if (result == PP_OK_COMPLETIONPENDING)
     output_.set_pp_array_output(output);
@@ -114,35 +114,32 @@
     PP_Bool save_as,
     PP_Var suggested_file_name,
     const PP_ArrayOutput& output,
-    const PP_CompletionCallback& callback) {
+    scoped_refptr<TrackedCallback> callback) {
   int32_t result = Show(false, save_as, suggested_file_name, callback);
   if (result == PP_OK_COMPLETIONPENDING)
     output_.set_pp_array_output(output);
   return result;
 }
 
-int32_t FileChooser::Show0_5(const PP_CompletionCallback& callback) {
+int32_t FileChooser::Show0_5(scoped_refptr<TrackedCallback> callback) {
   return Show(true, PP_FALSE, PP_MakeUndefined(), callback);
 }
 
 int32_t FileChooser::ShowWithoutUserGesture0_5(
     PP_Bool save_as,
     PP_Var suggested_file_name,
-    const PP_CompletionCallback& callback) {
+    scoped_refptr<TrackedCallback> callback) {
   return Show(false, save_as, suggested_file_name, callback);
 }
 
 int32_t FileChooser::Show(bool require_user_gesture,
                           PP_Bool save_as,
                           PP_Var suggested_file_name,
-                          const PP_CompletionCallback& callback) {
-  if (!callback.func)
-    return PP_ERROR_BLOCKS_MAIN_THREAD;
-
+                          scoped_refptr<TrackedCallback> callback) {
   if (TrackedCallback::IsPending(current_show_callback_))
     return PP_ERROR_INPROGRESS;  // Can't show more than once.
 
-  current_show_callback_ = new TrackedCallback(this, callback);
+  current_show_callback_ = callback;
   PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this);
   dispatcher->Send(
       new PpapiHostMsg_PPBFileChooser_Show(
diff --git a/ppapi/proxy/ppb_file_io_proxy.cc b/ppapi/proxy/ppb_file_io_proxy.cc
index 0acd3ac..6858655 100644
--- a/ppapi/proxy/ppb_file_io_proxy.cc
+++ b/ppapi/proxy/ppb_file_io_proxy.cc
@@ -1,4 +1,4 @@
-// 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.
 
@@ -41,32 +41,40 @@
   virtual int32_t GetOSFileDescriptor() OVERRIDE;
   virtual int32_t WillWrite(int64_t offset,
                             int32_t bytes_to_write,
-                            PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t WillSetLength(int64_t length,
-                                PP_CompletionCallback callback) OVERRIDE;
+                            scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t WillSetLength(
+      int64_t length,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
 
  private:
   // FileIOImpl overrides.
-  virtual int32_t OpenValidated(PP_Resource file_ref_resource,
-                                PPB_FileRef_API* file_ref_api,
-                                int32_t open_flags,
-                                PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t QueryValidated(PP_FileInfo* info,
-                                 PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t TouchValidated(PP_Time last_access_time,
-                                 PP_Time last_modified_time,
-                                 PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t ReadValidated(int64_t offset,
-                                char* buffer,
-                                int32_t bytes_to_read,
-                                PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t WriteValidated(int64_t offset,
-                                 const char* buffer,
-                                 int32_t bytes_to_write,
-                                 PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t SetLengthValidated(int64_t length,
-                                     PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t FlushValidated(PP_CompletionCallback callback) OVERRIDE;
+  virtual int32_t OpenValidated(
+      PP_Resource file_ref_resource,
+      PPB_FileRef_API* file_ref_api,
+      int32_t open_flags,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t QueryValidated(
+      PP_FileInfo* info,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t TouchValidated(
+      PP_Time last_access_time,
+      PP_Time last_modified_time,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t ReadValidated(
+      int64_t offset,
+      char* buffer,
+      int32_t bytes_to_read,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t WriteValidated(
+      int64_t offset,
+      const char* buffer,
+      int32_t bytes_to_write,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t SetLengthValidated(
+      int64_t length,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t FlushValidated(
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
 
   PluginDispatcher* GetDispatcher() const {
     return PluginDispatcher::GetForResource(this);
@@ -98,7 +106,7 @@
 
 int32_t FileIO::WillWrite(int64_t offset,
                           int32_t bytes_to_write,
-                          PP_CompletionCallback callback) {
+                          scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_WillWrite(
       kApiID, host_resource(), offset, bytes_to_write));
   RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
@@ -106,7 +114,7 @@
 }
 
 int32_t FileIO::WillSetLength(int64_t length,
-                              PP_CompletionCallback callback) {
+                              scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_WillSetLength(
       kApiID, host_resource(), length));
   RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
@@ -116,7 +124,7 @@
 int32_t FileIO::OpenValidated(PP_Resource file_ref_resource,
                               PPB_FileRef_API* file_ref_api,
                               int32_t open_flags,
-                              PP_CompletionCallback callback) {
+                              scoped_refptr<TrackedCallback> callback) {
   Resource* file_ref_object =
       PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_resource);
 
@@ -127,7 +135,7 @@
 }
 
 int32_t FileIO::QueryValidated(PP_FileInfo* info,
-                               PP_CompletionCallback callback) {
+                               scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Query(
       kApiID, host_resource()));
   RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, info);
@@ -136,7 +144,7 @@
 
 int32_t FileIO::TouchValidated(PP_Time last_access_time,
                                PP_Time last_modified_time,
-                               PP_CompletionCallback callback) {
+                               scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Touch(
       kApiID, host_resource(), last_access_time, last_modified_time));
   RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
@@ -146,7 +154,7 @@
 int32_t FileIO::ReadValidated(int64_t offset,
                               char* buffer,
                               int32_t bytes_to_read,
-                              PP_CompletionCallback callback) {
+                              scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Read(
       kApiID, host_resource(), offset, bytes_to_read));
   RegisterCallback(OPERATION_READ, callback, buffer, NULL);
@@ -156,7 +164,7 @@
 int32_t FileIO::WriteValidated(int64_t offset,
                                const char* buffer,
                                int32_t bytes_to_write,
-                               PP_CompletionCallback callback) {
+                               scoped_refptr<TrackedCallback> callback) {
   // TODO(brettw) it would be nice to use a shared memory buffer for large
   // writes rather than having to copy to a string (which will involve a number
   // of extra copies to serialize over IPC).
@@ -167,14 +175,14 @@
 }
 
 int32_t FileIO::SetLengthValidated(int64_t length,
-                                   PP_CompletionCallback callback) {
+                                   scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_SetLength(
       kApiID, host_resource(), length));
   RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
   return PP_OK_COMPLETIONPENDING;
 }
 
-int32_t FileIO::FlushValidated(PP_CompletionCallback callback) {
+int32_t FileIO::FlushValidated(scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Flush(
       kApiID, host_resource()));
   RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL, NULL);
diff --git a/ppapi/proxy/ppb_file_ref_proxy.cc b/ppapi/proxy/ppb_file_ref_proxy.cc
index 26c3e15..d8ffde67 100644
--- a/ppapi/proxy/ppb_file_ref_proxy.cc
+++ b/ppapi/proxy/ppb_file_ref_proxy.cc
@@ -38,14 +38,15 @@
 
   // PPB_FileRef_API implementation (not provided by PPB_FileRef_Shared).
   virtual PP_Resource GetParent() OVERRIDE;
-  virtual int32_t MakeDirectory(PP_Bool make_ancestors,
-                                PP_CompletionCallback callback) OVERRIDE;
+  virtual int32_t MakeDirectory(
+      PP_Bool make_ancestors,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t Touch(PP_Time last_access_time,
                         PP_Time last_modified_time,
-                        PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t Delete(PP_CompletionCallback callback) OVERRIDE;
+                        scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t Delete(scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t Rename(PP_Resource new_file_ref,
-                         PP_CompletionCallback callback) OVERRIDE;
+                         scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual PP_Var GetAbsolutePath() OVERRIDE;
 
   // Executes the pending callback with the given ID. See pending_callbacks_.
@@ -56,9 +57,8 @@
     return PluginDispatcher::GetForResource(this);
   }
 
-  // Adds a callback to the list and returns its ID. Returns 0 if the callback
-  // is invalid.
-  int SendCallback(PP_CompletionCallback callback);
+  // Adds a callback to the list and returns its ID.
+  int SendCallback(scoped_refptr<TrackedCallback> callback);
 
   // This class can have any number of out-standing requests with completion
   // callbacks, in contrast to most resources which have one possible pending
@@ -66,9 +66,10 @@
   //
   // To keep track of them, assign integer IDs to the callbacks, which is how
   // the callback will be identified when it's passed to the host and then
-  // back here.
-  int next_callback_id_;
-  typedef std::map<int, scoped_refptr<TrackedCallback> > PendingCallbackMap;
+  // back here. Use unsigned so that overflow is well-defined.
+  unsigned int next_callback_id_;
+  typedef std::map<unsigned int,
+                   scoped_refptr<TrackedCallback> > PendingCallbackMap;
   PendingCallbackMap pending_callbacks_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(FileRef);
@@ -76,7 +77,7 @@
 
 FileRef::FileRef(const PPB_FileRef_CreateInfo& info)
     : PPB_FileRef_Shared(OBJECT_IS_PROXY, info),
-      next_callback_id_(1) {
+      next_callback_id_(0u) {
 }
 
 FileRef::~FileRef() {
@@ -97,45 +98,30 @@
 }
 
 int32_t FileRef::MakeDirectory(PP_Bool make_ancestors,
-                               PP_CompletionCallback callback) {
-  int callback_id = SendCallback(callback);
-  if (!callback_id)
-    return PP_ERROR_BADARGUMENT;
-
+                               scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory(
-      API_ID_PPB_FILE_REF, host_resource(), make_ancestors, callback_id));
+      API_ID_PPB_FILE_REF, host_resource(), make_ancestors,
+      SendCallback(callback)));
   return PP_OK_COMPLETIONPENDING;
 }
 
 int32_t FileRef::Touch(PP_Time last_access_time,
                        PP_Time last_modified_time,
-                       PP_CompletionCallback callback) {
-  int callback_id = SendCallback(callback);
-  if (!callback_id)
-    return PP_ERROR_BADARGUMENT;
-
+                       scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Touch(
-      API_ID_PPB_FILE_REF, host_resource(),
-      last_access_time, last_modified_time, callback_id));
+      API_ID_PPB_FILE_REF, host_resource(), last_access_time,
+      last_modified_time, SendCallback(callback)));
   return PP_OK_COMPLETIONPENDING;
 }
 
-int32_t FileRef::Delete(PP_CompletionCallback callback) {
-  int callback_id = SendCallback(callback);
-  if (!callback_id)
-    return PP_ERROR_BADARGUMENT;
-
+int32_t FileRef::Delete(scoped_refptr<TrackedCallback> callback) {
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Delete(
-      API_ID_PPB_FILE_REF, host_resource(), callback_id));
+      API_ID_PPB_FILE_REF, host_resource(), SendCallback(callback)));
   return PP_OK_COMPLETIONPENDING;
 }
 
 int32_t FileRef::Rename(PP_Resource new_file_ref,
-                        PP_CompletionCallback callback) {
-  int callback_id = SendCallback(callback);
-  if (!callback_id)
-    return PP_ERROR_BADARGUMENT;
-
+                        scoped_refptr<TrackedCallback> callback) {
   Resource* new_file_ref_object =
       PpapiGlobals::Get()->GetResourceTracker()->GetResource(new_file_ref);
   if (!new_file_ref_object ||
@@ -144,7 +130,7 @@
 
   GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Rename(
       API_ID_PPB_FILE_REF, host_resource(),
-      new_file_ref_object->host_resource(), callback_id));
+      new_file_ref_object->host_resource(), SendCallback(callback)));
   return PP_OK_COMPLETIONPENDING;
 }
 
@@ -170,15 +156,12 @@
   callback->Run(result);
 }
 
-int FileRef::SendCallback(PP_CompletionCallback callback) {
-  if (!callback.func)
-    return 0;
-
+int FileRef::SendCallback(scoped_refptr<TrackedCallback> callback) {
   // In extreme cases the IDs may wrap around, so avoid duplicates.
-  while (pending_callbacks_.find(next_callback_id_) != pending_callbacks_.end())
-    next_callback_id_++;
+  while (pending_callbacks_.count(next_callback_id_))
+    ++next_callback_id_;
 
-  pending_callbacks_[next_callback_id_] = new TrackedCallback(this, callback);
+  pending_callbacks_[next_callback_id_] = callback;
   return next_callback_id_++;
 }
 
diff --git a/ppapi/proxy/ppb_file_system_proxy.cc b/ppapi/proxy/ppb_file_system_proxy.cc
index 370dcab..4619a1f 100644
--- a/ppapi/proxy/ppb_file_system_proxy.cc
+++ b/ppapi/proxy/ppb_file_system_proxy.cc
@@ -46,7 +46,7 @@
 
   // PPB_FileSystem_APi implementation.
   virtual int32_t Open(int64_t expected_size,
-                       PP_CompletionCallback callback) OVERRIDE;
+                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual PP_FileSystemType GetType() OVERRIDE;
 
   // Called when the host has responded to our open request.
@@ -75,13 +75,13 @@
 }
 
 int32_t FileSystem::Open(int64_t expected_size,
-                         PP_CompletionCallback callback) {
+                         scoped_refptr<TrackedCallback> callback) {
   if (TrackedCallback::IsPending(current_open_callback_))
     return PP_ERROR_INPROGRESS;
   if (called_open_)
     return PP_ERROR_FAILED;
 
-  current_open_callback_ = new TrackedCallback(this, callback);
+  current_open_callback_ = callback;
   called_open_ = true;
   PluginDispatcher::GetForResource(this)->Send(
       new PpapiHostMsg_PPBFileSystem_Open(
diff --git a/ppapi/proxy/ppb_flash_menu_proxy.cc b/ppapi/proxy/ppb_flash_menu_proxy.cc
index 276aaf8..1c919a6 100644
--- a/ppapi/proxy/ppb_flash_menu_proxy.cc
+++ b/ppapi/proxy/ppb_flash_menu_proxy.cc
@@ -30,7 +30,7 @@
   // PPB_Flash_Menu_API implementation.
   virtual int32_t Show(const PP_Point* location,
                        int32_t* selected_id,
-                       PP_CompletionCallback callback) OVERRIDE;
+                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
 
   void ShowACK(int32_t selected_id, int32_t result);
 
@@ -55,12 +55,12 @@
 
 int32_t FlashMenu::Show(const struct PP_Point* location,
                         int32_t* selected_id,
-                        struct PP_CompletionCallback callback) {
+                        scoped_refptr<TrackedCallback> callback) {
   if (TrackedCallback::IsPending(callback_))
     return PP_ERROR_INPROGRESS;
 
   selected_id_ptr_ = selected_id;
-  callback_ = new TrackedCallback(this, callback);
+  callback_ = callback;
 
   PluginDispatcher::GetForResource(this)->Send(
       new PpapiHostMsg_PPBFlashMenu_Show(
diff --git a/ppapi/proxy/ppb_graphics_2d_proxy.cc b/ppapi/proxy/ppb_graphics_2d_proxy.cc
index 0cbd3885..2fc34ccc 100644
--- a/ppapi/proxy/ppb_graphics_2d_proxy.cc
+++ b/ppapi/proxy/ppb_graphics_2d_proxy.cc
@@ -43,7 +43,7 @@
   void Scroll(const PP_Rect* clip_rect,
               const PP_Point* amount);
   void ReplaceContents(PP_Resource image_data);
-  int32_t Flush(PP_CompletionCallback callback);
+  int32_t Flush(scoped_refptr<TrackedCallback> callback);
 
   // Notification that the host has sent an ACK for a pending Flush.
   void FlushACK(int32_t result_code);
@@ -126,15 +126,10 @@
       kApiID, host_resource(), image_object->host_resource()));
 }
 
-int32_t Graphics2D::Flush(PP_CompletionCallback callback) {
-  // For now, disallow blocking calls. We'll need to add support for other
-  // threads to this later.
-  if (!callback.func)
-    return PP_ERROR_BLOCKS_MAIN_THREAD;
-
+int32_t Graphics2D::Flush(scoped_refptr<TrackedCallback> callback) {
   if (TrackedCallback::IsPending(current_flush_callback_))
     return PP_ERROR_INPROGRESS;  // Can't have >1 flush pending.
-  current_flush_callback_ = new TrackedCallback(this, callback);
+  current_flush_callback_ = callback;
 
   GetDispatcher()->Send(new PpapiHostMsg_PPBGraphics2D_Flush(kApiID,
                                                              host_resource()));
diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc
index 4cbb5ca..c68b286 100644
--- a/ppapi/proxy/ppb_instance_proxy.cc
+++ b/ppapi/proxy/ppb_instance_proxy.cc
@@ -437,16 +437,13 @@
 }
 
 int32_t PPB_Instance_Proxy::LockMouse(PP_Instance instance,
-                                      PP_CompletionCallback callback) {
-  if (!callback.func)
-    return PP_ERROR_BADARGUMENT;
-
+                                      scoped_refptr<TrackedCallback> callback) {
   // Save the mouse callback on the instance data.
   InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())->
       GetInstanceData(instance);
   if (!data)
     return PP_ERROR_BADARGUMENT;
-  if (data->mouse_lock_callback.func)
+  if (TrackedCallback::IsPending(data->mouse_lock_callback))
     return PP_ERROR_INPROGRESS;  // Already have a pending callback.
   data->mouse_lock_callback = callback;
 
@@ -654,7 +651,7 @@
     return;
   }
   int32_t result = enter.functions()->LockMouse(instance,
-                                                cb.pp_completion_callback());
+                                                enter.callback());
   if (result != PP_OK_COMPLETIONPENDING)
     cb.Run(result);
 }
@@ -720,8 +717,9 @@
     *result = enter.functions()->DocumentCanAccessDocument(active, target);
 }
 
-void PPB_Instance_Proxy::OnHostMsgGetDocumentURL(PP_Instance instance,
-                                                 SerializedVarReturnValue result) {
+void PPB_Instance_Proxy::OnHostMsgGetDocumentURL(
+    PP_Instance instance,
+    SerializedVarReturnValue result) {
   EnterInstanceNoLock enter(instance);
   if (enter.succeeded()) {
     result.Return(dispatcher(),
@@ -794,11 +792,11 @@
       GetInstanceData(instance);
   if (!data)
     return;  // Instance was probably deleted.
-  if (!data->mouse_lock_callback.func) {
+  if (TrackedCallback::IsPending(data->mouse_lock_callback)) {
     NOTREACHED();
     return;
   }
-  PP_RunAndClearCompletionCallback(&data->mouse_lock_callback, result);
+  TrackedCallback::ClearAndRun(&(data->mouse_lock_callback), result);
 }
 
 void PPB_Instance_Proxy::MouseLockCompleteInHost(int32_t result,
diff --git a/ppapi/proxy/ppb_instance_proxy.h b/ppapi/proxy/ppb_instance_proxy.h
index 7a84ec8..20dd60db 100644
--- a/ppapi/proxy/ppb_instance_proxy.h
+++ b/ppapi/proxy/ppb_instance_proxy.h
@@ -85,7 +85,7 @@
                             PP_Resource image,
                             const PP_Point* hot_spot) OVERRIDE;
   virtual int32_t LockMouse(PP_Instance instance,
-                            PP_CompletionCallback callback) OVERRIDE;
+                            scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual void UnlockMouse(PP_Instance instance) OVERRIDE;
   virtual PP_Bool GetDefaultPrintSettings(
       PP_Instance instance,
diff --git a/ppapi/proxy/ppb_message_loop_proxy.cc b/ppapi/proxy/ppb_message_loop_proxy.cc
index 7a64b50..bcbb82a7 100644
--- a/ppapi/proxy/ppb_message_loop_proxy.cc
+++ b/ppapi/proxy/ppb_message_loop_proxy.cc
@@ -13,6 +13,7 @@
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/proxy/plugin_dispatcher.h"
 #include "ppapi/proxy/plugin_globals.h"
+#include "ppapi/shared_impl/proxy_lock.h"
 #include "ppapi/shared_impl/resource.h"
 #include "ppapi/thunk/enter.h"
 #include "ppapi/thunk/ppb_message_loop_api.h"
@@ -140,10 +141,9 @@
   // PP_ERROR_BLOCKS_MAIN_THREAD.  Maybe have a special constructor for that
   // one?
 
-  // TODO(brettw) figure out how to release the lock. Can't run the message
-  // loop while holding the lock.
   nested_invocations_++;
-  loop_->Run();
+  CallWhileUnlocked(base::Bind(&MessageLoop::Run,
+                               base::Unretained(loop_.get())));
   nested_invocations_--;
 
   if (should_destroy_ && nested_invocations_ == 0) {
diff --git a/ppapi/proxy/ppb_network_monitor_private_proxy.cc b/ppapi/proxy/ppb_network_monitor_private_proxy.cc
index 865dc87d..0d17cd4 100644
--- a/ppapi/proxy/ppb_network_monitor_private_proxy.cc
+++ b/ppapi/proxy/ppb_network_monitor_private_proxy.cc
@@ -7,6 +7,7 @@
 #include "ppapi/proxy/enter_proxy.h"
 #include "ppapi/proxy/plugin_proxy_delegate.h"
 #include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/proxy_lock.h"
 #include "ppapi/thunk/ppb_network_monitor_private_api.h"
 
 namespace ppapi {
@@ -39,7 +40,13 @@
     return this;
   }
 
-  void OnNetworkListReceived(const scoped_refptr<NetworkListStorage>& list) {
+  // This is invoked when a network list is received for this monitor (either
+  // initially or on a change). It acquires the ProxyLock inside because
+  // ObserverListThreadSafe does not support Bind/Closure, otherwise we would
+  // wrap the call with a lock using RunWhileLocked.
+  void OnNetworkListReceivedLocks(
+      const scoped_refptr<NetworkListStorage>& list) {
+    ProxyAutoLock lock;
     PP_Resource list_resource =
         PPB_NetworkList_Private_Shared::Create(
             OBJECT_IS_PROXY, pp_instance(), list);
@@ -70,6 +77,8 @@
     PP_Instance instance,
     PPB_NetworkMonitor_Callback callback,
     void* user_data) {
+  // TODO(dmichael): Check that this thread has a valid message loop associated
+  //                 with it.
   if (!callback)
     return 0;
 
@@ -98,9 +107,9 @@
     // here.
     proxy->current_list_ = NULL;
   } else if (proxy->current_list_.get()) {
-    MessageLoop::current()->PostTask(FROM_HERE, RunWhileLocked(base::Bind(
-        &NetworkMonitor::OnNetworkListReceived,
-        result->AsWeakPtr(), proxy->current_list_)));
+    MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+        &NetworkMonitor::OnNetworkListReceivedLocks,
+        result->AsWeakPtr(), proxy->current_list_));
   }
 
   return result->GetReference();
@@ -122,7 +131,7 @@
     const ppapi::NetworkList& list) {
   scoped_refptr<NetworkListStorage> list_storage(new NetworkListStorage(list));
   current_list_ = list_storage;
-  monitors_->Notify(&NetworkMonitor::OnNetworkListReceived, list_storage);
+  monitors_->Notify(&NetworkMonitor::OnNetworkListReceivedLocks, list_storage);
 }
 
 void PPB_NetworkMonitor_Private_Proxy::OnNetworkMonitorDeleted(
diff --git a/ppapi/proxy/ppb_network_monitor_private_proxy.h b/ppapi/proxy/ppb_network_monitor_private_proxy.h
index 3c420d8..e764b0cb 100644
--- a/ppapi/proxy/ppb_network_monitor_private_proxy.h
+++ b/ppapi/proxy/ppb_network_monitor_private_proxy.h
@@ -47,6 +47,8 @@
   void OnNetworkMonitorDeleted(NetworkMonitor* monitor,
                                PP_Instance instance);
 
+  // We use ObserverListThreadSafe because we want to send notifications to the
+  // same thread that created the NetworkMonitor.
   scoped_refptr<ObserverListThreadSafe<NetworkMonitor> > monitors_;
 
   int monitors_count_;
diff --git a/ppapi/proxy/ppb_talk_private_proxy.cc b/ppapi/proxy/ppb_talk_private_proxy.cc
index 3b301f03..6297fa3 100644
--- a/ppapi/proxy/ppb_talk_private_proxy.cc
+++ b/ppapi/proxy/ppb_talk_private_proxy.cc
@@ -29,7 +29,7 @@
   thunk::PPB_Talk_Private_API* AsPPB_Talk_Private_API() { return this; }
 
   // PPB_Talk_API implementation.
-  int32_t GetPermission(const PP_CompletionCallback& callback) {
+  int32_t GetPermission(scoped_refptr<TrackedCallback> callback) {
     if (TrackedCallback::IsPending(callback_))
       return PP_ERROR_INPROGRESS;
     PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(
@@ -37,7 +37,7 @@
     if (!dispatcher)
       return PP_ERROR_FAILED;
 
-    callback_ = new TrackedCallback(this, callback);
+    callback_ = callback;
 
     if (PluginGlobals::Get()->plugin_proxy_delegate()->SendToBrowser(
         new PpapiHostMsg_PPBTalk_GetPermission(
diff --git a/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc b/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc
index ed5d5ad6..5e6557b 100644
--- a/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc
+++ b/ppapi/proxy/ppb_tcp_server_socket_private_proxy.cc
@@ -22,9 +22,6 @@
 namespace ppapi {
 namespace proxy {
 
-typedef thunk::EnterResource<thunk::PPB_TCPServerSocket_Private_API>
-    EnterTCPServerSocket;
-
 namespace {
 
 class TCPServerSocket : public PPB_TCPServerSocket_Shared {
@@ -164,7 +161,8 @@
     PP_Resource socket_resource,
     uint32 socket_id,
     int32_t status) {
-  EnterTCPServerSocket enter(socket_resource, true);
+ thunk::EnterResourceNoLock<thunk::PPB_TCPServerSocket_Private_API>
+     enter(socket_resource, true);
   if (enter.succeeded()) {
     PPB_TCPServerSocket_Shared* server_socket =
         static_cast<PPB_TCPServerSocket_Shared*>(enter.object());
diff --git a/ppapi/proxy/ppb_url_loader_proxy.cc b/ppapi/proxy/ppb_url_loader_proxy.cc
index 1eefe0c..bdeff845 100644
--- a/ppapi/proxy/ppb_url_loader_proxy.cc
+++ b/ppapi/proxy/ppb_url_loader_proxy.cc
@@ -91,19 +91,21 @@
 
   // PPB_URLLoader_API implementation.
   virtual int32_t Open(PP_Resource request_id,
-                       PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t FollowRedirect(PP_CompletionCallback callback) OVERRIDE;
+                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t FollowRedirect(
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual PP_Bool GetUploadProgress(int64_t* bytes_sent,
                                     int64_t* total_bytes_to_be_sent) OVERRIDE;
   virtual PP_Bool GetDownloadProgress(
       int64_t* bytes_received,
       int64_t* total_bytes_to_be_received) OVERRIDE;
   virtual PP_Resource GetResponseInfo() OVERRIDE;
-  virtual int32_t ReadResponseBody(void* buffer,
-                                   int32_t bytes_to_read,
-                                   PP_CompletionCallback callback) OVERRIDE;
+  virtual int32_t ReadResponseBody(
+      void* buffer,
+      int32_t bytes_to_read,
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t FinishStreamingToFile(
-      PP_CompletionCallback callback) OVERRIDE;
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual void Close() OVERRIDE;
   virtual void GrantUniversalAccess() OVERRIDE;
   virtual void SetStatusCallback(
@@ -178,7 +180,7 @@
 }
 
 int32_t URLLoader::Open(PP_Resource request_id,
-                        PP_CompletionCallback callback) {
+                        scoped_refptr<TrackedCallback> callback) {
   EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_id, true);
   if (enter.failed()) {
     Log(PP_LOGLEVEL_ERROR, "PPB_URLLoader.Open: The URL you're requesting is "
@@ -191,22 +193,18 @@
   if (TrackedCallback::IsPending(current_callback_))
     return PP_ERROR_INPROGRESS;
 
-  if (!callback.func)
-    return PP_ERROR_BLOCKS_MAIN_THREAD;
-  current_callback_ = new TrackedCallback(this, callback);
+  current_callback_ = callback;
 
   GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Open(
       API_ID_PPB_URL_LOADER, host_resource(), enter.object()->GetData()));
   return PP_OK_COMPLETIONPENDING;
 }
 
-int32_t URLLoader::FollowRedirect(PP_CompletionCallback callback) {
+int32_t URLLoader::FollowRedirect(scoped_refptr<TrackedCallback> callback) {
   if (TrackedCallback::IsPending(current_callback_))
     return PP_ERROR_INPROGRESS;
 
-  if (!callback.func)
-    return PP_ERROR_BLOCKS_MAIN_THREAD;
-  current_callback_ = new TrackedCallback(this, callback);
+  current_callback_ = callback;
 
   GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect(
       API_ID_PPB_URL_LOADER, host_resource()));
@@ -257,17 +255,12 @@
 
 int32_t URLLoader::ReadResponseBody(void* buffer,
                                     int32_t bytes_to_read,
-                                    PP_CompletionCallback callback) {
+                                    scoped_refptr<TrackedCallback> callback) {
   if (!buffer || bytes_to_read <= 0)
     return PP_ERROR_BADARGUMENT;  // Must specify an output buffer.
   if (TrackedCallback::IsPending(current_callback_))
     return PP_ERROR_INPROGRESS;  // Can only have one request pending.
 
-  // Currently we don't support sync calls to read. We'll need to revisit
-  // how this works when we allow blocking calls (from background threads).
-  if (!callback.func)
-    return PP_ERROR_BADARGUMENT;
-
   if (static_cast<size_t>(bytes_to_read) <= buffer_.size()) {
     // Special case: we've buffered enough data to be able to synchronously
     // return data to the caller. Do so without making IPCs.
@@ -275,7 +268,7 @@
     return bytes_to_read;
   }
 
-  current_callback_ = new TrackedCallback(this, callback);
+  current_callback_ = callback;
   current_read_buffer_ = buffer;
   current_read_buffer_size_ = bytes_to_read;
 
@@ -284,13 +277,12 @@
   return PP_OK_COMPLETIONPENDING;
 }
 
-int32_t URLLoader::FinishStreamingToFile(PP_CompletionCallback callback) {
+int32_t URLLoader::FinishStreamingToFile(
+    scoped_refptr<TrackedCallback> callback) {
   if (TrackedCallback::IsPending(current_callback_))
     return PP_ERROR_INPROGRESS;
 
-  if (!callback.func)
-    return PP_ERROR_BLOCKS_MAIN_THREAD;
-  current_callback_ = new TrackedCallback(this, callback);
+  current_callback_ = callback;
 
   GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile(
       API_ID_PPB_URL_LOADER, host_resource()));
diff --git a/ppapi/proxy/ppb_video_capture_proxy.cc b/ppapi/proxy/ppb_video_capture_proxy.cc
index 6a51299..badd40d 100644
--- a/ppapi/proxy/ppb_video_capture_proxy.cc
+++ b/ppapi/proxy/ppb_video_capture_proxy.cc
@@ -164,12 +164,12 @@
   // PPB_VideoCapture_Shared implementation.
   virtual int32_t InternalEnumerateDevices(
       PP_Resource* devices,
-      const PP_CompletionCallback& callback) OVERRIDE;
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t InternalOpen(
       const std::string& device_id,
       const PP_VideoCaptureDeviceInfo_Dev& requested_info,
       uint32_t buffer_count,
-      const PP_CompletionCallback& callback) OVERRIDE;
+      scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t InternalStartCapture() OVERRIDE;
   virtual int32_t InternalReuseBuffer(uint32_t buffer) OVERRIDE;
   virtual int32_t InternalStopCapture() OVERRIDE;
@@ -214,9 +214,10 @@
 }
 
 int32_t VideoCapture::InternalEnumerateDevices(
-    PP_Resource* devices, const PP_CompletionCallback& callback) {
+    PP_Resource* devices,
+    scoped_refptr<TrackedCallback> callback) {
   devices_ = devices;
-  enumerate_devices_callback_ = new TrackedCallback(this, callback);
+  enumerate_devices_callback_ = callback;
   GetDispatcher()->Send(new PpapiHostMsg_PPBVideoCapture_EnumerateDevices(
       API_ID_PPB_VIDEO_CAPTURE_DEV, host_resource()));
   return PP_OK_COMPLETIONPENDING;
@@ -226,12 +227,8 @@
     const std::string& device_id,
     const PP_VideoCaptureDeviceInfo_Dev& requested_info,
     uint32_t buffer_count,
-    const PP_CompletionCallback& callback) {
-  // Disallow blocking call. The base class doesn't check this.
-  if (!callback.func)
-    return PP_ERROR_BLOCKS_MAIN_THREAD;
-
-  open_callback_ = new TrackedCallback(this, callback);
+    scoped_refptr<TrackedCallback> callback) {
+  open_callback_ = callback;
   GetDispatcher()->Send(new PpapiHostMsg_PPBVideoCapture_Open(
       API_ID_PPB_VIDEO_CAPTURE_DEV, host_resource(), device_id, requested_info,
       buffer_count));
diff --git a/ppapi/proxy/ppb_video_decoder_proxy.cc b/ppapi/proxy/ppb_video_decoder_proxy.cc
index 3f5cdc41..2965fea4 100644
--- a/ppapi/proxy/ppb_video_decoder_proxy.cc
+++ b/ppapi/proxy/ppb_video_decoder_proxy.cc
@@ -1,4 +1,4 @@
-// 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.
 
@@ -35,12 +35,12 @@
 
   // PPB_VideoDecoder_API implementation.
   virtual int32_t Decode(const PP_VideoBitstreamBuffer_Dev* bitstream_buffer,
-                         PP_CompletionCallback callback) OVERRIDE;
+                         scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual void AssignPictureBuffers(
       uint32_t no_of_buffers, const PP_PictureBuffer_Dev* buffers) OVERRIDE;
   virtual void ReusePictureBuffer(int32_t picture_buffer_id) OVERRIDE;
-  virtual int32_t Flush(PP_CompletionCallback callback) OVERRIDE;
-  virtual int32_t Reset(PP_CompletionCallback callback) OVERRIDE;
+  virtual int32_t Flush(scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t Reset(scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual void Destroy() OVERRIDE;
 
  private:
@@ -65,7 +65,7 @@
 
 int32_t VideoDecoder::Decode(
     const PP_VideoBitstreamBuffer_Dev* bitstream_buffer,
-    PP_CompletionCallback callback) {
+    scoped_refptr<TrackedCallback> callback) {
   EnterResourceNoLock<PPB_Buffer_API>
       enter_buffer(bitstream_buffer->data, true);
   if (enter_buffer.failed())
@@ -102,7 +102,7 @@
       API_ID_PPB_VIDEO_DECODER_DEV, host_resource(), picture_buffer_id));
 }
 
-int32_t VideoDecoder::Flush(PP_CompletionCallback callback) {
+int32_t VideoDecoder::Flush(scoped_refptr<TrackedCallback> callback) {
   if (!SetFlushCallback(callback))
     return PP_ERROR_INPROGRESS;
 
@@ -112,7 +112,7 @@
   return PP_OK_COMPLETIONPENDING;
 }
 
-int32_t VideoDecoder::Reset(PP_CompletionCallback callback) {
+int32_t VideoDecoder::Reset(scoped_refptr<TrackedCallback> callback) {
   if (!SetResetCallback(callback))
     return PP_ERROR_INPROGRESS;
 
diff --git a/ppapi/proxy/proxy_array_output.h b/ppapi/proxy/proxy_array_output.h
index d717909..6d15e0b 100644
--- a/ppapi/proxy/proxy_array_output.h
+++ b/ppapi/proxy/proxy_array_output.h
@@ -30,7 +30,7 @@
 //
 //   callback = factory.NewOptionalCallback(&OnCallbackComplete, output);
 //   DoSomethingAsynchronously(output->pp_array_output(),
-//                             callback.PP_CompletionCallback());
+//                             callback.pp_completion_callback());
 //   ...
 namespace ppapi {
 namespace proxy {