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