xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/run-on-main-thread.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1 /* Run a function on the main thread
2    Copyright (C) 2019-2023 Free Software Foundation, Inc.
3 
4    This file is part of GDB.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #include "defs.h"
20 #include "run-on-main-thread.h"
21 #include "ser-event.h"
22 #if CXX_STD_THREAD
23 #include <thread>
24 #include <mutex>
25 #endif
26 #include "gdbsupport/event-loop.h"
27 
28 /* The serial event used when posting runnables.  */
29 
30 static struct serial_event *runnable_event;
31 
32 /* Runnables that have been posted.  */
33 
34 static std::vector<std::function<void ()>> runnables;
35 
36 #if CXX_STD_THREAD
37 
38 /* Mutex to hold when handling RUNNABLE_EVENT or RUNNABLES.  */
39 
40 static std::mutex runnable_mutex;
41 
42 /* The main thread.  */
43 
44 static std::thread::id main_thread;
45 
46 #endif
47 
48 /* Run all the queued runnables.  */
49 
50 static void
51 run_events (int error, gdb_client_data client_data)
52 {
53   std::vector<std::function<void ()>> local;
54 
55   /* Hold the lock while changing the globals, but not while running
56      the runnables.  */
57   {
58 #if CXX_STD_THREAD
59     std::lock_guard<std::mutex> lock (runnable_mutex);
60 #endif
61 
62     /* Clear the event fd.  Do this before flushing the events list,
63        so that any new event post afterwards is sure to re-awaken the
64        event loop.  */
65     serial_event_clear (runnable_event);
66 
67     /* Move the vector in case running a runnable pushes a new
68        runnable.  */
69     local = std::move (runnables);
70   }
71 
72   for (auto &item : local)
73     {
74       try
75 	{
76 	  item ();
77 	}
78       catch (...)
79 	{
80 	  /* Ignore exceptions in the callback.  */
81 	}
82     }
83 }
84 
85 /* See run-on-main-thread.h.  */
86 
87 void
88 run_on_main_thread (std::function<void ()> &&func)
89 {
90 #if CXX_STD_THREAD
91   std::lock_guard<std::mutex> lock (runnable_mutex);
92 #endif
93   runnables.emplace_back (std::move (func));
94   serial_event_set (runnable_event);
95 }
96 
97 /* See run-on-main-thread.h.  */
98 
99 bool
100 is_main_thread ()
101 {
102 #if CXX_STD_THREAD
103   return std::this_thread::get_id () == main_thread;
104 #else
105   return true;
106 #endif
107 }
108 
109 void _initialize_run_on_main_thread ();
110 void
111 _initialize_run_on_main_thread ()
112 {
113 #if CXX_STD_THREAD
114   main_thread = std::this_thread::get_id ();
115 #endif
116   runnable_event = make_serial_event ();
117   add_file_handler (serial_event_fd (runnable_event), run_events, nullptr,
118 		    "run-on-main-thread");
119 }
120