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 9namespace v8 { 10namespace internal { 11namespace wasm { 12namespace gdb_server { 13 14GdbServerThread::GdbServerThread(GdbServer* gdb_server) 15 : Thread(v8::base::Thread::Options("GdbServerThread")), 16 gdb_server_(gdb_server), 17 start_semaphore_(0) {} 18 19bool 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 38void 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 50void 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 97void 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