Commit 33fba3bf authored by yangguo@chromium.org's avatar yangguo@chromium.org

Remove DebuggerAgent.

R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/279423004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21315 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c0ec7f20
......@@ -201,20 +201,6 @@ class V8_EXPORT Debug {
const uint16_t* command, int length,
ClientData* client_data = NULL);
/**
* Register a callback function to be called when a debug message has been
* received and is ready to be processed. For the debug messages to be
* processed V8 needs to be entered, and in certain embedding scenarios this
* callback can be used to make sure V8 is entered for the debug message to
* 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, bool provide_locker = false);
/**
* Run a JavaScript function in the debugger.
* \param fun the function to call
......@@ -241,22 +227,6 @@ class V8_EXPORT Debug {
*/
static Local<Value> GetMirror(v8::Handle<v8::Value> obj);
/**
* Enable the V8 builtin debug agent. The debugger agent will listen on the
* supplied TCP/IP port for remote debugger connection.
* \param name the name of the embedding application
* \param port the TCP/IP port to listen on
* \param wait_for_connection whether V8 should pause on a first statement
* allowing remote debugger to connect before anything interesting happened
*/
static bool EnableAgent(const char* name, int port,
bool wait_for_connection = false);
/**
* Disable the V8 builtin debug agent. The TCP/IP connection will be closed.
*/
static void DisableAgent();
/**
* Makes V8 process all pending debug messages.
*
......@@ -275,10 +245,6 @@ class V8_EXPORT Debug {
* until V8 gets control again; however, embedding application may improve
* this by manually calling this method.
*
* It makes sense to call this method whenever a new debug message arrived and
* V8 is not already running. Method v8::Debug::SetDebugMessageDispatchHandler
* should help with the former condition.
*
* Technically this method in many senses is equivalent to executing empty
* script:
* 1. It does nothing except for processing all pending debug messages.
......
......@@ -109,28 +109,6 @@ bool RunCppCycle(v8::Handle<v8::Script> script,
v8::Persistent<v8::Context> debug_message_context;
void DispatchDebugMessages() {
// We are in some random thread. We should already have v8::Locker acquired
// (we requested this when registered this callback). We was called
// because new debug messages arrived; they may have already been processed,
// but we shouldn't worry about this.
//
// All we have to do is to set context and call ProcessDebugMessages.
//
// We should decide which V8 context to use here. This is important for
// "evaluate" command, because it must be executed some context.
// In our sample we have only one context, so there is nothing really to
// think about.
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate, debug_message_context);
v8::Context::Scope scope(context);
v8::Debug::ProcessDebugMessages();
}
int RunMain(int argc, char* argv[]) {
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
v8::Isolate* isolate = v8::Isolate::New();
......@@ -142,10 +120,6 @@ int RunMain(int argc, char* argv[]) {
v8::Handle<v8::Value> script_name;
int script_param_counter = 0;
int port_number = -1;
bool wait_for_connection = false;
bool support_callback = false;
MainCycleType cycle_type = CycleInCpp;
for (int i = 1; i < argc; i++) {
......@@ -158,13 +132,6 @@ int RunMain(int argc, char* argv[]) {
cycle_type = CycleInCpp;
} else if (strcmp(str, "--main-cycle-in-js") == 0) {
cycle_type = CycleInJs;
} else if (strcmp(str, "--callback") == 0) {
support_callback = true;
} else if (strcmp(str, "--wait-for-connection") == 0) {
wait_for_connection = true;
} else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
port_number = atoi(argv[i + 1]); // NOLINT
i++;
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
......@@ -214,14 +181,6 @@ int RunMain(int argc, char* argv[]) {
debug_message_context.Reset(isolate, context);
if (support_callback) {
v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
}
if (port_number != -1) {
v8::Debug::EnableAgent("lineprocessor", port_number, wait_for_connection);
}
bool report_exceptions = true;
v8::Handle<v8::Script> script;
......
......@@ -6824,22 +6824,11 @@ void Debug::SendCommand(Isolate* isolate,
int length,
ClientData* client_data) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
internal_isolate->debugger()->ProcessCommand(
internal_isolate->debugger()->EnqueueCommandMessage(
i::Vector<const uint16_t>(command, length), client_data);
}
void Debug::SetDebugMessageDispatchHandler(
DebugMessageDispatchHandler handler, bool provide_locker) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate,
"v8::Debug::SetDebugMessageDispatchHandler");
ENTER_V8(isolate);
isolate->debugger()->SetDebugMessageDispatchHandler(
handler, provide_locker);
}
Local<Value> Debug::Call(v8::Handle<v8::Function> fun,
v8::Handle<v8::Value> data) {
i::Isolate* isolate = i::Isolate::Current();
......@@ -6891,17 +6880,6 @@ Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
}
bool Debug::EnableAgent(const char* name, int port, bool wait_for_connection) {
return i::Isolate::Current()->debugger()->StartAgent(name, port,
wait_for_connection);
}
void Debug::DisableAgent() {
return i::Isolate::Current()->debugger()->StopAgent();
}
void Debug::ProcessDebugMessages() {
i::Execution::ProcessDebugMessages(i::Isolate::Current(), true);
}
......
......@@ -4,27 +4,16 @@
#include "d8.h"
#include "d8-debug.h"
#include "debug-agent.h"
#include "platform/socket.h"
namespace v8 {
static bool was_running = true;
void PrintPrompt(bool is_running) {
const char* prompt = is_running? "> " : "dbg> ";
was_running = is_running;
printf("%s", prompt);
fflush(stdout);
}
void PrintPrompt() {
PrintPrompt(was_running);
}
void HandleDebugEvent(const Debug::EventDetails& event_details) {
// TODO(svenpanne) There should be a way to retrieve this in the callback.
Isolate* isolate = Isolate::GetCurrent();
......@@ -140,208 +129,4 @@ void HandleDebugEvent(const Debug::EventDetails& event_details) {
}
}
void RunRemoteDebugger(Isolate* isolate, int port) {
RemoteDebugger debugger(isolate, port);
debugger.Run();
}
void RemoteDebugger::Run() {
bool ok;
// Connect to the debugger agent.
conn_ = new i::Socket;
static const int kPortStrSize = 6;
char port_str[kPortStrSize];
i::OS::SNPrintF(i::Vector<char>(port_str, kPortStrSize), "%d", port_);
ok = conn_->Connect("localhost", port_str);
if (!ok) {
printf("Unable to connect to debug agent %d\n", i::Socket::GetLastError());
return;
}
// Start the receiver thread.
ReceiverThread receiver(this);
receiver.Start();
// Start the keyboard thread.
KeyboardThread keyboard(this);
keyboard.Start();
PrintPrompt();
// Process events received from debugged VM and from the keyboard.
bool terminate = false;
while (!terminate) {
event_available_.Wait();
RemoteDebuggerEvent* event = GetEvent();
switch (event->type()) {
case RemoteDebuggerEvent::kMessage:
HandleMessageReceived(event->data());
break;
case RemoteDebuggerEvent::kKeyboard:
HandleKeyboardCommand(event->data());
break;
case RemoteDebuggerEvent::kDisconnect:
terminate = true;
break;
default:
UNREACHABLE();
}
delete event;
}
delete conn_;
conn_ = NULL;
// Wait for the receiver thread to end.
receiver.Join();
}
void RemoteDebugger::MessageReceived(i::SmartArrayPointer<char> message) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
AddEvent(event);
}
void RemoteDebugger::KeyboardCommand(i::SmartArrayPointer<char> command) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
AddEvent(event);
}
void RemoteDebugger::ConnectionClosed() {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
i::SmartArrayPointer<char>());
AddEvent(event);
}
void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
i::LockGuard<i::Mutex> lock_guard(&event_access_);
if (head_ == NULL) {
ASSERT(tail_ == NULL);
head_ = event;
tail_ = event;
} else {
ASSERT(tail_ != NULL);
tail_->set_next(event);
tail_ = event;
}
event_available_.Signal();
}
RemoteDebuggerEvent* RemoteDebugger::GetEvent() {
i::LockGuard<i::Mutex> lock_guard(&event_access_);
ASSERT(head_ != NULL);
RemoteDebuggerEvent* result = head_;
head_ = head_->next();
if (head_ == NULL) {
ASSERT(tail_ == result);
tail_ = NULL;
}
return result;
}
void RemoteDebugger::HandleMessageReceived(char* message) {
Locker lock(isolate_);
HandleScope scope(isolate_);
// Print the event details.
TryCatch try_catch;
Handle<Object> details = Shell::DebugMessageDetails(
isolate_, Handle<String>::Cast(String::NewFromUtf8(isolate_, message)));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate_, &try_catch);
PrintPrompt();
return;
}
String::Utf8Value str(details->Get(String::NewFromUtf8(isolate_, "text")));
if (str.length() == 0) {
// Empty string is used to signal not to process this event.
return;
}
if (*str != NULL) {
printf("%s\n", *str);
} else {
printf("???\n");
}
bool is_running = details->Get(String::NewFromUtf8(isolate_, "running"))
->ToBoolean()
->Value();
PrintPrompt(is_running);
}
void RemoteDebugger::HandleKeyboardCommand(char* command) {
Locker lock(isolate_);
HandleScope scope(isolate_);
// Convert the debugger command to a JSON debugger request.
TryCatch try_catch;
Handle<Value> request = Shell::DebugCommandToJSONRequest(
isolate_, String::NewFromUtf8(isolate_, command));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate_, &try_catch);
PrintPrompt();
return;
}
// If undefined is returned the command was handled internally and there is
// no JSON to send.
if (request->IsUndefined()) {
PrintPrompt();
return;
}
// Send the JSON debugger request.
i::DebuggerAgentUtil::SendMessage(conn_, Handle<String>::Cast(request));
}
void ReceiverThread::Run() {
// Receive the connect message (with empty body).
i::SmartArrayPointer<char> message =
i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
ASSERT(message.get() == NULL);
while (true) {
// Receive a message.
i::SmartArrayPointer<char> message =
i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
if (message.get() == NULL) {
remote_debugger_->ConnectionClosed();
return;
}
// Pass the message to the main thread.
remote_debugger_->MessageReceived(message);
}
}
void KeyboardThread::Run() {
static const int kBufferSize = 256;
while (true) {
// read keyboard input.
char command[kBufferSize];
char* str = fgets(command, kBufferSize, stdin);
if (str == NULL) {
break;
}
// Pass the keyboard command to the main thread.
remote_debugger_->KeyboardCommand(
i::SmartArrayPointer<char>(i::StrDup(command)));
}
}
} // namespace v8
......@@ -8,125 +8,12 @@
#include "d8.h"
#include "debug.h"
#include "platform/socket.h"
namespace v8 {
void HandleDebugEvent(const Debug::EventDetails& event_details);
// Start the remove debugger connecting to a V8 debugger agent on the specified
// port.
void RunRemoteDebugger(Isolate* isolate, int port);
// Forward declerations.
class RemoteDebuggerEvent;
class ReceiverThread;
// Remote debugging class.
class RemoteDebugger {
public:
explicit RemoteDebugger(Isolate* isolate, int port)
: isolate_(isolate),
port_(port),
event_available_(0),
head_(NULL), tail_(NULL) {}
void Run();
// Handle events from the subordinate threads.
void MessageReceived(i::SmartArrayPointer<char> message);
void KeyboardCommand(i::SmartArrayPointer<char> command);
void ConnectionClosed();
private:
// Add new debugger event to the list.
void AddEvent(RemoteDebuggerEvent* event);
// Read next debugger event from the list.
RemoteDebuggerEvent* GetEvent();
// Handle a message from the debugged V8.
void HandleMessageReceived(char* message);
// Handle a keyboard command.
void HandleKeyboardCommand(char* command);
// Get connection to agent in debugged V8.
i::Socket* conn() { return conn_; }
Isolate* isolate_;
int port_; // Port used to connect to debugger V8.
i::Socket* conn_; // Connection to debugger agent in debugged V8.
// Linked list of events from debugged V8 and from keyboard input. Access to
// the list is guarded by a mutex and a semaphore signals new items in the
// list.
i::Mutex event_access_;
i::Semaphore event_available_;
RemoteDebuggerEvent* head_;
RemoteDebuggerEvent* tail_;
friend class ReceiverThread;
};
// Thread reading from debugged V8 instance.
class ReceiverThread: public i::Thread {
public:
explicit ReceiverThread(RemoteDebugger* remote_debugger)
: Thread("d8:ReceiverThrd"),
remote_debugger_(remote_debugger) {}
~ReceiverThread() {}
void Run();
private:
RemoteDebugger* remote_debugger_;
};
// Thread reading keyboard input.
class KeyboardThread: public i::Thread {
public:
explicit KeyboardThread(RemoteDebugger* remote_debugger)
: Thread("d8:KeyboardThrd"),
remote_debugger_(remote_debugger) {}
~KeyboardThread() {}
void Run();
private:
RemoteDebugger* remote_debugger_;
};
// Events processed by the main deubgger thread.
class RemoteDebuggerEvent {
public:
RemoteDebuggerEvent(int type, i::SmartArrayPointer<char> data)
: type_(type), data_(data), next_(NULL) {
ASSERT(type == kMessage || type == kKeyboard || type == kDisconnect);
}
static const int kMessage = 1;
static const int kKeyboard = 2;
static const int kDisconnect = 3;
int type() { return type_; }
char* data() { return data_.get(); }
private:
void set_next(RemoteDebuggerEvent* event) { next_ = event; }
RemoteDebuggerEvent* next() { return next_; }
int type_;
i::SmartArrayPointer<char> data_;
RemoteDebuggerEvent* next_;
friend class RemoteDebugger;
};
} // namespace v8
......
......@@ -83,7 +83,7 @@ bool ReadLineEditor::Close() {
Handle<String> ReadLineEditor::Prompt(const char* prompt) {
char* result = NULL;
{ // Release lock for blocking input.
Unlocker unlock(Isolate::GetCurrent());
Unlocker unlock(isolate_);
result = readline(prompt);
}
if (result == NULL) return Handle<String>();
......
......@@ -638,16 +638,6 @@ Local<Value> Shell::DebugCommandToJSONRequest(Isolate* isolate,
}
void Shell::DispatchDebugMessages() {
Isolate* isolate = v8::Isolate::GetCurrent();
HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate, Shell::evaluation_context_);
v8::Context::Scope context_scope(context);
v8::Debug::ProcessDebugMessages();
}
int32_t* Counter::Bind(const char* name, bool is_histogram) {
int i;
for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
......@@ -796,9 +786,7 @@ void Shell::InstallUtilityScript(Isolate* isolate) {
script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
// Start the in-process debugger if requested.
if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
v8::Debug::SetDebugEventListener(HandleDebugEvent);
}
if (i::FLAG_debugger) v8::Debug::SetDebugEventListener(HandleDebugEvent);
}
#endif // !V8_SHARED
......@@ -920,12 +908,6 @@ void Shell::InitializeDebugger(Isolate* isolate) {
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
utility_context_.Reset(isolate,
Context::New(isolate, NULL, global_template));
// Start the debugger agent if requested.
if (i::FLAG_debugger_agent) {
v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
}
#endif // !V8_SHARED
}
......@@ -1552,19 +1534,8 @@ int Shell::Main(int argc, char* argv[]) {
result = RunMain(isolate, argc, argv);
}
#ifndef V8_SHARED
// Run remote debugger if requested, but never on --test
if (i::FLAG_remote_debugger && !options.test_shell) {
InstallUtilityScript(isolate);
RunRemoteDebugger(isolate, i::FLAG_debugger_port);
return 0;
}
#endif // !V8_SHARED
// Run interactive shell if explicitly requested or if no script has been
// executed, but never on --test
if (( options.interactive_shell || !options.script_executed )
&& !options.test_shell ) {
#ifndef V8_SHARED
......
......@@ -265,7 +265,6 @@ class Shell : public i::AllStatic {
Handle<String> message);
static Local<Value> DebugCommandToJSONRequest(Isolate* isolate,
Handle<String> command);
static void DispatchDebugMessages();
static void PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args);
#endif // !V8_SHARED
......
This diff is collapsed.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_DEBUG_AGENT_H_
#define V8_DEBUG_AGENT_H_
#include "../include/v8-debug.h"
#include "platform.h"
namespace v8 {
namespace internal {
// Forward decelrations.
class DebuggerAgentSession;
class Socket;
// Debugger agent which starts a socket listener on the debugger port and
// handles connection from a remote debugger.
class DebuggerAgent: public Thread {
public:
DebuggerAgent(Isolate* isolate, const char* name, int port);
~DebuggerAgent();
void Shutdown();
void WaitUntilListening();
Isolate* isolate() { return isolate_; }
private:
void Run();
void CreateSession(Socket* socket);
void DebuggerMessage(const v8::Debug::Message& message);
void CloseSession();
void OnSessionClosed(DebuggerAgentSession* session);
Isolate* isolate_;
SmartArrayPointer<const char> name_; // Name of the embedding application.
int port_; // Port to use for the agent.
Socket* server_; // Server socket for listen/accept.
bool terminate_; // Termination flag.
RecursiveMutex session_access_; // Mutex guarding access to session_.
DebuggerAgentSession* session_; // Current active session if any.
Semaphore terminate_now_; // Semaphore to signal termination.
Semaphore listening_;
friend class DebuggerAgentSession;
friend void DebuggerAgentMessageHandler(const v8::Debug::Message& message);
DISALLOW_COPY_AND_ASSIGN(DebuggerAgent);
};
// Debugger agent session. The session receives requests from the remote
// debugger and sends debugger events/responses to the remote debugger.
class DebuggerAgentSession: public Thread {
public:
DebuggerAgentSession(DebuggerAgent* agent, Socket* client)
: Thread("v8:DbgAgntSessn"),
agent_(agent), client_(client) {}
~DebuggerAgentSession();
void DebuggerMessage(Vector<uint16_t> message);
void Shutdown();
private:
void Run();
void DebuggerMessage(Vector<char> message);
DebuggerAgent* agent_;
Socket* client_;
DISALLOW_COPY_AND_ASSIGN(DebuggerAgentSession);
};
// Utility methods factored out to be used by the D8 shell as well.
class DebuggerAgentUtil {
public:
static const char* const kContentLength;
static SmartArrayPointer<char> ReceiveMessage(Socket* conn);
static bool SendConnectMessage(Socket* conn, const char* embedding_host);
static bool SendMessage(Socket* conn, const Vector<uint16_t> message);
static bool SendMessage(Socket* conn, const v8::Handle<v8::String> message);
static int ReceiveAll(Socket* conn, char* data, int len);
};
} } // namespace v8::internal
#endif // V8_DEBUG_AGENT_H_
......@@ -2632,9 +2632,6 @@ Debugger::Debugger(Isolate* isolate)
never_unload_debugger_(false),
message_handler_(NULL),
debugger_unload_pending_(false),
debug_message_dispatch_handler_(NULL),
message_dispatch_helper_thread_(NULL),
agent_(NULL),
command_queue_(isolate->logger(), kQueueInitialSize),
command_received_(0),
event_command_queue_(isolate->logger(), kQueueInitialSize),
......@@ -3189,7 +3186,7 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) {
// Send an empty command to the debugger if in a break to make JavaScript
// run again if the debugger is closed.
if (isolate_->debug()->InDebugger()) {
ProcessCommand(Vector<const uint16_t>::empty());
EnqueueCommandMessage(Vector<const uint16_t>::empty());
}
}
}
......@@ -3211,18 +3208,6 @@ void Debugger::ListenersChanged() {
}
void Debugger::SetDebugMessageDispatchHandler(
v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
debug_message_dispatch_handler_ = handler;
if (provide_locker && message_dispatch_helper_thread_ == NULL) {
message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
message_dispatch_helper_thread_->Start();
}
}
// Calls the registered debug message handler. This callback is part of the
// public API.
void Debugger::InvokeMessageHandler(MessageImpl message) {
......@@ -3238,8 +3223,8 @@ void Debugger::InvokeMessageHandler(MessageImpl message) {
// a copy of the command string managed by the debugger. Up to this
// point, the command data was managed by the API client. Called
// by the API client thread.
void Debugger::ProcessCommand(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data) {
void Debugger::EnqueueCommandMessage(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data) {
// Need to cast away const.
CommandMessage message = CommandMessage::New(
Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
......@@ -3253,18 +3238,6 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command,
if (!isolate_->debug()->InDebugger()) {
isolate_->stack_guard()->RequestDebugCommand();
}
MessageDispatchHelperThread* dispatch_thread;
{
LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
dispatch_thread = message_dispatch_helper_thread_;
}
if (dispatch_thread == NULL) {
CallMessageDispatchHandler();
} else {
dispatch_thread->Schedule();
}
}
......@@ -3312,60 +3285,6 @@ MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun,
}
static void StubMessageHandler2(const v8::Debug::Message& message) {
// Simply ignore message.
}
bool Debugger::StartAgent(const char* name, int port,
bool wait_for_connection) {
if (wait_for_connection) {
// Suspend V8 if it is already running or set V8 to suspend whenever
// it starts.
// Provide stub message handler; V8 auto-continues each suspend
// when there is no message handler; we doesn't need it.
// Once become suspended, V8 will stay so indefinitely long, until remote
// debugger connects and issues "continue" command.
Debugger::message_handler_ = StubMessageHandler2;
v8::Debug::DebugBreak(reinterpret_cast<v8::Isolate*>(isolate_));
}
if (agent_ == NULL) {
agent_ = new DebuggerAgent(isolate_, name, port);
agent_->Start();
}
return true;
}
void Debugger::StopAgent() {
if (agent_ != NULL) {
agent_->Shutdown();
agent_->Join();
delete agent_;
agent_ = NULL;
}
}
void Debugger::WaitForAgent() {
if (agent_ != NULL)
agent_->WaitUntilListening();
}
void Debugger::CallMessageDispatchHandler() {
v8::Debug::DebugMessageDispatchHandler handler;
{
LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
handler = Debugger::debug_message_dispatch_handler_;
}
if (handler != NULL) {
handler();
}
}
EnterDebugger::EnterDebugger(Isolate* isolate)
: isolate_(isolate),
prev_(isolate_->debug()->debugger_entry()),
......@@ -3703,38 +3622,4 @@ void LockingCommandMessageQueue::Clear() {
queue_.Clear();
}
MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
: Thread("v8:MsgDispHelpr"),
isolate_(isolate), sem_(0),
already_signalled_(false) {
}
void MessageDispatchHelperThread::Schedule() {
{
LockGuard<Mutex> lock_guard(&mutex_);
if (already_signalled_) {
return;
}
already_signalled_ = true;
}
sem_.Signal();
}
void MessageDispatchHelperThread::Run() {
while (true) {
sem_.Wait();
{
LockGuard<Mutex> lock_guard(&mutex_);
already_signalled_ = false;
}
{
Locker locker(reinterpret_cast<v8::Isolate*>(isolate_));
isolate_->debugger()->CallMessageDispatchHandler();
}
}
}
} } // namespace v8::internal
......@@ -8,7 +8,6 @@
#include "allocation.h"
#include "arguments.h"
#include "assembler.h"
#include "debug-agent.h"
#include "execution.h"
#include "factory.h"
#include "flags.h"
......@@ -783,16 +782,10 @@ class Debugger {
bool auto_continue);
void SetEventListener(Handle<Object> callback, Handle<Object> data);
void SetMessageHandler(v8::Debug::MessageHandler handler);
void SetDebugMessageDispatchHandler(
v8::Debug::DebugMessageDispatchHandler handler,
bool provide_locker);
// Invoke the message handler function.
void InvokeMessageHandler(MessageImpl message);
// Add a debugger command to the command queue.
void ProcessCommand(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data = NULL);
void EnqueueCommandMessage(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data = NULL);
// Check whether there are commands in the command queue.
bool HasCommands();
......@@ -803,18 +796,6 @@ class Debugger {
MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun,
Handle<Object> data);
// Start the debugger agent listening on the provided port.
bool StartAgent(const char* name, int port,
bool wait_for_connection = false);
// Stop the debugger agent.
void StopAgent();
// Blocks until the agent has started listening for connections
void WaitForAgent();
void CallMessageDispatchHandler();
Handle<Context> GetDebugContext();
// Unload the debugger if possible. Only called when no debugger is currently
......@@ -882,6 +863,9 @@ class Debugger {
Handle<Object> event_data);
void ListenersChanged();
// Invoke the message handler function.
void InvokeMessageHandler(MessageImpl message);
RecursiveMutex debugger_access_; // Mutex guarding debugger variables.
Handle<Object> event_listener_; // Global handle to listener.
Handle<Object> event_listener_data_;
......@@ -892,12 +876,6 @@ class Debugger {
v8::Debug::MessageHandler message_handler_;
bool debugger_unload_pending_; // Was message handler cleared?
Mutex dispatch_handler_access_; // Mutex guarding dispatch handler.
v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_;
MessageDispatchHelperThread* message_dispatch_helper_thread_;
DebuggerAgent* agent_;
static const int kQueueInitialSize = 4;
LockingCommandMessageQueue command_queue_;
Semaphore command_received_; // Signaled for each command received.
......@@ -994,29 +972,6 @@ class Debug_Address {
Debug::AddressId id_;
};
// 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:
explicit MessageDispatchHelperThread(Isolate* isolate);
~MessageDispatchHelperThread() {}
void Schedule();
private:
void Run();
Isolate* isolate_;
Semaphore sem_;
Mutex mutex_;
bool already_signalled_;
DISALLOW_COPY_AND_ASSIGN(MessageDispatchHelperThread);
};
} } // namespace v8::internal
#endif // V8_DEBUG_H_
......@@ -714,6 +714,9 @@ void Execution::DebugBreakHelper(Isolate* isolate) {
void Execution::ProcessDebugMessages(Isolate* isolate,
bool debug_command_only) {
// Assert that we are on the main thread of the isolate.
ASSERT(ThreadId::Current().Equals(isolate->thread_id()));
isolate->stack_guard()->ClearDebugCommand();
StackLimitCheck check(isolate);
......
......@@ -660,10 +660,6 @@ DEFINE_bool(help, false, "Print usage message, including flags, on console")
DEFINE_bool(dump_counters, false, "Dump counters on exit")
DEFINE_bool(debugger, false, "Enable JavaScript debugger")
DEFINE_bool(remote_debugger, false, "Connect JavaScript debugger to the "
"debugger agent in another process")
DEFINE_bool(debugger_agent, false, "Enable debugger agent")
DEFINE_int(debugger_port, 5858, "Port to use for remote debugging")
DEFINE_string(map_counters, "", "Map counters to a file")
DEFINE_args(js_arguments,
......
......@@ -75,7 +75,6 @@ typedef void* ExternalReferenceRedirectorPointer();
class Debug;
class Debugger;
class DebuggerAgent;
#if !defined(__arm__) && V8_TARGET_ARCH_ARM || \
!defined(__aarch64__) && V8_TARGET_ARCH_ARM64 || \
......@@ -358,7 +357,6 @@ typedef List<HeapObject*> DebugObjectCache;
V(bool, fp_stubs_generated, false) \
V(int, max_available_threads, 0) \
V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \
V(DebuggerAgent*, debugger_agent_instance, NULL) \
V(InterruptCallback, api_interrupt_callback, NULL) \
V(void*, api_interrupt_callback_data, NULL) \
ISOLATE_INIT_SIMULATOR_LIST(V)
......
......@@ -5788,242 +5788,6 @@ TEST(DebuggerClearMessageHandlerWhileActive) {
}
/* Test DebugMessageDispatch */
/* In this test, the V8 thread waits for a message from the debug thread.
* The DebugMessageDispatchHandler is executed from the debugger thread
* which signals the V8 thread to wake up.
*/
class DebugMessageDispatchV8Thread : public v8::internal::Thread {
public:
DebugMessageDispatchV8Thread() : Thread("DebugMessageDispatchV8Thread") { }
void Run();
};
class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
public:
DebugMessageDispatchDebuggerThread()
: Thread("DebugMessageDispatchDebuggerThread") { }
void Run();
};
Barriers* debug_message_dispatch_barriers;
static void DebugMessageHandler() {
debug_message_dispatch_barriers->semaphore_1.Signal();
}
void DebugMessageDispatchV8Thread::Run() {
v8::Isolate::Scope isolate_scope(CcTest::isolate());
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
// Set up debug message dispatch handler.
v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
CompileRun("var y = 1 + 2;\n");
debug_message_dispatch_barriers->barrier_1.Wait();
debug_message_dispatch_barriers->semaphore_1.Wait();
debug_message_dispatch_barriers->barrier_2.Wait();
}
void DebugMessageDispatchDebuggerThread::Run() {
debug_message_dispatch_barriers->barrier_1.Wait();
SendContinueCommand();
debug_message_dispatch_barriers->barrier_2.Wait();
}
TEST(DebuggerDebugMessageDispatch) {
DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
// Create a V8 environment
Barriers stack_allocated_debug_message_dispatch_barriers;
debug_message_dispatch_barriers =
&stack_allocated_debug_message_dispatch_barriers;
debug_message_dispatch_v8_thread.Start();
debug_message_dispatch_debugger_thread.Start();
debug_message_dispatch_v8_thread.Join();
debug_message_dispatch_debugger_thread.Join();
}
TEST(DebuggerAgent) {
v8::V8::Initialize();
i::Debugger* debugger = CcTest::i_isolate()->debugger();
// Make sure these ports is not used by other tests to allow tests to run in
// parallel.
const int kPort1 = 5858 + FlagDependentPortOffset();
const int kPort2 = 5857 + FlagDependentPortOffset();
const int kPort3 = 5856 + FlagDependentPortOffset();
// Make a string with the port2 number.
const int kPortBufferLen = 6;
char port2_str[kPortBufferLen];
OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
bool ok;
// Test starting and stopping the agent without any client connection.
debugger->StartAgent("test", kPort1);
debugger->StopAgent();
// Test starting the agent, connecting a client and shutting down the agent
// with the client connected.
ok = debugger->StartAgent("test", kPort2);
CHECK(ok);
debugger->WaitForAgent();
i::Socket* client = new i::Socket;
ok = client->Connect("localhost", port2_str);
CHECK(ok);
// It is important to wait for a message from the agent. Otherwise,
// we can close the server socket during "accept" syscall, making it failing
// (at least on Linux), and the test will work incorrectly.
char buf;
ok = client->Receive(&buf, 1) == 1;
CHECK(ok);
debugger->StopAgent();
delete client;
// Test starting and stopping the agent with the required port already
// occoupied.
i::Socket* server = new i::Socket;
ok = server->Bind(kPort3);
CHECK(ok);
debugger->StartAgent("test", kPort3);
debugger->StopAgent();
delete server;
}
class DebuggerAgentProtocolServerThread : public i::Thread {
public:
explicit DebuggerAgentProtocolServerThread(int port)
: Thread("DebuggerAgentProtocolServerThread"),
port_(port),
server_(NULL),
client_(NULL),
listening_(0) {
}
~DebuggerAgentProtocolServerThread() {
// Close both sockets.
delete client_;
delete server_;
}
void Run();
void WaitForListening() { listening_.Wait(); }
char* body() { return body_.get(); }
private:
int port_;
i::SmartArrayPointer<char> body_;
i::Socket* server_; // Server socket used for bind/accept.
i::Socket* client_; // Single client connection used by the test.
i::Semaphore listening_; // Signalled when the server is in listen mode.
};
void DebuggerAgentProtocolServerThread::Run() {
bool ok;
// Create the server socket and bind it to the requested port.
server_ = new i::Socket;
CHECK(server_ != NULL);
ok = server_->Bind(port_);
CHECK(ok);
// Listen for new connections.
ok = server_->Listen(1);
CHECK(ok);
listening_.Signal();
// Accept a connection.
client_ = server_->Accept();
CHECK(client_ != NULL);
// Receive a debugger agent protocol message.
i::DebuggerAgentUtil::ReceiveMessage(client_);
}
TEST(DebuggerAgentProtocolOverflowHeader) {
// Make sure this port is not used by other tests to allow tests to run in
// parallel.
const int kPort = 5860 + FlagDependentPortOffset();
static const char* kLocalhost = "localhost";
// Make a string with the port number.
const int kPortBufferLen = 6;
char port_str[kPortBufferLen];
OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
// Create a socket server to receive a debugger agent message.
DebuggerAgentProtocolServerThread* server =
new DebuggerAgentProtocolServerThread(kPort);
server->Start();
server->WaitForListening();
// Connect.
i::Socket* client = new i::Socket;
CHECK(client != NULL);
bool ok = client->Connect(kLocalhost, port_str);
CHECK(ok);
// Send headers which overflow the receive buffer.
static const int kBufferSize = 1000;
char buffer[kBufferSize];
// Long key and short value: XXXX....XXXX:0\r\n.
for (int i = 0; i < kBufferSize - 4; i++) {
buffer[i] = 'X';
}
buffer[kBufferSize - 4] = ':';
buffer[kBufferSize - 3] = '0';
buffer[kBufferSize - 2] = '\r';
buffer[kBufferSize - 1] = '\n';
int result = client->Send(buffer, kBufferSize);
CHECK_EQ(kBufferSize, result);
// Short key and long value: X:XXXX....XXXX\r\n.
buffer[0] = 'X';
buffer[1] = ':';
for (int i = 2; i < kBufferSize - 2; i++) {
buffer[i] = 'X';
}
buffer[kBufferSize - 2] = '\r';
buffer[kBufferSize - 1] = '\n';
result = client->Send(buffer, kBufferSize);
CHECK_EQ(kBufferSize, result);
// Add empty body to request.
const char* content_length_zero_header = "Content-Length:0\r\n";
int length = StrLength(content_length_zero_header);
result = client->Send(content_length_zero_header, length);
CHECK_EQ(length, result);
result = client->Send("\r\n", 2);
CHECK_EQ(2, result);
// Wait until data is received.
server->Join();
// Check for empty body.
CHECK(server->body() == NULL);
// Close the client before the server to avoid TIME_WAIT issues.
client->Shutdown();
delete client;
delete server;
}
// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
// Make sure that DebugGetLoadedScripts doesn't return scripts
// with disposed external source.
......@@ -6783,7 +6547,7 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) {
static int counting_message_handler_counter;
static void CountingMessageHandler(const v8::Debug::Message& message) {
counting_message_handler_counter++;
if (message.IsResponse()) counting_message_handler_counter++;
}
......@@ -6830,6 +6594,83 @@ TEST(ProcessDebugMessages) {
}
class SendCommandThread : public v8::internal::Thread {
public:
explicit SendCommandThread(v8::Isolate* isolate)
: Thread("SendCommandThread"),
semaphore_(0),
isolate_(isolate) { }
static void ProcessDebugMessages(v8::Isolate* isolate, void* data) {
v8::Debug::ProcessDebugMessages();
reinterpret_cast<v8::internal::Semaphore*>(data)->Signal();
}
virtual void Run() {
semaphore_.Wait();
const int kBufferSize = 1000;
uint16_t buffer[kBufferSize];
const char* scripts_command =
"{\"seq\":0,"
"\"type\":\"request\","
"\"command\":\"scripts\"}";
int length = AsciiToUtf16(scripts_command, buffer);
// Send scripts command.
for (int i = 0; i < 100; i++) {
CHECK_EQ(i, counting_message_handler_counter);
// Queue debug message.
v8::Debug::SendCommand(isolate_, buffer, length);
// Synchronize with the main thread to force message processing.
isolate_->RequestInterrupt(ProcessDebugMessages, &semaphore_);
semaphore_.Wait();
}
v8::V8::TerminateExecution(isolate_);
}
void StartSending() {
semaphore_.Signal();
}
private:
v8::internal::Semaphore semaphore_;
v8::Isolate* isolate_;
};
static SendCommandThread* send_command_thread_ = NULL;
static void StartSendingCommands(
const v8::FunctionCallbackInfo<v8::Value>& info) {
send_command_thread_->StartSending();
}
TEST(ProcessDebugMessagesThreaded) {
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
counting_message_handler_counter = 0;
v8::Debug::SetMessageHandler2(CountingMessageHandler);
send_command_thread_ = new SendCommandThread(isolate);
send_command_thread_->Start();
v8::Handle<v8::FunctionTemplate> start =
v8::FunctionTemplate::New(isolate, StartSendingCommands);
env->Global()->Set(v8_str("start"), start->GetFunction());
CompileRun("start(); while (true) { }");
CHECK_EQ(100, counting_message_handler_counter);
v8::Debug::SetMessageHandler2(NULL);
CheckDebuggerUnloaded();
}
struct BacktraceData {
static int frame_counter;
static void MessageHandler(const v8::Debug::Message& message) {
......
......@@ -313,8 +313,6 @@
'../../src/dateparser-inl.h',
'../../src/dateparser.cc',
'../../src/dateparser.h',
'../../src/debug-agent.cc',
'../../src/debug-agent.h',
'../../src/debug.cc',
'../../src/debug.h',
'../../src/deoptimizer.cc',
......
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