mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
inspector: refactor to rename and comment methods
Pure refactor, makes no functional changes but the renaming helped me
see more clearly what the relationship was between methods and
variables.
* Renamed methods to reduce number of slightly different names for the
same thing ("thread" vs "io thread", etc.).
* Added comments where it was useful to me.
PR-URL: https://github.com/nodejs/node/pull/13321
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
1 parent
ce5745bf92
commit
26ab769940
11 files changed
+278
-213
No files matched your search
+62
-63
@@ -40,8 +40,8 @@ using v8_inspector::StringBuffer;
|
||||
using v8_inspector::StringView;
|
||||
using v8_inspector::V8Inspector;
|
||||
|
||||
static uv_sem_t inspector_io_thread_semaphore;
|
||||
static uv_async_t start_inspector_thread_async;
|
||||
static uv_sem_t start_io_thread_semaphore;
|
||||
static uv_async_t start_io_thread_async;
|
||||
|
||||
class StartIoTask : public v8::Task {
|
||||
public:
|
||||
@@ -61,36 +61,36 @@ std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
|
||||
return StringBuffer::create(StringView(*buffer, buffer.length()));
|
||||
}
|
||||
|
||||
// Called from the main thread.
|
||||
void StartInspectorIoThreadAsyncCallback(uv_async_t* handle) {
|
||||
// Called on the main thread.
|
||||
void StartIoThreadAsyncCallback(uv_async_t* handle) {
|
||||
static_cast<Agent*>(handle->data)->StartIoThread(false);
|
||||
}
|
||||
|
||||
void StartIoCallback(Isolate* isolate, void* agent) {
|
||||
void StartIoInterrupt(Isolate* isolate, void* agent) {
|
||||
static_cast<Agent*>(agent)->StartIoThread(false);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __POSIX__
|
||||
static void EnableInspectorIOThreadSignalHandler(int signo) {
|
||||
uv_sem_post(&inspector_io_thread_semaphore);
|
||||
static void StartIoThreadWakeup(int signo) {
|
||||
uv_sem_post(&start_io_thread_semaphore);
|
||||
}
|
||||
|
||||
inline void* InspectorIoThreadSignalThreadMain(void* unused) {
|
||||
inline void* StartIoThreadMain(void* unused) {
|
||||
for (;;) {
|
||||
uv_sem_wait(&inspector_io_thread_semaphore);
|
||||
Agent* agent = static_cast<Agent*>(start_inspector_thread_async.data);
|
||||
uv_sem_wait(&start_io_thread_semaphore);
|
||||
Agent* agent = static_cast<Agent*>(start_io_thread_async.data);
|
||||
if (agent != nullptr)
|
||||
agent->RequestIoStart();
|
||||
agent->RequestIoThreadStart();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int RegisterDebugSignalHandler() {
|
||||
static int StartDebugSignalHandler() {
|
||||
// Start a watchdog thread for calling v8::Debug::DebugBreak() because
|
||||
// it's not safe to call directly from the signal handler, it can
|
||||
// deadlock with the thread it interrupts.
|
||||
CHECK_EQ(0, uv_sem_init(&inspector_io_thread_semaphore, 0));
|
||||
CHECK_EQ(0, uv_sem_init(&start_io_thread_semaphore, 0));
|
||||
pthread_attr_t attr;
|
||||
CHECK_EQ(0, pthread_attr_init(&attr));
|
||||
// Don't shrink the thread's stack on FreeBSD. Said platform decided to
|
||||
@@ -101,11 +101,13 @@ static int RegisterDebugSignalHandler() {
|
||||
#endif // __FreeBSD__
|
||||
CHECK_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
|
||||
sigset_t sigmask;
|
||||
// Mask all signals.
|
||||
sigfillset(&sigmask);
|
||||
CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask));
|
||||
pthread_t thread;
|
||||
const int err = pthread_create(&thread, &attr,
|
||||
InspectorIoThreadSignalThreadMain, nullptr);
|
||||
StartIoThreadMain, nullptr);
|
||||
// Restore original mask
|
||||
CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr));
|
||||
CHECK_EQ(0, pthread_attr_destroy(&attr));
|
||||
if (err != 0) {
|
||||
@@ -115,7 +117,7 @@ static int RegisterDebugSignalHandler() {
|
||||
// receiving the signal would terminate the process.
|
||||
return -err;
|
||||
}
|
||||
RegisterSignalHandler(SIGUSR1, EnableInspectorIOThreadSignalHandler);
|
||||
RegisterSignalHandler(SIGUSR1, StartIoThreadWakeup);
|
||||
// Unblock SIGUSR1. A pending SIGUSR1 signal will now be delivered.
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGUSR1);
|
||||
@@ -126,10 +128,10 @@ static int RegisterDebugSignalHandler() {
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI EnableDebugThreadProc(void* arg) {
|
||||
Agent* agent = static_cast<Agent*>(start_inspector_thread_async.data);
|
||||
DWORD WINAPI StartIoThreadProc(void* arg) {
|
||||
Agent* agent = static_cast<Agent*>(start_io_thread_async.data);
|
||||
if (agent != nullptr)
|
||||
agent->RequestIoStart();
|
||||
agent->RequestIoThreadStart();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -138,7 +140,7 @@ static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf,
|
||||
return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
|
||||
}
|
||||
|
||||
static int RegisterDebugSignalHandler() {
|
||||
static int StartDebugSignalHandler() {
|
||||
wchar_t mapping_name[32];
|
||||
HANDLE mapping_handle;
|
||||
DWORD pid;
|
||||
@@ -173,7 +175,7 @@ static int RegisterDebugSignalHandler() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*handler = EnableDebugThreadProc;
|
||||
*handler = StartIoThreadProc;
|
||||
|
||||
UnmapViewOfFile(static_cast<void*>(handler));
|
||||
|
||||
@@ -205,7 +207,7 @@ class JsBindingsSessionDelegate : public InspectorSessionDelegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnMessage(const v8_inspector::StringView& message) override {
|
||||
void SendMessageToFrontend(const v8_inspector::StringView& message) override {
|
||||
Isolate* isolate = env_->isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
Context::Scope context_scope(env_->context());
|
||||
@@ -418,7 +420,7 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
|
||||
void flushProtocolNotifications() override { }
|
||||
|
||||
void sendMessageToFrontend(const StringView& message) {
|
||||
delegate_->OnMessage(message);
|
||||
delegate_->SendMessageToFrontend(message);
|
||||
}
|
||||
|
||||
InspectorSessionDelegate* const delegate_;
|
||||
@@ -434,7 +436,7 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
|
||||
platform_(platform),
|
||||
terminated_(false),
|
||||
running_nested_loop_(false) {
|
||||
inspector_ = V8Inspector::create(env->isolate(), this);
|
||||
client_ = V8Inspector::create(env->isolate(), this);
|
||||
}
|
||||
|
||||
void runMessageLoopOnPause(int context_group_id) override {
|
||||
@@ -459,11 +461,11 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
|
||||
std::unique_ptr<StringBuffer> name_buffer = Utf8ToStringView(name);
|
||||
v8_inspector::V8ContextInfo info(context, CONTEXT_GROUP_ID,
|
||||
name_buffer->string());
|
||||
inspector_->contextCreated(info);
|
||||
client_->contextCreated(info);
|
||||
}
|
||||
|
||||
void contextDestroyed(Local<Context> context) {
|
||||
inspector_->contextDestroyed(context);
|
||||
client_->contextDestroyed(context);
|
||||
}
|
||||
|
||||
void quitMessageLoopOnPause() override {
|
||||
@@ -473,7 +475,7 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
|
||||
void connectFrontend(InspectorSessionDelegate* delegate) {
|
||||
CHECK_EQ(channel_, nullptr);
|
||||
channel_ = std::unique_ptr<ChannelImpl>(
|
||||
new ChannelImpl(inspector_.get(), delegate));
|
||||
new ChannelImpl(client_.get(), delegate));
|
||||
}
|
||||
|
||||
void disconnectFrontend() {
|
||||
@@ -507,7 +509,7 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
|
||||
|
||||
Isolate* isolate = context->GetIsolate();
|
||||
|
||||
inspector_->exceptionThrown(
|
||||
client_->exceptionThrown(
|
||||
context,
|
||||
StringView(DETAILS, sizeof(DETAILS) - 1),
|
||||
error,
|
||||
@@ -515,7 +517,7 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
|
||||
ToProtocolString(isolate, message->GetScriptResourceName())->string(),
|
||||
message->GetLineNumber(context).FromMaybe(0),
|
||||
message->GetStartColumn(context).FromMaybe(0),
|
||||
inspector_->createStackTrace(stack_trace),
|
||||
client_->createStackTrace(stack_trace),
|
||||
script_id);
|
||||
}
|
||||
|
||||
@@ -528,12 +530,12 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
|
||||
v8::Platform* platform_;
|
||||
bool terminated_;
|
||||
bool running_nested_loop_;
|
||||
std::unique_ptr<V8Inspector> inspector_;
|
||||
std::unique_ptr<V8Inspector> client_;
|
||||
std::unique_ptr<ChannelImpl> channel_;
|
||||
};
|
||||
|
||||
Agent::Agent(Environment* env) : parent_env_(env),
|
||||
inspector_(nullptr),
|
||||
client_(nullptr),
|
||||
platform_(nullptr),
|
||||
enabled_(false) {}
|
||||
|
||||
@@ -546,18 +548,19 @@ bool Agent::Start(v8::Platform* platform, const char* path,
|
||||
const DebugOptions& options) {
|
||||
path_ = path == nullptr ? "" : path;
|
||||
debug_options_ = options;
|
||||
inspector_ =
|
||||
client_ =
|
||||
std::unique_ptr<NodeInspectorClient>(
|
||||
new NodeInspectorClient(parent_env_, platform));
|
||||
inspector_->contextCreated(parent_env_->context(), "Node.js Main Context");
|
||||
client_->contextCreated(parent_env_->context(), "Node.js Main Context");
|
||||
platform_ = platform;
|
||||
CHECK_EQ(0, uv_async_init(uv_default_loop(),
|
||||
&start_inspector_thread_async,
|
||||
StartInspectorIoThreadAsyncCallback));
|
||||
start_inspector_thread_async.data = this;
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(&start_inspector_thread_async));
|
||||
&start_io_thread_async,
|
||||
StartIoThreadAsyncCallback));
|
||||
start_io_thread_async.data = this;
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
|
||||
|
||||
RegisterDebugSignalHandler();
|
||||
// Ignore failure, SIGUSR1 won't work, but that should not block node start.
|
||||
StartDebugSignalHandler();
|
||||
if (options.inspector_enabled()) {
|
||||
return StartIoThread(options.wait_for_connect());
|
||||
}
|
||||
@@ -568,14 +571,14 @@ bool Agent::StartIoThread(bool wait_for_connect) {
|
||||
if (io_ != nullptr)
|
||||
return true;
|
||||
|
||||
CHECK_NE(inspector_, nullptr);
|
||||
CHECK_NE(client_, nullptr);
|
||||
|
||||
enabled_ = true;
|
||||
io_ = std::unique_ptr<InspectorIo>(
|
||||
new InspectorIo(parent_env_, platform_, path_, debug_options_,
|
||||
wait_for_connect));
|
||||
if (!io_->Start()) {
|
||||
inspector_.reset();
|
||||
client_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -612,20 +615,16 @@ void Agent::Stop() {
|
||||
|
||||
void Agent::Connect(InspectorSessionDelegate* delegate) {
|
||||
enabled_ = true;
|
||||
inspector_->connectFrontend(delegate);
|
||||
client_->connectFrontend(delegate);
|
||||
}
|
||||
|
||||
bool Agent::IsConnected() {
|
||||
return io_ && io_->IsConnected();
|
||||
}
|
||||
|
||||
bool Agent::IsStarted() {
|
||||
return !!inspector_;
|
||||
}
|
||||
|
||||
void Agent::WaitForDisconnect() {
|
||||
CHECK_NE(inspector_, nullptr);
|
||||
inspector_->contextDestroyed(parent_env_->context());
|
||||
CHECK_NE(client_, nullptr);
|
||||
client_->contextDestroyed(parent_env_->context());
|
||||
if (io_ != nullptr) {
|
||||
io_->WaitForDisconnect();
|
||||
}
|
||||
@@ -634,42 +633,42 @@ void Agent::WaitForDisconnect() {
|
||||
void Agent::FatalException(Local<Value> error, Local<v8::Message> message) {
|
||||
if (!IsStarted())
|
||||
return;
|
||||
inspector_->FatalException(error, message);
|
||||
client_->FatalException(error, message);
|
||||
WaitForDisconnect();
|
||||
}
|
||||
|
||||
void Agent::Dispatch(const StringView& message) {
|
||||
CHECK_NE(inspector_, nullptr);
|
||||
inspector_->dispatchMessageFromFrontend(message);
|
||||
CHECK_NE(client_, nullptr);
|
||||
client_->dispatchMessageFromFrontend(message);
|
||||
}
|
||||
|
||||
void Agent::Disconnect() {
|
||||
CHECK_NE(inspector_, nullptr);
|
||||
inspector_->disconnectFrontend();
|
||||
CHECK_NE(client_, nullptr);
|
||||
client_->disconnectFrontend();
|
||||
}
|
||||
|
||||
void Agent::RunMessageLoop() {
|
||||
CHECK_NE(inspector_, nullptr);
|
||||
inspector_->runMessageLoopOnPause(CONTEXT_GROUP_ID);
|
||||
CHECK_NE(client_, nullptr);
|
||||
client_->runMessageLoopOnPause(CONTEXT_GROUP_ID);
|
||||
}
|
||||
|
||||
InspectorSessionDelegate* Agent::delegate() {
|
||||
CHECK_NE(inspector_, nullptr);
|
||||
ChannelImpl* channel = inspector_->channel();
|
||||
CHECK_NE(client_, nullptr);
|
||||
ChannelImpl* channel = client_->channel();
|
||||
if (channel == nullptr)
|
||||
return nullptr;
|
||||
return channel->delegate();
|
||||
}
|
||||
|
||||
void Agent::PauseOnNextJavascriptStatement(const std::string& reason) {
|
||||
ChannelImpl* channel = inspector_->channel();
|
||||
ChannelImpl* channel = client_->channel();
|
||||
if (channel != nullptr)
|
||||
channel->schedulePauseOnNextStatement(reason);
|
||||
}
|
||||
|
||||
// static
|
||||
void Agent::InitJSBindings(Local<Object> target, Local<Value> unused,
|
||||
Local<Context> context, void* priv) {
|
||||
void Agent::InitInspector(Local<Object> target, Local<Value> unused,
|
||||
Local<Context> context, void* priv) {
|
||||
Environment* env = Environment::GetCurrent(context);
|
||||
Agent* agent = env->inspector_agent();
|
||||
env->SetMethod(target, "consoleCall", InspectorConsoleCall);
|
||||
@@ -678,19 +677,19 @@ void Agent::InitJSBindings(Local<Object> target, Local<Value> unused,
|
||||
env->SetMethod(target, "connect", ConnectJSBindingsSession);
|
||||
}
|
||||
|
||||
void Agent::RequestIoStart() {
|
||||
void Agent::RequestIoThreadStart() {
|
||||
// We need to attempt to interrupt V8 flow (in case Node is running
|
||||
// continuous JS code) and to wake up libuv thread (in case Node is wating
|
||||
// for IO events)
|
||||
uv_async_send(&start_inspector_thread_async);
|
||||
uv_async_send(&start_io_thread_async);
|
||||
v8::Isolate* isolate = parent_env_->isolate();
|
||||
platform_->CallOnForegroundThread(isolate, new StartIoTask(this));
|
||||
isolate->RequestInterrupt(StartIoCallback, this);
|
||||
uv_async_send(&start_inspector_thread_async);
|
||||
isolate->RequestInterrupt(StartIoInterrupt, this);
|
||||
uv_async_send(&start_io_thread_async);
|
||||
}
|
||||
|
||||
} // namespace inspector
|
||||
} // namespace node
|
||||
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector,
|
||||
node::inspector::Agent::InitJSBindings);
|
||||
node::inspector::Agent::InitInspector);
|
||||
+29
-14
@@ -39,7 +39,8 @@ class InspectorSessionDelegate {
|
||||
public:
|
||||
virtual ~InspectorSessionDelegate() = default;
|
||||
virtual bool WaitForFrontendMessage() = 0;
|
||||
virtual void OnMessage(const v8_inspector::StringView& message) = 0;
|
||||
virtual void SendMessageToFrontend(const v8_inspector::StringView& message)
|
||||
= 0;
|
||||
};
|
||||
|
||||
class InspectorIo;
|
||||
@@ -50,39 +51,53 @@ class Agent {
|
||||
explicit Agent(node::Environment* env);
|
||||
~Agent();
|
||||
|
||||
// Create client_, may create io_ if option enabled
|
||||
bool Start(v8::Platform* platform, const char* path,
|
||||
const DebugOptions& options);
|
||||
// Stop and destroy io_
|
||||
void Stop();
|
||||
|
||||
bool IsStarted();
|
||||
bool IsStarted() { return !!client_; }
|
||||
|
||||
// IO thread started, and client connected
|
||||
bool IsConnected();
|
||||
|
||||
|
||||
void WaitForDisconnect();
|
||||
void FatalException(v8::Local<v8::Value> error,
|
||||
v8::Local<v8::Message> message);
|
||||
|
||||
// These methods are called by the WS protocol and JS binding to create
|
||||
// inspector sessions. The inspector responds by using the delegate to send
|
||||
// messages back.
|
||||
void Connect(InspectorSessionDelegate* delegate);
|
||||
InspectorSessionDelegate* delegate();
|
||||
void Disconnect();
|
||||
void Dispatch(const v8_inspector::StringView& message);
|
||||
InspectorSessionDelegate* delegate();
|
||||
|
||||
void RunMessageLoop();
|
||||
bool enabled() {
|
||||
return enabled_;
|
||||
}
|
||||
bool enabled() { return enabled_; }
|
||||
void PauseOnNextJavascriptStatement(const std::string& reason);
|
||||
static void InitJSBindings(v8::Local<v8::Object> target,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv);
|
||||
|
||||
// Initialize 'inspector' module bindings
|
||||
static void InitInspector(v8::Local<v8::Object> target,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv);
|
||||
|
||||
bool StartIoThread(bool wait_for_connect);
|
||||
InspectorIo* io() {
|
||||
return io_.get();
|
||||
}
|
||||
// Can be called from any thread
|
||||
void RequestIoStart();
|
||||
|
||||
// Can only be called from the the main thread.
|
||||
bool StartIoThread(bool wait_for_connect);
|
||||
|
||||
// Calls StartIoThread() from off the main thread.
|
||||
void RequestIoThreadStart();
|
||||
|
||||
private:
|
||||
node::Environment* parent_env_;
|
||||
std::unique_ptr<NodeInspectorClient> inspector_;
|
||||
std::unique_ptr<NodeInspectorClient> client_;
|
||||
std::unique_ptr<InspectorIo> io_;
|
||||
v8::Platform* platform_;
|
||||
bool enabled_;
|
||||
|
||||
+63
-47
@@ -28,16 +28,32 @@ template<typename Transport>
|
||||
using TransportAndIo = std::pair<Transport*, InspectorIo*>;
|
||||
|
||||
std::string GetProcessTitle() {
|
||||
// uv_get_process_title will trim the title if it is too long.
|
||||
char title[2048];
|
||||
int err = uv_get_process_title(title, sizeof(title));
|
||||
if (err == 0) {
|
||||
return title;
|
||||
} else {
|
||||
// Title is too long, or could not be retrieved.
|
||||
return "Node.js";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ScriptPath(uv_loop_t* loop, const std::string& script_name) {
|
||||
std::string script_path;
|
||||
|
||||
if (!script_name.empty()) {
|
||||
uv_fs_t req;
|
||||
req.ptr = nullptr;
|
||||
if (0 == uv_fs_realpath(loop, &req, script_name.c_str(), nullptr)) {
|
||||
CHECK_NE(req.ptr, nullptr);
|
||||
script_path = std::string(static_cast<char*>(req.ptr));
|
||||
}
|
||||
uv_fs_req_cleanup(&req);
|
||||
}
|
||||
|
||||
return script_path;
|
||||
}
|
||||
|
||||
// UUID RFC: https://www.ietf.org/rfc/rfc4122.txt
|
||||
// Used ver 4 - with numbers
|
||||
std::string GenerateID() {
|
||||
@@ -97,6 +113,7 @@ int CloseAsyncAndLoop(uv_async_t* async) {
|
||||
return uv_loop_close(async->loop);
|
||||
}
|
||||
|
||||
// Delete main_thread_req_ on async handle close
|
||||
void ReleasePairOnAsyncClose(uv_handle_t* async) {
|
||||
AsyncAndAgent* pair = node::ContainerOf(&AsyncAndAgent::first,
|
||||
reinterpret_cast<uv_async_t*>(async));
|
||||
@@ -118,18 +135,25 @@ class IoSessionDelegate : public InspectorSessionDelegate {
|
||||
public:
|
||||
explicit IoSessionDelegate(InspectorIo* io) : io_(io) { }
|
||||
bool WaitForFrontendMessage() override;
|
||||
void OnMessage(const v8_inspector::StringView& message) override;
|
||||
void SendMessageToFrontend(const v8_inspector::StringView& message) override;
|
||||
private:
|
||||
InspectorIo* io_;
|
||||
};
|
||||
|
||||
// Passed to InspectorSocketServer to handle WS inspector protocol events,
|
||||
// mostly session start, message received, and session end.
|
||||
class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
|
||||
public:
|
||||
InspectorIoDelegate(InspectorIo* io, const std::string& script_path,
|
||||
const std::string& script_name, bool wait);
|
||||
// Calls PostIncomingMessage() with appropriate InspectorAction:
|
||||
// kStartSession
|
||||
bool StartSession(int session_id, const std::string& target_id) override;
|
||||
// kSendMessage
|
||||
void MessageReceived(int session_id, const std::string& message) override;
|
||||
// kEndSession
|
||||
void EndSession(int session_id) override;
|
||||
|
||||
std::vector<std::string> GetTargetIds() override;
|
||||
std::string GetTargetTitle(const std::string& id) override;
|
||||
std::string GetTargetUrl(const std::string& id) override;
|
||||
@@ -137,6 +161,7 @@ class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
|
||||
void ServerDone() override {
|
||||
io_->ServerDone();
|
||||
}
|
||||
|
||||
private:
|
||||
InspectorIo* io_;
|
||||
bool connected_;
|
||||
@@ -172,27 +197,27 @@ InspectorIo::InspectorIo(Environment* env, v8::Platform* platform,
|
||||
bool wait_for_connect)
|
||||
: options_(options), thread_(), delegate_(nullptr),
|
||||
state_(State::kNew), parent_env_(env),
|
||||
io_thread_req_(), platform_(platform),
|
||||
thread_req_(), platform_(platform),
|
||||
dispatching_messages_(false), session_id_(0),
|
||||
script_name_(path),
|
||||
wait_for_connect_(wait_for_connect), port_(-1) {
|
||||
main_thread_req_ = new AsyncAndAgent({uv_async_t(), env->inspector_agent()});
|
||||
CHECK_EQ(0, uv_async_init(env->event_loop(), &main_thread_req_->first,
|
||||
InspectorIo::MainThreadAsyncCb));
|
||||
InspectorIo::MainThreadReqAsyncCb));
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(&main_thread_req_->first));
|
||||
CHECK_EQ(0, uv_sem_init(&start_sem_, 0));
|
||||
CHECK_EQ(0, uv_sem_init(&thread_start_sem_, 0));
|
||||
}
|
||||
|
||||
InspectorIo::~InspectorIo() {
|
||||
uv_sem_destroy(&start_sem_);
|
||||
uv_sem_destroy(&thread_start_sem_);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&main_thread_req_->first),
|
||||
ReleasePairOnAsyncClose);
|
||||
}
|
||||
|
||||
bool InspectorIo::Start() {
|
||||
CHECK_EQ(state_, State::kNew);
|
||||
CHECK_EQ(uv_thread_create(&thread_, InspectorIo::ThreadCbIO, this), 0);
|
||||
uv_sem_wait(&start_sem_);
|
||||
CHECK_EQ(uv_thread_create(&thread_, InspectorIo::ThreadMain, this), 0);
|
||||
uv_sem_wait(&thread_start_sem_);
|
||||
|
||||
if (state_ == State::kError) {
|
||||
return false;
|
||||
@@ -234,76 +259,66 @@ void InspectorIo::WaitForDisconnect() {
|
||||
}
|
||||
|
||||
// static
|
||||
void InspectorIo::ThreadCbIO(void* io) {
|
||||
static_cast<InspectorIo*>(io)->WorkerRunIO<InspectorSocketServer>();
|
||||
void InspectorIo::ThreadMain(void* io) {
|
||||
static_cast<InspectorIo*>(io)->ThreadMain<InspectorSocketServer>();
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename Transport>
|
||||
void InspectorIo::WriteCbIO(uv_async_t* async) {
|
||||
TransportAndIo<Transport>* io_and_transport =
|
||||
void InspectorIo::IoThreadAsyncCb(uv_async_t* async) {
|
||||
TransportAndIo<Transport>* transport_and_io =
|
||||
static_cast<TransportAndIo<Transport>*>(async->data);
|
||||
if (io_and_transport == nullptr) {
|
||||
if (transport_and_io == nullptr) {
|
||||
return;
|
||||
}
|
||||
MessageQueue<TransportAction> outgoing_messages;
|
||||
InspectorIo* io = io_and_transport->second;
|
||||
io->SwapBehindLock(&io->outgoing_message_queue_, &outgoing_messages);
|
||||
for (const auto& outgoing : outgoing_messages) {
|
||||
Transport* transport = transport_and_io->first;
|
||||
InspectorIo* io = transport_and_io->second;
|
||||
MessageQueue<TransportAction> outgoing_message_queue;
|
||||
io->SwapBehindLock(&io->outgoing_message_queue_, &outgoing_message_queue);
|
||||
for (const auto& outgoing : outgoing_message_queue) {
|
||||
switch (std::get<0>(outgoing)) {
|
||||
case TransportAction::kKill:
|
||||
io_and_transport->first->TerminateConnections();
|
||||
transport->TerminateConnections();
|
||||
// Fallthrough
|
||||
case TransportAction::kStop:
|
||||
io_and_transport->first->Stop(nullptr);
|
||||
transport->Stop(nullptr);
|
||||
break;
|
||||
case TransportAction::kSendMessage:
|
||||
std::string message = StringViewToUtf8(std::get<2>(outgoing)->string());
|
||||
io_and_transport->first->Send(std::get<1>(outgoing), message);
|
||||
transport->Send(std::get<1>(outgoing), message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Transport>
|
||||
void InspectorIo::WorkerRunIO() {
|
||||
void InspectorIo::ThreadMain() {
|
||||
uv_loop_t loop;
|
||||
loop.data = nullptr;
|
||||
int err = uv_loop_init(&loop);
|
||||
CHECK_EQ(err, 0);
|
||||
io_thread_req_.data = nullptr;
|
||||
err = uv_async_init(&loop, &io_thread_req_, WriteCbIO<Transport>);
|
||||
thread_req_.data = nullptr;
|
||||
err = uv_async_init(&loop, &thread_req_, IoThreadAsyncCb<Transport>);
|
||||
CHECK_EQ(err, 0);
|
||||
std::string script_path;
|
||||
if (!script_name_.empty()) {
|
||||
uv_fs_t req;
|
||||
req.ptr = nullptr;
|
||||
if (0 == uv_fs_realpath(&loop, &req, script_name_.c_str(), nullptr)) {
|
||||
CHECK_NE(req.ptr, nullptr);
|
||||
script_path = std::string(static_cast<char*>(req.ptr));
|
||||
}
|
||||
uv_fs_req_cleanup(&req);
|
||||
}
|
||||
std::string script_path = ScriptPath(&loop, script_name_);
|
||||
InspectorIoDelegate delegate(this, script_path, script_name_,
|
||||
wait_for_connect_);
|
||||
delegate_ = &delegate;
|
||||
InspectorSocketServer server(&delegate,
|
||||
options_.host_name(),
|
||||
options_.port());
|
||||
Transport server(&delegate, &loop, options_.host_name(), options_.port());
|
||||
TransportAndIo<Transport> queue_transport(&server, this);
|
||||
io_thread_req_.data = &queue_transport;
|
||||
if (!server.Start(&loop)) {
|
||||
thread_req_.data = &queue_transport;
|
||||
if (!server.Start()) {
|
||||
state_ = State::kError; // Safe, main thread is waiting on semaphore
|
||||
CHECK_EQ(0, CloseAsyncAndLoop(&io_thread_req_));
|
||||
uv_sem_post(&start_sem_);
|
||||
CHECK_EQ(0, CloseAsyncAndLoop(&thread_req_));
|
||||
uv_sem_post(&thread_start_sem_);
|
||||
return;
|
||||
}
|
||||
port_ = server.port(); // Safe, main thread is waiting on semaphore.
|
||||
if (!wait_for_connect_) {
|
||||
uv_sem_post(&start_sem_);
|
||||
uv_sem_post(&thread_start_sem_);
|
||||
}
|
||||
uv_run(&loop, UV_RUN_DEFAULT);
|
||||
io_thread_req_.data = nullptr;
|
||||
thread_req_.data = nullptr;
|
||||
CHECK_EQ(uv_loop_close(&loop), 0);
|
||||
delegate_ = nullptr;
|
||||
}
|
||||
@@ -339,7 +354,7 @@ void InspectorIo::PostIncomingMessage(InspectorAction action, int session_id,
|
||||
NotifyMessageReceived();
|
||||
}
|
||||
|
||||
void InspectorIo::WaitForFrontendMessage() {
|
||||
void InspectorIo::WaitForIncomingMessage() {
|
||||
Mutex::ScopedLock scoped_lock(state_lock_);
|
||||
if (incoming_message_queue_.empty())
|
||||
incoming_message_cond_.Wait(scoped_lock);
|
||||
@@ -394,7 +409,7 @@ void InspectorIo::DispatchMessages() {
|
||||
}
|
||||
|
||||
// static
|
||||
void InspectorIo::MainThreadAsyncCb(uv_async_t* req) {
|
||||
void InspectorIo::MainThreadReqAsyncCb(uv_async_t* req) {
|
||||
AsyncAndAgent* pair = node::ContainerOf(&AsyncAndAgent::first, req);
|
||||
// Note that this may be called after io was closed or even after a new
|
||||
// one was created and ran.
|
||||
@@ -409,7 +424,7 @@ void InspectorIo::Write(TransportAction action, int session_id,
|
||||
return;
|
||||
AppendMessage(&outgoing_message_queue_, action, session_id,
|
||||
StringBuffer::create(inspector_message));
|
||||
int err = uv_async_send(&io_thread_req_);
|
||||
int err = uv_async_send(&thread_req_);
|
||||
CHECK_EQ(0, err);
|
||||
}
|
||||
|
||||
@@ -471,11 +486,12 @@ std::string InspectorIoDelegate::GetTargetUrl(const std::string& id) {
|
||||
}
|
||||
|
||||
bool IoSessionDelegate::WaitForFrontendMessage() {
|
||||
io_->WaitForFrontendMessage();
|
||||
io_->WaitForIncomingMessage();
|
||||
return true;
|
||||
}
|
||||
|
||||
void IoSessionDelegate::OnMessage(const v8_inspector::StringView& message) {
|
||||
void IoSessionDelegate::SendMessageToFrontend(
|
||||
const v8_inspector::StringView& message) {
|
||||
io_->Write(TransportAction::kSendMessage, io_->session_id_, message);
|
||||
}
|
||||
|
||||
|
||||
+39
-17
@@ -50,22 +50,25 @@ class InspectorIo {
|
||||
bool wait_for_connect);
|
||||
|
||||
~InspectorIo();
|
||||
// Start the inspector agent thread
|
||||
// Start the inspector agent thread, waiting for it to initialize,
|
||||
// and waiting as well for a connection if wait_for_connect.
|
||||
bool Start();
|
||||
// Stop the inspector agent
|
||||
// Stop the inspector agent thread.
|
||||
void Stop();
|
||||
|
||||
bool IsStarted();
|
||||
bool IsConnected();
|
||||
void WaitForDisconnect();
|
||||
|
||||
void WaitForDisconnect();
|
||||
// Called from thread to queue an incoming message and trigger
|
||||
// DispatchMessages() on the main thread.
|
||||
void PostIncomingMessage(InspectorAction action, int session_id,
|
||||
const std::string& message);
|
||||
void ResumeStartup() {
|
||||
uv_sem_post(&start_sem_);
|
||||
uv_sem_post(&thread_start_sem_);
|
||||
}
|
||||
void ServerDone() {
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&io_thread_req_), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&thread_req_), nullptr);
|
||||
}
|
||||
|
||||
int port() const { return port_; }
|
||||
@@ -84,46 +87,65 @@ class InspectorIo {
|
||||
kShutDown
|
||||
};
|
||||
|
||||
static void ThreadCbIO(void* agent);
|
||||
static void MainThreadAsyncCb(uv_async_t* req);
|
||||
// Callback for main_thread_req_'s uv_async_t
|
||||
static void MainThreadReqAsyncCb(uv_async_t* req);
|
||||
|
||||
// Wrapper for agent->ThreadMain()
|
||||
static void ThreadMain(void* agent);
|
||||
|
||||
// Runs a uv_loop_t
|
||||
template <typename Transport> void ThreadMain();
|
||||
// Called by ThreadMain's loop when triggered by thread_req_, writes
|
||||
// messages from outgoing_message_queue to the InspectorSockerServer
|
||||
template <typename Transport> static void IoThreadAsyncCb(uv_async_t* async);
|
||||
|
||||
template <typename Transport> static void WriteCbIO(uv_async_t* async);
|
||||
template <typename Transport> void WorkerRunIO();
|
||||
void SetConnected(bool connected);
|
||||
void DispatchMessages();
|
||||
// Write action to outgoing_message_queue, and wake the thread
|
||||
void Write(TransportAction action, int session_id,
|
||||
const v8_inspector::StringView& message);
|
||||
// Thread-safe append of message to a queue. Return true if the queue
|
||||
// used to be empty.
|
||||
template <typename ActionType>
|
||||
bool AppendMessage(MessageQueue<ActionType>* vector, ActionType action,
|
||||
int session_id,
|
||||
std::unique_ptr<v8_inspector::StringBuffer> buffer);
|
||||
// Used as equivalent of a thread-safe "pop" of an entire queue's content.
|
||||
template <typename ActionType>
|
||||
void SwapBehindLock(MessageQueue<ActionType>* vector1,
|
||||
MessageQueue<ActionType>* vector2);
|
||||
void WaitForFrontendMessage();
|
||||
// Wait on incoming_message_cond_
|
||||
void WaitForIncomingMessage();
|
||||
// Broadcast incoming_message_cond_
|
||||
void NotifyMessageReceived();
|
||||
bool StartThread(bool wait);
|
||||
|
||||
// Message queues
|
||||
ConditionVariable incoming_message_cond_;
|
||||
|
||||
const DebugOptions options_;
|
||||
uv_sem_t start_sem_;
|
||||
Mutex state_lock_;
|
||||
|
||||
// The IO thread runs its own uv_loop to implement the TCP server off
|
||||
// the main thread.
|
||||
uv_thread_t thread_;
|
||||
// Used by Start() to wait for thread to initialize, or for it to initialize
|
||||
// and receive a connection if wait_for_connect was requested.
|
||||
uv_sem_t thread_start_sem_;
|
||||
|
||||
InspectorIoDelegate* delegate_;
|
||||
State state_;
|
||||
node::Environment* parent_env_;
|
||||
|
||||
uv_async_t io_thread_req_;
|
||||
// Attached to the uv_loop in ThreadMain()
|
||||
uv_async_t thread_req_;
|
||||
// Note that this will live while the async is being closed - likely, past
|
||||
// the parent object lifespan
|
||||
std::pair<uv_async_t, Agent*>* main_thread_req_;
|
||||
std::unique_ptr<InspectorSessionDelegate> session_delegate_;
|
||||
v8::Platform* platform_;
|
||||
|
||||
// Message queues
|
||||
ConditionVariable incoming_message_cond_;
|
||||
Mutex state_lock_; // Locked before mutating either queue.
|
||||
MessageQueue<InspectorAction> incoming_message_queue_;
|
||||
MessageQueue<TransportAction> outgoing_message_queue_;
|
||||
|
||||
bool dispatching_messages_;
|
||||
int session_id_;
|
||||
|
||||
|
||||
+30
-30
@@ -68,7 +68,7 @@ static void dispose_inspector(uv_handle_t* handle) {
|
||||
}
|
||||
|
||||
static void close_connection(InspectorSocket* inspector) {
|
||||
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->client);
|
||||
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->tcp);
|
||||
if (!uv_is_closing(socket)) {
|
||||
uv_read_stop(reinterpret_cast<uv_stream_t*>(socket));
|
||||
uv_close(socket, dispose_inspector);
|
||||
@@ -107,7 +107,7 @@ static int write_to_client(InspectorSocket* inspector,
|
||||
|
||||
// Freed in write_request_cleanup
|
||||
WriteRequest* wr = new WriteRequest(inspector, msg, len);
|
||||
uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(&inspector->client);
|
||||
uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(&inspector->tcp);
|
||||
return uv_write(&wr->req, stream, &wr->buf, 1, write_cb) < 0;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ static void invoke_read_callback(InspectorSocket* inspector,
|
||||
int status, const uv_buf_t* buf) {
|
||||
if (inspector->ws_state->read_cb) {
|
||||
inspector->ws_state->read_cb(
|
||||
reinterpret_cast<uv_stream_t*>(&inspector->client), status, buf);
|
||||
reinterpret_cast<uv_stream_t*>(&inspector->tcp), status, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ static int parse_ws_frames(InspectorSocket* inspector) {
|
||||
uv_buf_t buffer;
|
||||
size_t len = output.size();
|
||||
inspector->ws_state->alloc_cb(
|
||||
reinterpret_cast<uv_handle_t*>(&inspector->client),
|
||||
reinterpret_cast<uv_handle_t*>(&inspector->tcp),
|
||||
len, &buffer);
|
||||
CHECK_GE(buffer.len, len);
|
||||
memcpy(buffer.base, &output[0], len);
|
||||
@@ -360,14 +360,14 @@ static void websockets_data_cb(uv_stream_t* stream, ssize_t nread,
|
||||
}
|
||||
|
||||
int inspector_read_start(InspectorSocket* inspector,
|
||||
uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
|
||||
uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
|
||||
ASSERT(inspector->ws_mode);
|
||||
ASSERT(!inspector->shutting_down || read_cb == nullptr);
|
||||
inspector->ws_state->close_sent = false;
|
||||
inspector->ws_state->alloc_cb = alloc_cb;
|
||||
inspector->ws_state->read_cb = read_cb;
|
||||
int err =
|
||||
uv_read_start(reinterpret_cast<uv_stream_t*>(&inspector->client),
|
||||
uv_read_start(reinterpret_cast<uv_stream_t*>(&inspector->tcp),
|
||||
prepare_buffer,
|
||||
websockets_data_cb);
|
||||
if (err < 0) {
|
||||
@@ -377,7 +377,7 @@ int inspector_read_start(InspectorSocket* inspector,
|
||||
}
|
||||
|
||||
void inspector_read_stop(InspectorSocket* inspector) {
|
||||
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->client));
|
||||
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->tcp));
|
||||
inspector->ws_state->alloc_cb = nullptr;
|
||||
inspector->ws_state->read_cb = nullptr;
|
||||
}
|
||||
@@ -426,7 +426,7 @@ static int path_cb(http_parser* parser, const char* at, size_t length) {
|
||||
}
|
||||
|
||||
static void handshake_complete(InspectorSocket* inspector) {
|
||||
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->client));
|
||||
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->tcp));
|
||||
handshake_cb callback = inspector->http_parsing_state->callback;
|
||||
inspector->ws_state = new ws_state_s();
|
||||
inspector->ws_mode = true;
|
||||
@@ -448,7 +448,7 @@ static void report_handshake_failure_cb(uv_handle_t* handle) {
|
||||
}
|
||||
|
||||
static void close_and_report_handshake_failure(InspectorSocket* inspector) {
|
||||
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->client);
|
||||
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->tcp);
|
||||
if (uv_is_closing(socket)) {
|
||||
report_handshake_failure_cb(socket);
|
||||
} else {
|
||||
@@ -474,7 +474,7 @@ static void handshake_failed(InspectorSocket* inspector) {
|
||||
}
|
||||
|
||||
// init_handshake references message_complete_cb
|
||||
static void init_handshake(InspectorSocket* inspector);
|
||||
static void init_handshake(InspectorSocket* socket);
|
||||
|
||||
static int message_complete_cb(http_parser* parser) {
|
||||
InspectorSocket* inspector = static_cast<InspectorSocket*>(parser->data);
|
||||
@@ -513,7 +513,7 @@ static int message_complete_cb(http_parser* parser) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void data_received_cb(uv_stream_s* client, ssize_t nread,
|
||||
static void data_received_cb(uv_stream_s* tcp, ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
#if DUMP_READS
|
||||
if (nread >= 0) {
|
||||
@@ -523,7 +523,7 @@ static void data_received_cb(uv_stream_s* client, ssize_t nread,
|
||||
printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, uv_err_name(nread));
|
||||
}
|
||||
#endif
|
||||
InspectorSocket* inspector = inspector_from_stream(client);
|
||||
InspectorSocket* inspector = inspector_from_stream(tcp);
|
||||
reclaim_uv_buf(inspector, buf, nread);
|
||||
if (nread < 0 || nread == UV_EOF) {
|
||||
close_and_report_handshake_failure(inspector);
|
||||
@@ -542,15 +542,15 @@ static void data_received_cb(uv_stream_s* client, ssize_t nread,
|
||||
}
|
||||
}
|
||||
|
||||
static void init_handshake(InspectorSocket* inspector) {
|
||||
http_parsing_state_s* state = inspector->http_parsing_state;
|
||||
static void init_handshake(InspectorSocket* socket) {
|
||||
http_parsing_state_s* state = socket->http_parsing_state;
|
||||
CHECK_NE(state, nullptr);
|
||||
state->current_header.clear();
|
||||
state->ws_key.clear();
|
||||
state->path.clear();
|
||||
state->done = false;
|
||||
http_parser_init(&state->parser, HTTP_REQUEST);
|
||||
state->parser.data = inspector;
|
||||
state->parser.data = socket;
|
||||
http_parser_settings* settings = &state->parser_settings;
|
||||
http_parser_settings_init(settings);
|
||||
settings->on_header_field = header_field_cb;
|
||||
@@ -559,26 +559,26 @@ static void init_handshake(InspectorSocket* inspector) {
|
||||
settings->on_url = path_cb;
|
||||
}
|
||||
|
||||
int inspector_accept(uv_stream_t* server, InspectorSocket* inspector,
|
||||
int inspector_accept(uv_stream_t* server, InspectorSocket* socket,
|
||||
handshake_cb callback) {
|
||||
ASSERT_NE(callback, nullptr);
|
||||
CHECK_EQ(inspector->http_parsing_state, nullptr);
|
||||
CHECK_EQ(socket->http_parsing_state, nullptr);
|
||||
|
||||
inspector->http_parsing_state = new http_parsing_state_s();
|
||||
uv_stream_t* client = reinterpret_cast<uv_stream_t*>(&inspector->client);
|
||||
int err = uv_tcp_init(server->loop, &inspector->client);
|
||||
socket->http_parsing_state = new http_parsing_state_s();
|
||||
uv_stream_t* tcp = reinterpret_cast<uv_stream_t*>(&socket->tcp);
|
||||
int err = uv_tcp_init(server->loop, &socket->tcp);
|
||||
|
||||
if (err == 0) {
|
||||
err = uv_accept(server, client);
|
||||
err = uv_accept(server, tcp);
|
||||
}
|
||||
if (err == 0) {
|
||||
init_handshake(inspector);
|
||||
inspector->http_parsing_state->callback = callback;
|
||||
err = uv_read_start(client, prepare_buffer,
|
||||
init_handshake(socket);
|
||||
socket->http_parsing_state->callback = callback;
|
||||
err = uv_read_start(tcp, prepare_buffer,
|
||||
data_received_cb);
|
||||
}
|
||||
if (err != 0) {
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(client), NULL);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(tcp), NULL);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -594,10 +594,10 @@ void inspector_write(InspectorSocket* inspector, const char* data,
|
||||
}
|
||||
|
||||
void inspector_close(InspectorSocket* inspector,
|
||||
inspector_cb callback) {
|
||||
inspector_cb callback) {
|
||||
// libuv throws assertions when closing stream that's already closed - we
|
||||
// need to do the same.
|
||||
ASSERT(!uv_is_closing(reinterpret_cast<uv_handle_t*>(&inspector->client)));
|
||||
ASSERT(!uv_is_closing(reinterpret_cast<uv_handle_t*>(&inspector->tcp)));
|
||||
ASSERT(!inspector->shutting_down);
|
||||
inspector->shutting_down = true;
|
||||
inspector->ws_state->close_cb = callback;
|
||||
@@ -612,9 +612,9 @@ void inspector_close(InspectorSocket* inspector,
|
||||
}
|
||||
|
||||
bool inspector_is_active(const InspectorSocket* inspector) {
|
||||
const uv_handle_t* client =
|
||||
reinterpret_cast<const uv_handle_t*>(&inspector->client);
|
||||
return !inspector->shutting_down && !uv_is_closing(client);
|
||||
const uv_handle_t* tcp =
|
||||
reinterpret_cast<const uv_handle_t*>(&inspector->tcp);
|
||||
return !inspector->shutting_down && !uv_is_closing(tcp);
|
||||
}
|
||||
|
||||
void InspectorSocket::reinit() {
|
||||
|
||||
@@ -48,6 +48,7 @@ struct ws_state_s {
|
||||
bool received_close;
|
||||
};
|
||||
|
||||
// HTTP Wrapper around a uv_tcp_t
|
||||
class InspectorSocket {
|
||||
public:
|
||||
InspectorSocket() : data(nullptr), http_parsing_state(nullptr),
|
||||
@@ -58,7 +59,7 @@ class InspectorSocket {
|
||||
struct http_parsing_state_s* http_parsing_state;
|
||||
struct ws_state_s* ws_state;
|
||||
std::vector<char> buffer;
|
||||
uv_tcp_t client;
|
||||
uv_tcp_t tcp;
|
||||
bool ws_mode;
|
||||
bool shutting_down;
|
||||
bool connection_eof;
|
||||
@@ -82,7 +83,7 @@ void inspector_write(InspectorSocket* inspector,
|
||||
bool inspector_is_active(const InspectorSocket* inspector);
|
||||
|
||||
inline InspectorSocket* inspector_from_stream(uv_tcp_t* stream) {
|
||||
return node::ContainerOf(&InspectorSocket::client, stream);
|
||||
return node::ContainerOf(&InspectorSocket::tcp, stream);
|
||||
}
|
||||
|
||||
inline InspectorSocket* inspector_from_stream(uv_stream_t* stream) {
|
||||
|
||||
@@ -230,9 +230,9 @@ class SocketSession {
|
||||
|
||||
private:
|
||||
enum class State { kHttp, kWebSocket, kClosing, kEOF, kDeclined };
|
||||
static void CloseCallback_(InspectorSocket* socket, int code);
|
||||
static void ReadCallback_(uv_stream_t* stream, ssize_t read,
|
||||
const uv_buf_t* buf);
|
||||
static void CloseCallback(InspectorSocket* socket, int code);
|
||||
static void ReadCallback(uv_stream_t* stream, ssize_t read,
|
||||
const uv_buf_t* buf);
|
||||
void OnRemoteDataIO(ssize_t read, const uv_buf_t* buf);
|
||||
const int id_;
|
||||
InspectorSocket socket_;
|
||||
@@ -242,9 +242,10 @@ class SocketSession {
|
||||
};
|
||||
|
||||
InspectorSocketServer::InspectorSocketServer(SocketServerDelegate* delegate,
|
||||
uv_loop_t* loop,
|
||||
const std::string& host,
|
||||
int port,
|
||||
FILE* out) : loop_(nullptr),
|
||||
FILE* out) : loop_(loop),
|
||||
delegate_(delegate),
|
||||
host_(host),
|
||||
port_(port),
|
||||
@@ -255,7 +256,6 @@ InspectorSocketServer::InspectorSocketServer(SocketServerDelegate* delegate,
|
||||
state_ = ServerState::kNew;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool InspectorSocketServer::HandshakeCallback(InspectorSocket* socket,
|
||||
inspector_handshake_event event,
|
||||
@@ -361,7 +361,7 @@ void InspectorSocketServer::SendListResponse(InspectorSocket* socket) {
|
||||
}
|
||||
if (!connected) {
|
||||
std::string host;
|
||||
GetSocketHost(&socket->client, &host);
|
||||
GetSocketHost(&socket->tcp, &host);
|
||||
std::string address = GetWsUrl(host, port_, id);
|
||||
std::ostringstream frontend_url;
|
||||
frontend_url << "chrome-devtools://devtools/bundled";
|
||||
@@ -374,9 +374,8 @@ void InspectorSocketServer::SendListResponse(InspectorSocket* socket) {
|
||||
SendHttpResponse(socket, MapsToString(response));
|
||||
}
|
||||
|
||||
bool InspectorSocketServer::Start(uv_loop_t* loop) {
|
||||
bool InspectorSocketServer::Start() {
|
||||
CHECK_EQ(state_, ServerState::kNew);
|
||||
loop_ = loop;
|
||||
sockaddr_in addr;
|
||||
uv_tcp_init(loop_, &server_);
|
||||
uv_ip4_addr(host_.c_str(), port_, &addr);
|
||||
@@ -470,11 +469,11 @@ SocketSession::SocketSession(InspectorSocketServer* server, int id)
|
||||
void SocketSession::Close() {
|
||||
CHECK_NE(state_, State::kClosing);
|
||||
state_ = State::kClosing;
|
||||
inspector_close(&socket_, CloseCallback_);
|
||||
inspector_close(&socket_, CloseCallback);
|
||||
}
|
||||
|
||||
// static
|
||||
void SocketSession::CloseCallback_(InspectorSocket* socket, int code) {
|
||||
void SocketSession::CloseCallback(InspectorSocket* socket, int code) {
|
||||
SocketSession* session = SocketSession::From(socket);
|
||||
CHECK_EQ(State::kClosing, session->state_);
|
||||
session->server_->SessionTerminated(session);
|
||||
@@ -483,12 +482,12 @@ void SocketSession::CloseCallback_(InspectorSocket* socket, int code) {
|
||||
void SocketSession::FrontendConnected() {
|
||||
CHECK_EQ(State::kHttp, state_);
|
||||
state_ = State::kWebSocket;
|
||||
inspector_read_start(&socket_, OnBufferAlloc, ReadCallback_);
|
||||
inspector_read_start(&socket_, OnBufferAlloc, ReadCallback);
|
||||
}
|
||||
|
||||
// static
|
||||
void SocketSession::ReadCallback_(uv_stream_t* stream, ssize_t read,
|
||||
const uv_buf_t* buf) {
|
||||
void SocketSession::ReadCallback(uv_stream_t* stream, ssize_t read,
|
||||
const uv_buf_t* buf) {
|
||||
InspectorSocket* socket = inspector_from_stream(stream);
|
||||
SocketSession::From(socket)->OnRemoteDataIO(read, buf);
|
||||
}
|
||||
|
||||
@@ -30,17 +30,30 @@ class SocketServerDelegate {
|
||||
virtual void ServerDone() = 0;
|
||||
};
|
||||
|
||||
// HTTP Server, writes messages requested as TransportActions, and responds
|
||||
// to HTTP requests and WS upgrades.
|
||||
|
||||
|
||||
|
||||
class InspectorSocketServer {
|
||||
public:
|
||||
using ServerCallback = void (*)(InspectorSocketServer*);
|
||||
InspectorSocketServer(SocketServerDelegate* delegate,
|
||||
uv_loop_t* loop,
|
||||
const std::string& host,
|
||||
int port,
|
||||
FILE* out = stderr);
|
||||
bool Start(uv_loop_t* loop);
|
||||
// Start listening on host/port
|
||||
bool Start();
|
||||
|
||||
// Called by the TransportAction sent with InspectorIo::Write():
|
||||
// kKill and kStop
|
||||
void Stop(ServerCallback callback);
|
||||
// kSendMessage
|
||||
void Send(int session_id, const std::string& message);
|
||||
// kKill
|
||||
void TerminateConnections();
|
||||
|
||||
int port() {
|
||||
return port_;
|
||||
}
|
||||
|
||||
+3
-3
@@ -4010,8 +4010,8 @@ static void ParseArgs(int* argc,
|
||||
}
|
||||
|
||||
|
||||
static void StartDebug(Environment* env, const char* path,
|
||||
DebugOptions debug_options) {
|
||||
static void StartInspector(Environment* env, const char* path,
|
||||
DebugOptions debug_options) {
|
||||
#if HAVE_INSPECTOR
|
||||
CHECK(!env->inspector_agent()->IsStarted());
|
||||
v8_platform.StartInspector(env, path, debug_options);
|
||||
@@ -4503,7 +4503,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
||||
env.Start(argc, argv, exec_argc, exec_argv, v8_is_profiling);
|
||||
|
||||
const char* path = argc > 1 ? argv[1] : nullptr;
|
||||
StartDebug(&env, path, debug_options);
|
||||
StartInspector(&env, path, debug_options);
|
||||
|
||||
if (debug_options.inspector_enabled() && !v8_platform.InspectorStarted(&env))
|
||||
return 12; // Signal internal error.
|
||||
|
||||
@@ -335,8 +335,8 @@ static void really_close(uv_handle_t* handle) {
|
||||
// Called when the test leaves inspector socket in active state
|
||||
static void manual_inspector_socket_cleanup() {
|
||||
EXPECT_EQ(0, uv_is_active(
|
||||
reinterpret_cast<uv_handle_t*>(&inspector.client)));
|
||||
really_close(reinterpret_cast<uv_handle_t*>(&inspector.client));
|
||||
reinterpret_cast<uv_handle_t*>(&inspector.tcp)));
|
||||
really_close(reinterpret_cast<uv_handle_t*>(&inspector.tcp));
|
||||
delete inspector.ws_state;
|
||||
inspector.ws_state = nullptr;
|
||||
delete inspector.http_parsing_state;
|
||||
@@ -346,7 +346,7 @@ static void manual_inspector_socket_cleanup() {
|
||||
|
||||
static void assert_both_sockets_closed() {
|
||||
SPIN_WHILE(uv_is_active(reinterpret_cast<uv_handle_t*>(&client_socket)));
|
||||
SPIN_WHILE(uv_is_active(reinterpret_cast<uv_handle_t*>(&inspector.client)));
|
||||
SPIN_WHILE(uv_is_active(reinterpret_cast<uv_handle_t*>(&inspector.tcp)));
|
||||
}
|
||||
|
||||
static void on_connection(uv_connect_t* connect, int status) {
|
||||
|
||||
@@ -306,9 +306,9 @@ class SocketWrapper {
|
||||
class ServerHolder {
|
||||
public:
|
||||
template <typename Delegate>
|
||||
ServerHolder(Delegate* delegate, int port, FILE* out = NULL)
|
||||
ServerHolder(Delegate* delegate, uv_loop_t* loop, int port, FILE* out = NULL)
|
||||
: closed(false), paused(false),
|
||||
server_(delegate, HOST, port, out) {
|
||||
server_(delegate, loop, HOST, port, out) {
|
||||
delegate->Connect(&server_);
|
||||
}
|
||||
|
||||
@@ -387,8 +387,8 @@ static const std::string WsHandshakeRequest(const std::string& target_id) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, InspectorSessions) {
|
||||
TestInspectorServerDelegate delegate;
|
||||
ServerHolder server(&delegate, 0);
|
||||
ASSERT_TRUE(server->Start(&loop));
|
||||
ServerHolder server(&delegate, &loop, 0);
|
||||
ASSERT_TRUE(server->Start());
|
||||
|
||||
SocketWrapper well_behaved_socket(&loop);
|
||||
// Regular connection
|
||||
@@ -474,8 +474,8 @@ TEST_F(InspectorSocketServerTest, InspectorSessions) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, ServerDoesNothing) {
|
||||
TestInspectorServerDelegate delegate;
|
||||
ServerHolder server(&delegate, 0);
|
||||
ASSERT_TRUE(server->Start(&loop));
|
||||
ServerHolder server(&delegate, &loop, 0);
|
||||
ASSERT_TRUE(server->Start());
|
||||
|
||||
server->Stop(ServerHolder::CloseCallback);
|
||||
server->TerminateConnections();
|
||||
@@ -485,8 +485,8 @@ TEST_F(InspectorSocketServerTest, ServerDoesNothing) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, ServerWithoutTargets) {
|
||||
ServerDelegateNoTargets delegate;
|
||||
ServerHolder server(&delegate, 0);
|
||||
ASSERT_TRUE(server->Start(&loop));
|
||||
ServerHolder server(&delegate, &loop, 0);
|
||||
ASSERT_TRUE(server->Start());
|
||||
TestHttpRequest(server.port(), "/json/list", "[ ]");
|
||||
TestHttpRequest(server.port(), "/json", "[ ]");
|
||||
|
||||
@@ -503,10 +503,10 @@ TEST_F(InspectorSocketServerTest, ServerWithoutTargets) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, ServerCannotStart) {
|
||||
ServerDelegateNoTargets delegate1, delegate2;
|
||||
ServerHolder server1(&delegate1, 0);
|
||||
ASSERT_TRUE(server1->Start(&loop));
|
||||
ServerHolder server2(&delegate2, server1.port());
|
||||
ASSERT_FALSE(server2->Start(&loop));
|
||||
ServerHolder server1(&delegate1, &loop, 0);
|
||||
ASSERT_TRUE(server1->Start());
|
||||
ServerHolder server2(&delegate2, &loop, server1.port());
|
||||
ASSERT_FALSE(server2->Start());
|
||||
server1->Stop(ServerHolder::CloseCallback);
|
||||
server1->TerminateConnections();
|
||||
SPIN_WHILE(!server1.closed);
|
||||
@@ -515,8 +515,8 @@ TEST_F(InspectorSocketServerTest, ServerCannotStart) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, StoppingServerDoesNotKillConnections) {
|
||||
ServerDelegateNoTargets delegate;
|
||||
ServerHolder server(&delegate, 0);
|
||||
ASSERT_TRUE(server->Start(&loop));
|
||||
ServerHolder server(&delegate, &loop, 0);
|
||||
ASSERT_TRUE(server->Start());
|
||||
SocketWrapper socket1(&loop);
|
||||
socket1.Connect(HOST, server.port());
|
||||
socket1.TestHttpRequest("/json/list", "[ ]");
|
||||
@@ -530,8 +530,8 @@ TEST_F(InspectorSocketServerTest, StoppingServerDoesNotKillConnections) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, ClosingConnectionReportsDone) {
|
||||
ServerDelegateNoTargets delegate;
|
||||
ServerHolder server(&delegate, 0);
|
||||
ASSERT_TRUE(server->Start(&loop));
|
||||
ServerHolder server(&delegate, &loop, 0);
|
||||
ASSERT_TRUE(server->Start());
|
||||
SocketWrapper socket1(&loop);
|
||||
socket1.Connect(HOST, server.port());
|
||||
socket1.TestHttpRequest("/json/list", "[ ]");
|
||||
@@ -545,8 +545,8 @@ TEST_F(InspectorSocketServerTest, ClosingConnectionReportsDone) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, ClosingSocketReportsDone) {
|
||||
TestInspectorServerDelegate delegate;
|
||||
ServerHolder server(&delegate, 0);
|
||||
ASSERT_TRUE(server->Start(&loop));
|
||||
ServerHolder server(&delegate, &loop, 0);
|
||||
ASSERT_TRUE(server->Start());
|
||||
SocketWrapper socket1(&loop);
|
||||
socket1.Connect(HOST, server.port());
|
||||
socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
|
||||
@@ -560,8 +560,8 @@ TEST_F(InspectorSocketServerTest, ClosingSocketReportsDone) {
|
||||
|
||||
TEST_F(InspectorSocketServerTest, TerminatingSessionReportsDone) {
|
||||
TestInspectorServerDelegate delegate;
|
||||
ServerHolder server(&delegate, 0);
|
||||
ASSERT_TRUE(server->Start(&loop));
|
||||
ServerHolder server(&delegate, &loop, 0);
|
||||
ASSERT_TRUE(server->Start());
|
||||
SocketWrapper socket1(&loop);
|
||||
socket1.Connect(HOST, server.port());
|
||||
socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
|
||||
|
||||
Reference in new issue
Block a user