-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[lldb-dap] Add command line option --connection-timeout
#156803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
9af1b00
c78a38f
13b1358
3e927b0
b185ae3
c2862d6
bf0df0b
c1ffd44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -223,6 +223,35 @@ static int DuplicateFileDescriptor(int fd) { | |
| #endif | ||
| } | ||
|
|
||
| static void | ||
| ResetConnectionTimeout(std::mutex &connection_timeout_mutex, | ||
| MainLoopBase::TimePoint &conncetion_timeout_time_point) { | ||
| std::scoped_lock<std::mutex> lock(connection_timeout_mutex); | ||
| conncetion_timeout_time_point = MainLoopBase::TimePoint(); | ||
| } | ||
|
|
||
| static void | ||
| TrackConnectionTimeout(MainLoop &loop, std::mutex &connection_timeout_mutex, | ||
| MainLoopBase::TimePoint &conncetion_timeout_time_point, | ||
| std::chrono::seconds ttl_seconds) { | ||
| MainLoopBase::TimePoint next_checkpoint = | ||
| std::chrono::steady_clock::now() + std::chrono::seconds(ttl_seconds); | ||
| { | ||
| std::scoped_lock<std::mutex> lock(connection_timeout_mutex); | ||
| // We don't need to take the max of `ttl_time_point` and `next_checkpoint`, | ||
| // because `next_checkpoint` must be the latest. | ||
| conncetion_timeout_time_point = next_checkpoint; | ||
| } | ||
| loop.AddCallback( | ||
| [&connection_timeout_mutex, &conncetion_timeout_time_point, | ||
| next_checkpoint](MainLoopBase &loop) { | ||
| std::scoped_lock<std::mutex> lock(connection_timeout_mutex); | ||
| if (conncetion_timeout_time_point == next_checkpoint) | ||
| loop.RequestTermination(); | ||
| }, | ||
| next_checkpoint); | ||
| } | ||
|
|
||
| static llvm::Expected<std::pair<Socket::SocketProtocol, std::string>> | ||
| validateConnection(llvm::StringRef conn) { | ||
| auto uri = lldb_private::URI::Parse(conn); | ||
|
|
@@ -255,10 +284,11 @@ validateConnection(llvm::StringRef conn) { | |
| return make_error(); | ||
| } | ||
|
|
||
| static llvm::Error | ||
| serveConnection(const Socket::SocketProtocol &protocol, const std::string &name, | ||
| Log *log, const ReplMode default_repl_mode, | ||
| const std::vector<std::string> &pre_init_commands) { | ||
| static llvm::Error serveConnection( | ||
| const Socket::SocketProtocol &protocol, const std::string &name, Log *log, | ||
| const ReplMode default_repl_mode, | ||
| const std::vector<std::string> &pre_init_commands, | ||
| std::optional<std::chrono::seconds> connection_timeout_seconds) { | ||
| Status status; | ||
| static std::unique_ptr<Socket> listener = Socket::Create(protocol, status); | ||
| if (status.Fail()) { | ||
|
|
@@ -283,6 +313,12 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name, | |
| g_loop.AddPendingCallback( | ||
| [](MainLoopBase &loop) { loop.RequestTermination(); }); | ||
| }); | ||
| static MainLoopBase::TimePoint g_connection_timeout_time_point; | ||
| static std::mutex g_connection_timeout_mutex; | ||
| if (connection_timeout_seconds) | ||
| TrackConnectionTimeout(g_loop, g_connection_timeout_mutex, | ||
| g_connection_timeout_time_point, | ||
| connection_timeout_seconds.value()); | ||
| std::condition_variable dap_sessions_condition; | ||
| std::mutex dap_sessions_mutex; | ||
| std::map<MainLoop *, DAP *> dap_sessions; | ||
|
|
@@ -291,6 +327,11 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name, | |
| &dap_sessions_mutex, &dap_sessions, | ||
| &clientCount]( | ||
| std::unique_ptr<Socket> sock) { | ||
| // Reset the keep alive timer, because we won't be killing the server | ||
| // while this connection is being served. | ||
| if (connection_timeout_seconds) | ||
| ResetConnectionTimeout(g_connection_timeout_mutex, | ||
| g_connection_timeout_time_point); | ||
| std::string client_name = llvm::formatv("client_{0}", clientCount++).str(); | ||
| DAP_LOG(log, "({0}) client connected", client_name); | ||
|
|
||
|
|
@@ -327,6 +368,12 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name, | |
| std::unique_lock<std::mutex> lock(dap_sessions_mutex); | ||
| dap_sessions.erase(&loop); | ||
| std::notify_all_at_thread_exit(dap_sessions_condition, std::move(lock)); | ||
|
|
||
| // Start the countdown to kill the server at the end of each connection. | ||
| if (connection_timeout_seconds) | ||
| TrackConnectionTimeout(g_loop, g_connection_timeout_mutex, | ||
| g_connection_timeout_time_point, | ||
| connection_timeout_seconds.value()); | ||
| }); | ||
| client.detach(); | ||
| }); | ||
|
|
@@ -456,6 +503,31 @@ int main(int argc, char *argv[]) { | |
| connection.assign(path); | ||
| } | ||
|
|
||
| std::optional<std::chrono::seconds> connection_timeout_seconds; | ||
| if (llvm::opt::Arg *connection_timeout_arg = | ||
| input_args.getLastArg(OPT_connection_timeout)) { | ||
| if (!connection.empty()) { | ||
| llvm::StringRef connection_timeout_string_value = | ||
| connection_timeout_arg->getValue(); | ||
| int connection_timeout_int_value; | ||
| if (connection_timeout_string_value.getAsInteger( | ||
| 10, connection_timeout_int_value)) { | ||
| llvm::errs() << "'" << connection_timeout_string_value | ||
| << "' is not a valid connection timeout value\n"; | ||
| return EXIT_FAILURE; | ||
| } | ||
| // Ignore non-positive values. | ||
| if (connection_timeout_int_value > 0) | ||
| connection_timeout_seconds = | ||
| std::chrono::seconds(connection_timeout_int_value); | ||
| } else { | ||
| llvm::errs() | ||
| << "\"--connection-timeout\" requires \"--connection\" to be " | ||
| "specified\n"; | ||
| return EXIT_FAILURE; | ||
| } | ||
| } | ||
|
|
||
| #if !defined(_WIN32) | ||
| if (input_args.hasArg(OPT_wait_for_debugger)) { | ||
| printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); | ||
|
|
@@ -519,8 +591,9 @@ int main(int argc, char *argv[]) { | |
| Socket::SocketProtocol protocol; | ||
| std::string name; | ||
| std::tie(protocol, name) = *maybeProtoclAndName; | ||
| if (auto Err = serveConnection(protocol, name, log.get(), default_repl_mode, | ||
| pre_init_commands)) { | ||
| if (auto Err = | ||
|
||
| serveConnection(protocol, name, log.get(), default_repl_mode, | ||
| pre_init_commands, connection_timeout_seconds)) { | ||
| llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), | ||
| "Connection failed: "); | ||
| return EXIT_FAILURE; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.