Commit 8b7a288e authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Debugger message handler can be called from V8 thread.

The message handler function set through the debugger API is normally called in a different thread than the V8 thread where execution is stopped due to debugger event. This change adds an option to the API for specifying that the message handler should be called directly from the V8 thread. For an application like Chrome where thread dispatching is already in place this makes more sense.

Add an option to the message handler debugger API to process messages in the thread where V8 is running instead of posting it to a queue for processing on a additional thread.
Review URL: http://codereview.chromium.org/42643

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1627 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8e34544b
...@@ -131,7 +131,8 @@ class EXPORT Debug { ...@@ -131,7 +131,8 @@ class EXPORT Debug {
static void DebugBreak(); static void DebugBreak();
// Message based interface. The message protocol is JSON. // Message based interface. The message protocol is JSON.
static void SetMessageHandler(DebugMessageHandler handler, void* data = NULL); static void SetMessageHandler(DebugMessageHandler handler, void* data = NULL,
bool message_handler_thread = true);
static void SendCommand(const uint16_t* command, int length); static void SendCommand(const uint16_t* command, int length);
// Dispatch interface. // Dispatch interface.
......
...@@ -3074,9 +3074,10 @@ void Debug::DebugBreak() { ...@@ -3074,9 +3074,10 @@ void Debug::DebugBreak() {
} }
void Debug::SetMessageHandler(v8::DebugMessageHandler handler, void* data) { void Debug::SetMessageHandler(v8::DebugMessageHandler handler, void* data,
bool message_handler_thread) {
EnsureInitialized("v8::Debug::SetMessageHandler"); EnsureInitialized("v8::Debug::SetMessageHandler");
i::Debugger::SetMessageHandler(handler, data); i::Debugger::SetMessageHandler(handler, data, message_handler_thread);
} }
......
This diff is collapsed.
...@@ -396,6 +396,46 @@ class Debug { ...@@ -396,6 +396,46 @@ class Debug {
}; };
// A Queue of Vector<uint16_t> objects. A thread-safe version is
// LockingMessageQueue, based on this class.
class MessageQueue BASE_EMBEDDED {
public:
explicit MessageQueue(int size);
~MessageQueue();
bool IsEmpty() const { return start_ == end_; }
Vector<uint16_t> Get();
void Put(const Vector<uint16_t>& message);
void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
private:
// Doubles the size of the message queue, and copies the messages.
void Expand();
Vector<uint16_t>* messages_;
int start_;
int end_;
int size_; // The size of the queue buffer. Queue can hold size-1 messages.
};
// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t>
// messages. The message data is not managed by LockingMessageQueue.
// Pointers to the data are passed in and out. Implemented by adding a
// Mutex to MessageQueue. Includes logging of all puts and gets.
class LockingMessageQueue BASE_EMBEDDED {
public:
explicit LockingMessageQueue(int size);
~LockingMessageQueue();
bool IsEmpty() const;
Vector<uint16_t> Get();
void Put(const Vector<uint16_t>& message);
void Clear();
private:
MessageQueue queue_;
Mutex* lock_;
DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue);
};
class DebugMessageThread; class DebugMessageThread;
class Debugger { class Debugger {
...@@ -427,14 +467,33 @@ class Debugger { ...@@ -427,14 +467,33 @@ class Debugger {
static void ProcessDebugEvent(v8::DebugEvent event, static void ProcessDebugEvent(v8::DebugEvent event,
Handle<Object> event_data, Handle<Object> event_data,
bool auto_continue); bool auto_continue);
static void NotifyMessageHandler(v8::DebugEvent event,
Handle<Object> exec_state,
Handle<Object> event_data,
bool auto_continue);
static void SetEventListener(Handle<Object> callback, Handle<Object> data); static void SetEventListener(Handle<Object> callback, Handle<Object> data);
static void SetMessageHandler(v8::DebugMessageHandler handler, void* data); static void SetMessageHandler(v8::DebugMessageHandler handler, void* data,
bool message_handler_thread);
static void TearDown(); static void TearDown();
static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler, static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
void* data); void* data);
// Invoke the message handler function.
static void InvokeMessageHandler(Vector< uint16_t> message);
// Send a message to the message handler eiher through the message thread or
// directly.
static void SendMessage(Vector<uint16_t> message); static void SendMessage(Vector<uint16_t> message);
// Send the JSON message for a debug event.
static bool SendEventMessage(Handle<Object> event_data);
// Add a debugger command to the command queue.
static void ProcessCommand(Vector<const uint16_t> command); static void ProcessCommand(Vector<const uint16_t> command);
// Check whether there are commands in the command queue.
static bool HasCommands(); static bool HasCommands();
static void ProcessHostDispatch(void* dispatch); static void ProcessHostDispatch(void* dispatch);
static void UpdateActiveDebugger(); static void UpdateActiveDebugger();
static Handle<Object> Call(Handle<JSFunction> fun, static Handle<Object> Call(Handle<JSFunction> fun,
...@@ -477,95 +536,30 @@ class Debugger { ...@@ -477,95 +536,30 @@ class Debugger {
static DebuggerAgent* agent_; static DebuggerAgent* agent_;
friend class DebugMessageThread; static const int kQueueInitialSize = 4;
}; static LockingMessageQueue command_queue_;
static LockingMessageQueue message_queue_;
static Semaphore* command_received_; // Signaled for each command received.
// A Queue of Vector<uint16_t> objects. A thread-safe version is static Semaphore* message_received_; // Signalled for each message send.
// LockingMessageQueue, based on this class.
class MessageQueue BASE_EMBEDDED {
public:
explicit MessageQueue(int size);
~MessageQueue();
bool IsEmpty() const { return start_ == end_; }
Vector<uint16_t> Get();
void Put(const Vector<uint16_t>& message);
void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
private:
// Doubles the size of the message queue, and copies the messages.
void Expand();
Vector<uint16_t>* messages_;
int start_;
int end_;
int size_; // The size of the queue buffer. Queue can hold size-1 messages.
};
// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t> friend class DebugMessageThread;
// messages. The message data is not managed by LockingMessageQueue.
// Pointers to the data are passed in and out. Implemented by adding a
// Mutex to MessageQueue. Includes logging of all puts and gets.
class LockingMessageQueue BASE_EMBEDDED {
public:
explicit LockingMessageQueue(int size);
~LockingMessageQueue();
bool IsEmpty() const;
Vector<uint16_t> Get();
void Put(const Vector<uint16_t>& message);
void Clear();
private:
MessageQueue queue_;
Mutex* lock_;
DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue);
}; };
/* This class is the data for a running thread that serializes // Thread to read messages from the message queue and invoke the debug message
* event messages and command processing for the debugger. // handler in another thread as the V8 thread. This thread is started if the
* All uncommented methods are called only from this message thread. // registration of the debug message handler requested to be called in a thread
*/ // seperate from the V8 thread.
class DebugMessageThread: public Thread { class DebugMessageThread: public Thread {
public: public:
DebugMessageThread(); // Called from API thread. DebugMessageThread() : keep_running_(true) {}
virtual ~DebugMessageThread(); virtual ~DebugMessageThread() {}
// Called by V8 thread. Reports events from V8 VM.
// Also handles command processing in stopped state of V8,
// when host_running_ is false.
void DebugEvent(v8::DebugEvent,
Handle<Object> exec_state,
Handle<Object> event_data,
bool auto_continue);
// Puts event on the output queue. Called by V8.
// This is where V8 hands off
// processing of the event to the DebugMessageThread thread,
// which forwards it to the debug_message_handler set by the API.
void SendMessage(Vector<uint16_t> event_json);
// Formats an event into JSON, and calls SendMessage.
bool SetEventJSONFromEvent(Handle<Object> event_data);
// Puts a command coming from the public API on the queue. Called
// by the API client thread. This is where the API client hands off
// processing of the command to the DebugMessageThread thread.
void ProcessCommand(Vector<uint16_t> command);
void ProcessHostDispatch(void* dispatch);
void OnDebuggerInactive();
// Main function of DebugMessageThread thread. // Main function of DebugMessageThread thread.
void Run(); void Run();
// Check whether there are commands in the queue.
bool HasCommands() { return !command_queue_.IsEmpty(); }
void Stop(); void Stop();
bool host_running_; // Is the debugging host running or stopped?
Semaphore* command_received_; // Non-zero when command queue is non-empty.
Semaphore* message_received_; // Exactly equal to message queue length.
private: private:
bool TwoByteEqualsAscii(Vector<uint16_t> two_byte, const char* ascii);
static const int kQueueInitialSize = 4;
LockingMessageQueue command_queue_;
LockingMessageQueue message_queue_;
bool keep_running_; bool keep_running_;
DISALLOW_COPY_AND_ASSIGN(DebugMessageThread); DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment