]>
Commit | Line | Data |
---|---|---|
9411c49e | 1 | /* Run a function on the main thread |
1d506c26 | 2 | Copyright (C) 2019-2024 Free Software Foundation, Inc. |
9411c49e TT |
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 | |
47ccd6b8 | 23 | #include <thread> |
9411c49e TT |
24 | #include <mutex> |
25 | #endif | |
400b5eca | 26 | #include "gdbsupport/event-loop.h" |
9411c49e TT |
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 | ||
07d8d4bd | 42 | /* The main thread's thread id. */ |
47ccd6b8 | 43 | |
07d8d4bd | 44 | static std::thread::id main_thread_id; |
47ccd6b8 | 45 | |
9411c49e TT |
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 | ||
c082d7f5 TV |
97 | #if CXX_STD_THREAD |
98 | static bool main_thread_id_initialized = false; | |
99 | #endif | |
100 | ||
47ccd6b8 TT |
101 | /* See run-on-main-thread.h. */ |
102 | ||
103 | bool | |
104 | is_main_thread () | |
105 | { | |
106 | #if CXX_STD_THREAD | |
c082d7f5 TV |
107 | /* Initialize main_thread_id on first use of is_main_thread. */ |
108 | if (!main_thread_id_initialized) | |
109 | { | |
110 | main_thread_id_initialized = true; | |
111 | ||
112 | main_thread_id = std::this_thread::get_id (); | |
113 | } | |
114 | ||
07d8d4bd | 115 | return std::this_thread::get_id () == main_thread_id; |
47ccd6b8 TT |
116 | #else |
117 | return true; | |
118 | #endif | |
119 | } | |
120 | ||
6c265988 | 121 | void _initialize_run_on_main_thread (); |
9411c49e TT |
122 | void |
123 | _initialize_run_on_main_thread () | |
124 | { | |
47ccd6b8 | 125 | #if CXX_STD_THREAD |
c082d7f5 TV |
126 | /* The variable main_thread_id should be initialized when entering main, or |
127 | at an earlier use, so it should already be initialized here. */ | |
128 | gdb_assert (main_thread_id_initialized); | |
129 | ||
130 | /* Assume that we execute this in the main thread. */ | |
131 | gdb_assert (is_main_thread ()); | |
47ccd6b8 | 132 | #endif |
9411c49e | 133 | runnable_event = make_serial_event (); |
2554f6f5 SM |
134 | add_file_handler (serial_event_fd (runnable_event), run_events, nullptr, |
135 | "run-on-main-thread"); | |
9411c49e | 136 | } |