From: pfeldman@chromium.org Date: Wed, 22 Apr 2009 14:16:50 +0000 (+0000) Subject: DevTools: Add support for eventless host message dispatching. X-Git-Tag: upstream/4.7.83~24261 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a3a0d643054258483763b5f0c82e4a1849a3dc62;p=platform%2Fupstream%2Fv8.git DevTools: Add support for eventless host message dispatching. Review URL: http://codereview.chromium.org/87026 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1773 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/include/v8-debug.h b/include/v8-debug.h index fc93d76dd..debeac15c 100644 --- a/include/v8-debug.h +++ b/include/v8-debug.h @@ -124,12 +124,8 @@ class EXPORT Debug { /** * Debug host dispatch callback function. - * - * \param dispatch the dispatch value - * \param data the data value passed when registering the dispatch handler */ - typedef void (*HostDispatchHandler)(ClientData* dispatch); - + typedef void (*HostDispatchHandler)(); // Set a C debug event listener. static bool SetDebugEventListener(EventCallback that, @@ -149,8 +145,8 @@ class EXPORT Debug { ClientData* client_data = NULL); // Dispatch interface. - static void SetHostDispatchHandler(HostDispatchHandler handler); - static void SendHostDispatch(ClientData* dispatch); + static void SetHostDispatchHandler(HostDispatchHandler handler, + int period = 100); /** * Run a JavaScript function in the debugger. diff --git a/src/api.cc b/src/api.cc index 7845525da..9b681260b 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3276,16 +3276,11 @@ void Debug::SendCommand(const uint16_t* command, int length, } -void Debug::SetHostDispatchHandler(HostDispatchHandler handler) { +void Debug::SetHostDispatchHandler(HostDispatchHandler handler, + int period) { EnsureInitialized("v8::Debug::SetHostDispatchHandler"); ENTER_V8; - i::Debugger::SetHostDispatchHandler(handler); -} - - -void Debug::SendHostDispatch(ClientData* dispatch) { - if (!i::V8::HasBeenSetup()) return; - i::Debugger::ProcessHostDispatch(dispatch); + i::Debugger::SetHostDispatchHandler(handler, period); } diff --git a/src/debug.cc b/src/debug.cc index da5952ba0..32a96a83a 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1424,6 +1424,7 @@ DebugMessageThread* Debugger::message_thread_ = NULL; v8::Debug::MessageHandler Debugger::message_handler_ = NULL; bool Debugger::message_handler_cleared_ = false; v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL; +int Debugger::host_dispatch_micros_ = 100 * 1000; DebuggerAgent* Debugger::agent_ = NULL; LockingMessageQueue Debugger::command_queue_(kQueueInitialSize); LockingMessageQueue Debugger::message_queue_(kQueueInitialSize); @@ -1827,7 +1828,17 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, // Process requests from the debugger. while (true) { // Wait for new command in the queue. - command_received_->Wait(); + if (Debugger::host_dispatch_handler_) { + // In case there is a host dispatch - do periodic dispatches. + if (!command_received_->Wait(host_dispatch_micros_)) { + // Timout expired, do the dispatch. + Debugger::host_dispatch_handler_(); + continue; + } + } else { + // In case there is no host dispatch - just wait. + command_received_->Wait(); + } // The debug command interrupt flag might have been set when the command was // added. @@ -1842,19 +1853,6 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, return; } - // Check if the command is a host dispatch. - if (command.IsHostDispatch()) { - if (Debugger::host_dispatch_handler_) { - Debugger::host_dispatch_handler_(command.client_data()); - // Delete the dispatch. - command.Dispose(); - } - if (auto_continue && !HasCommands()) { - return; - } - continue; - } - // Invoke JavaScript to process the debug request. v8::Local fun_name; v8::Local fun; @@ -1971,8 +1969,10 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler, } -void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler) { +void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, + int period) { host_dispatch_handler_ = handler; + host_dispatch_micros_ = period * 1000; } @@ -2067,19 +2067,6 @@ bool Debugger::HasCommands() { } -void Debugger::ProcessHostDispatch(v8::Debug::ClientData* dispatch) { - // Puts a host dispatch comming from the public API on the queue. - Logger::DebugTag("Put dispatch on command_queue."); - command_queue_.Put(Message::NewHostDispatch(dispatch)); - command_received_->Signal(); - - // Set the debug command break flag to have the host dispatch processed. - if (!Debug::InDebugger()) { - StackGuard::DebugCommand(); - } -} - - bool Debugger::IsDebuggerActive() { ScopedLock with(debugger_access_); @@ -2168,17 +2155,14 @@ void DebugMessageThread::Stop() { Message::Message() : text_(Vector::empty()), - client_data_(NULL), - is_host_dispatch_(false) { + client_data_(NULL) { } Message::Message(const Vector& text, - v8::Debug::ClientData* data, - bool is_host_dispatch) + v8::Debug::ClientData* data) : text_(text), - client_data_(data), - is_host_dispatch_(is_host_dispatch) { + client_data_(data) { } @@ -2193,19 +2177,9 @@ void Message::Dispose() { } -bool Message::IsHostDispatch() const { - return is_host_dispatch_; -} - - Message Message::NewCommand(const Vector& command, v8::Debug::ClientData* data) { - return Message(command.Clone(), data, false); -} - - -Message Message::NewHostDispatch(v8::Debug::ClientData* dispatch) { - return Message(Vector::empty(), dispatch, true); + return Message(command.Clone(), data); } @@ -2217,7 +2191,7 @@ Message Message::NewOutput(v8::Handle output, text = Vector::New(output->Length()); output->Write(text.start(), 0, output->Length()); } - return Message(text, data, false); + return Message(text, data); } diff --git a/src/debug.h b/src/debug.h index 45de9ffe8..ffd3da9b4 100644 --- a/src/debug.h +++ b/src/debug.h @@ -409,7 +409,6 @@ class Message { public: static Message NewCommand(const Vector& command, v8::Debug::ClientData* data); - static Message NewHostDispatch(v8::Debug::ClientData* dispatch); static Message NewOutput(v8::Handle output, v8::Debug::ClientData* data); static Message NewEmptyMessage(); @@ -418,17 +417,14 @@ class Message { // Deletes user data and disposes of the text. void Dispose(); - bool IsHostDispatch() const; Vector text() const { return text_; } v8::Debug::ClientData* client_data() const { return client_data_; } private: Message(const Vector& text, - v8::Debug::ClientData* data, - bool is_host_dispatch); + v8::Debug::ClientData* data); Vector text_; v8::Debug::ClientData* client_data_; - bool is_host_dispatch_; }; // A Queue of Vector objects. A thread-safe version is @@ -510,7 +506,8 @@ class Debugger { static void SetMessageHandler(v8::Debug::MessageHandler handler, bool message_handler_thread); static void TearDown(); - static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler); + static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, + int period); // Invoke the message handler function. static void InvokeMessageHandler(Message message); @@ -529,7 +526,6 @@ class Debugger { // Check whether there are commands in the command queue. static bool HasCommands(); - static void ProcessHostDispatch(v8::Debug::ClientData* dispatch); static Handle Call(Handle fun, Handle data, bool* pending_exception); @@ -576,6 +572,7 @@ class Debugger { static v8::Debug::MessageHandler message_handler_; static bool message_handler_cleared_; // Was message handler cleared? static v8::Debug::HostDispatchHandler host_dispatch_handler_; + static int host_dispatch_micros_; static DebuggerAgent* agent_; diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index bfbd54bd2..fea07c564 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -3564,13 +3564,17 @@ TEST(MessageQueueExpandAndDestroy) { new TestClientData())); queue.Put(Message::NewCommand(Vector::empty(), new TestClientData())); - queue.Put(Message::NewHostDispatch(new TestClientData())); + queue.Put(Message::NewCommand(Vector::empty(), + new TestClientData())); ASSERT_EQ(0, TestClientData::destructor_call_counter); queue.Get().Dispose(); ASSERT_EQ(1, TestClientData::destructor_call_counter); - queue.Put(Message::NewHostDispatch(new TestClientData())); - queue.Put(Message::NewHostDispatch(new TestClientData())); - queue.Put(Message::NewHostDispatch(new TestClientData())); + queue.Put(Message::NewCommand(Vector::empty(), + new TestClientData())); + queue.Put(Message::NewCommand(Vector::empty(), + new TestClientData())); + queue.Put(Message::NewCommand(Vector::empty(), + new TestClientData())); queue.Put(Message::NewOutput(v8::Handle(), new TestClientData())); queue.Put(Message::NewEmptyMessage()); @@ -4219,53 +4223,107 @@ TEST(DebuggerClearMessageHandlerWhileActive) { } -int host_dispatch_hit_count = 0; -static void HostDispatchHandlerHitCount(v8::Debug::ClientData* dispatch) { - host_dispatch_hit_count++; +/* Test DebuggerHostDispatch */ +/* In this test, the debugger waits for a command on a breakpoint + * and is dispatching host commands while in the infinite loop. + */ + +class HostDispatchV8Thread : public v8::internal::Thread { + public: + void Run(); +}; + +class HostDispatchDebuggerThread : public v8::internal::Thread { + public: + void Run(); +}; + +Barriers* host_dispatch_barriers; + +static void HostDispatchMessageHandler(const uint16_t* message, + int length, + v8::Debug::ClientData* client_data) { + static char print_buffer[1000]; + Utf16ToAscii(message, length, print_buffer); + printf("%s\n", print_buffer); + fflush(stdout); +} + + +static void HostDispatchDispatchHandler() { + host_dispatch_barriers->semaphore_1->Signal(); } -// Test that clearing the debug event listener actually clears all break points -// and related information. -TEST(DebuggerHostDispatch) { - i::FLAG_debugger_auto_break = true; +void HostDispatchV8Thread::Run() { + const char* source_1 = "var y_global = 3;\n" + "function cat( new_value ) {\n" + " var x = new_value;\n" + " y_global = 4;\n" + " x = 3 * x + 1;\n" + " y_global = 5;\n" + " return x;\n" + "}\n" + "\n"; + const char* source_2 = "cat(17);\n"; v8::HandleScope scope; DebugLocalContext env; - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* command_continue = - "{\"seq\":0," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; + // Setup message and host dispatch handlers. + v8::Debug::SetMessageHandler(HostDispatchMessageHandler); + v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */); - // Create an empty function to call for processing debug commands - v8::Local empty = - CompileFunction(&env, "function empty(){}", "empty"); + CompileRun(source_1); + host_dispatch_barriers->barrier_1.Wait(); + host_dispatch_barriers->barrier_2.Wait(); + CompileRun(source_2); +} - // Setup message and host dispatch handlers. - v8::Debug::SetMessageHandler(DummyMessageHandler); - v8::Debug::SetHostDispatchHandler(HostDispatchHandlerHitCount); - // Send a host dispatch by itself. - v8::Debug::SendHostDispatch(NULL); - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. - CHECK_EQ(1, host_dispatch_hit_count); +void HostDispatchDebuggerThread::Run() { + const int kBufSize = 1000; + uint16_t buffer[kBufSize]; - // Fill a host dispatch and a continue command on the command queue. - v8::Debug::SendHostDispatch(NULL); - v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer)); - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. + const char* command_1 = "{\"seq\":101," + "\"type\":\"request\"," + "\"command\":\"setbreakpoint\"," + "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}"; + const char* command_2 = "{\"seq\":102," + "\"type\":\"request\"," + "\"command\":\"continue\"}"; - // Fill a continue command and a host dispatch on the command queue. - v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer)); - v8::Debug::SendHostDispatch(NULL); - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. - empty->Call(env->Global(), 0, NULL); // Run JavaScript to activate debugger. + // v8 thread initializes, runs source_1 + host_dispatch_barriers->barrier_1.Wait(); + // 1: Set breakpoint in cat(). + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer)); + + host_dispatch_barriers->barrier_2.Wait(); + // v8 thread starts compiling source_2. + // Break happens, to run queued commands and host dispatches. + // Wait for host dispatch to be processed. + host_dispatch_barriers->semaphore_1->Wait(); + // 2: Continue evaluation + v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer)); +} + +HostDispatchDebuggerThread host_dispatch_debugger_thread; +HostDispatchV8Thread host_dispatch_v8_thread; + + +TEST(DebuggerHostDispatch) { + i::FLAG_debugger_auto_break = true; + + // Create a V8 environment + Barriers stack_allocated_host_dispatch_barriers; + stack_allocated_host_dispatch_barriers.Initialize(); + host_dispatch_barriers = &stack_allocated_host_dispatch_barriers; + + host_dispatch_v8_thread.Start(); + host_dispatch_debugger_thread.Start(); - // All the host dispatch callback should be called. - CHECK_EQ(3, host_dispatch_hit_count); + host_dispatch_v8_thread.Join(); + host_dispatch_debugger_thread.Join(); }