From 4460691252d5c345f0b34ac366639df23c687832 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Tue, 21 Mar 2023 08:35:09 -0600 Subject: Fix race in DAP startup Internal AdaCore DAP testing on Windows has had occasional failures that show: assert threading.current_thread() is _dap_thread I think this is a race in DAP startup: the _dap_thread global is only set on return from start_thread, but it seems possible that the thread itself could already run and encounter a @in_dap_thread decorator. This patch fixes the problem by setting the global before running any of the code in the new thread. This also lets us remove a FIXME. --- gdb/python/lib/gdb/dap/server.py | 4 +--- gdb/python/lib/gdb/dap/startup.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index 92b4eee..ff88282 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -100,9 +100,7 @@ class Server: log("WROTE: <<<" + json.dumps(obj) + ">>>") self.write_queue.put(obj) - # This must be run in the DAP thread, but we can't use - # @in_dap_thread here because the global isn't set until after - # this starts running. FIXME. + @in_dap_thread def main_loop(self): """The main loop of the DAP server.""" # Before looping, start the thread that writes JSON to the diff --git a/gdb/python/lib/gdb/dap/startup.py b/gdb/python/lib/gdb/dap/startup.py index 22246a9..aa834cd 100644 --- a/gdb/python/lib/gdb/dap/startup.py +++ b/gdb/python/lib/gdb/dap/startup.py @@ -59,14 +59,20 @@ def start_thread(name, target, args=()): with blocked_signals(): result = threading.Thread(target=target, args=args, daemon=True) result.start() - return result def start_dap(target): """Start the DAP thread and invoke TARGET there.""" - global _dap_thread exec_and_log("set breakpoint pending on") - _dap_thread = start_thread("DAP", target) + + # Functions in this thread contain assertions that check for this + # global, so we must set it before letting these functions run. + def really_start_dap(): + global _dap_thread + _dap_thread = threading.current_thread() + target() + + start_thread("DAP", really_start_dap) def in_gdb_thread(func): -- cgit v1.1