blob: a9f1b58f6c3da6f7f9275733938d2db2f52fe0ea (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
// Copyright 2020 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.
#include "src/debug/wasm/gdb-server/gdb-server-thread.h"
#include "src/debug/wasm/gdb-server/gdb-server.h"
#include "src/debug/wasm/gdb-server/session.h"
namespace v8 {
namespace internal {
namespace wasm {
namespace gdb_server {
GdbServerThread::GdbServerThread(GdbServer* gdb_server)
: Thread(v8::base::Thread::Options("GdbServerThread")),
gdb_server_(gdb_server),
start_semaphore_(0) {}
bool GdbServerThread::StartAndInitialize() {
// Executed in the Isolate thread.
if (!Start()) {
return false;
}
// We need to make sure that {Stop} is never called before the thread has
// completely initialized {transport_} and {target_}. Otherwise there could be
// a race condition where in the main thread {Stop} might get called before
// the transport is created, and then in the GDBServer thread we may have time
// to setup the transport and block on accept() before the main thread blocks
// on joining the thread.
// The small performance hit caused by this Wait should be negligeable because
// this operation happensat most once per process and only when the
// --wasm-gdb-remote flag is set.
start_semaphore_.Wait();
return true;
}
void GdbServerThread::CleanupThread() {
// Executed in the GdbServer thread.
v8::base::MutexGuard guard(&mutex_);
target_ = nullptr;
transport_ = nullptr;
#if _WIN32
::WSACleanup();
#endif
}
void GdbServerThread::Run() {
// Executed in the GdbServer thread.
#ifdef _WIN32
// Initialize Winsock
WSADATA wsaData;
int iResult = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
TRACE_GDB_REMOTE("GdbServerThread::Run: WSAStartup failed\n");
return;
}
#endif
// If the default port is not available, try any port.
SocketBinding socket_binding = SocketBinding::Bind(FLAG_wasm_gdb_remote_port);
if (!socket_binding.IsValid()) {
socket_binding = SocketBinding::Bind(0);
}
if (!socket_binding.IsValid()) {
TRACE_GDB_REMOTE("GdbServerThread::Run: Failed to bind any TCP port\n");
return;
}
TRACE_GDB_REMOTE("gdb-remote(%d) : Connect GDB with 'target remote :%d\n",
__LINE__, socket_binding.GetBoundPort());
transport_ = socket_binding.CreateTransport();
target_ = std::make_unique<Target>(gdb_server_);
// Here we have completed the initialization, and the thread that called
// {StartAndInitialize} may resume execution.
start_semaphore_.Signal();
while (!target_->IsTerminated()) {
// Wait for incoming connections.
if (!transport_->AcceptConnection()) {
continue;
}
// Create a new session for this connection
Session session(transport_.get());
TRACE_GDB_REMOTE("GdbServerThread: Connected\n");
// Run this session for as long as it lasts
target_->Run(&session);
}
CleanupThread();
}
void GdbServerThread::Stop() {
// Executed in the Isolate thread.
// Synchronized, becauses {Stop} might be called while {Run} is still
// initializing {transport_} and {target_}. If this happens and the thread is
// blocked waiting for an incoming connection or GdbServer for incoming
// packets, it will unblocked when {transport_} is closed.
v8::base::MutexGuard guard(&mutex_);
if (target_) {
target_->Terminate();
}
if (transport_) {
transport_->Close();
}
}
} // namespace gdb_server
} // namespace wasm
} // namespace internal
} // namespace v8
|