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