Implement issue 549 Make V8 call DebugMessageDispatchHandler with Locker locked
authorpeter.rybin@gmail.com <peter.rybin@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Jan 2010 15:48:41 +0000 (15:48 +0000)
committerpeter.rybin@gmail.com <peter.rybin@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Jan 2010 15:48:41 +0000 (15:48 +0000)
Review URL: http://codereview.chromium.org/505025

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3634 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8-debug.h
src/api.cc
src/debug.cc
src/debug.h

index ff3182c..2e5fb3f 100644 (file)
@@ -224,9 +224,11 @@ class EXPORT Debug {
    * be processed. Note that debug messages will only be processed if there is
    * a V8 break. This can happen automatically by using the option
    * --debugger-auto-break.
+   * \param provide_locker requires that V8 acquires v8::Locker for you before
+   *        calling handler
    */
   static void SetDebugMessageDispatchHandler(
-      DebugMessageDispatchHandler handler);
+      DebugMessageDispatchHandler handler, bool provide_locker = false);
 
  /**
   * Run a JavaScript function in the debugger.
index 2546101..322c90f 100644 (file)
@@ -3669,7 +3669,6 @@ void Debug::SetMessageHandler(v8::Debug::MessageHandler handler,
 void Debug::SetMessageHandler2(v8::Debug::MessageHandler2 handler) {
   EnsureInitialized("v8::Debug::SetMessageHandler");
   ENTER_V8;
-  HandleScope scope;
   i::Debugger::SetMessageHandler(handler);
 }
 
@@ -3691,10 +3690,10 @@ void Debug::SetHostDispatchHandler(HostDispatchHandler handler,
 
 
 void Debug::SetDebugMessageDispatchHandler(
-    DebugMessageDispatchHandler handler) {
+    DebugMessageDispatchHandler handler, bool provide_locker) {
   EnsureInitialized("v8::Debug::SetDebugMessageDispatchHandler");
   ENTER_V8;
-  i::Debugger::SetDebugMessageDispatchHandler(handler);
+  i::Debugger::SetDebugMessageDispatchHandler(handler, provide_locker);
 }
 
 
index 9a02355..34b3a6d 100644 (file)
@@ -1761,8 +1761,10 @@ bool Debugger::never_unload_debugger_ = false;
 v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
 bool Debugger::debugger_unload_pending_ = false;
 v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
+Mutex* Debugger::dispatch_handler_access_ = OS::CreateMutex();
 v8::Debug::DebugMessageDispatchHandler
     Debugger::debug_message_dispatch_handler_ = NULL;
+MessageDispatchHelperThread* Debugger::message_dispatch_helper_thread_ = NULL;
 int Debugger::host_dispatch_micros_ = 100 * 1000;
 DebuggerAgent* Debugger::agent_ = NULL;
 LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
@@ -2399,8 +2401,14 @@ void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
 
 
 void Debugger::SetDebugMessageDispatchHandler(
-    v8::Debug::DebugMessageDispatchHandler handler) {
+    v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
+  ScopedLock with(dispatch_handler_access_);
   debug_message_dispatch_handler_ = handler;
+
+  if (provide_locker && message_dispatch_helper_thread_ == NULL) {
+    message_dispatch_helper_thread_ = new MessageDispatchHelperThread;
+    message_dispatch_helper_thread_->Start();
+  }
 }
 
 
@@ -2435,8 +2443,16 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command,
     StackGuard::DebugCommand();
   }
 
-  if (Debugger::debug_message_dispatch_handler_ != NULL) {
-    Debugger::debug_message_dispatch_handler_();
+  MessageDispatchHelperThread* dispatch_thread;
+  {
+    ScopedLock with(dispatch_handler_access_);
+    dispatch_thread = message_dispatch_helper_thread_;
+  }
+
+  if (dispatch_thread == NULL) {
+    CallMessageDispatchHandler();
+  } else {
+    dispatch_thread->Schedule();
   }
 }
 
@@ -2523,6 +2539,19 @@ void Debugger::WaitForAgent() {
     agent_->WaitUntilListening();
 }
 
+
+void Debugger::CallMessageDispatchHandler() {
+  v8::Debug::DebugMessageDispatchHandler handler;
+  {
+    ScopedLock with(dispatch_handler_access_);
+    handler = Debugger::debug_message_dispatch_handler_;
+  }
+  if (handler != NULL) {
+    handler();
+  }
+}
+
+
 MessageImpl MessageImpl::NewEvent(DebugEvent event,
                                   bool running,
                                   Handle<JSObject> exec_state,
@@ -2743,6 +2772,45 @@ void LockingCommandMessageQueue::Clear() {
   queue_.Clear();
 }
 
+
+MessageDispatchHelperThread::MessageDispatchHelperThread()
+    : sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
+      already_signalled_(false) {
+}
+
+
+MessageDispatchHelperThread::~MessageDispatchHelperThread() {
+  delete mutex_;
+  delete sem_;
+}
+
+
+void MessageDispatchHelperThread::Schedule() {
+  {
+    ScopedLock lock(mutex_);
+    if (already_signalled_) {
+      return;
+    }
+    already_signalled_ = true;
+  }
+  sem_->Signal();
+}
+
+
+void MessageDispatchHelperThread::Run() {
+  while (true) {
+    sem_->Wait();
+    {
+      ScopedLock lock(mutex_);
+      already_signalled_ = false;
+    }
+    {
+      Locker locker;
+      Debugger::CallMessageDispatchHandler();
+    }
+  }
+}
+
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
 } }  // namespace v8::internal
index fe9ff35..5ea2e52 100644 (file)
@@ -559,6 +559,9 @@ class CommandMessageQueue BASE_EMBEDDED {
 };
 
 
+class MessageDispatchHelperThread;
+
+
 // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage
 // messages.  The message data is not managed by LockingCommandMessageQueue.
 // Pointers to the data are passed in and out. Implemented by adding a
@@ -619,7 +622,8 @@ class Debugger {
   static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
                                      int period);
   static void SetDebugMessageDispatchHandler(
-      v8::Debug::DebugMessageDispatchHandler handler);
+      v8::Debug::DebugMessageDispatchHandler handler,
+      bool provide_locker);
 
   // Invoke the message handler function.
   static void InvokeMessageHandler(MessageImpl message);
@@ -645,6 +649,8 @@ class Debugger {
   // Blocks until the agent has started listening for connections
   static void WaitForAgent();
 
+  static void CallMessageDispatchHandler();
+
   // Unload the debugger if possible. Only called when no debugger is currently
   // active.
   static void UnloadDebugger();
@@ -683,7 +689,9 @@ class Debugger {
   static v8::Debug::MessageHandler2 message_handler_;
   static bool debugger_unload_pending_;  // Was message handler cleared?
   static v8::Debug::HostDispatchHandler host_dispatch_handler_;
+  static Mutex* dispatch_handler_access_;  // Mutex guarding dispatch handler.
   static v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_;
+  static MessageDispatchHelperThread* message_dispatch_helper_thread_;
   static int host_dispatch_micros_;
 
   static DebuggerAgent* agent_;
@@ -860,6 +868,27 @@ class Debug_Address {
   int reg_;
 };
 
+// The optional thread that Debug Agent may use to temporary call V8 to process
+// pending debug requests if debuggee is not running V8 at the moment.
+// Techincally it does not call V8 itself, rather it asks embedding program
+// to do this via v8::Debug::HostDispatchHandler
+class MessageDispatchHelperThread: public Thread {
+ public:
+  MessageDispatchHelperThread();
+  ~MessageDispatchHelperThread();
+
+  void Schedule();
+
+ private:
+  void Run();
+
+  Semaphore* const sem_;
+  Mutex* const mutex_;
+  bool already_signalled_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageDispatchHelperThread);
+};
+
 
 } }  // namespace v8::internal