| /* Async events for the GDB event loop. | |
| Copyright (C) 1999-2023 Free Software Foundation, Inc. | |
| This file is part of GDB. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
| #include "defs.h" | |
| #include "async-event.h" | |
| #include "ser-event.h" | |
| #include "top.h" | |
| #include "ui.h" | |
| /* PROC is a function to be invoked when the READY flag is set. This | |
| happens when there has been a signal and the corresponding signal | |
| handler has 'triggered' this async_signal_handler for execution. | |
| The actual work to be done in response to a signal will be carried | |
| out by PROC at a later time, within process_event. This provides a | |
| deferred execution of signal handlers. | |
| Async_init_signals takes care of setting up such an | |
| async_signal_handler for each interesting signal. */ | |
| struct async_signal_handler | |
| { | |
| /* If ready, call this handler from the main event loop, using | |
| invoke_async_handler. */ | |
| int ready; | |
| /* Pointer to next handler. */ | |
| struct async_signal_handler *next_handler; | |
| /* Function to call to do the work. */ | |
| sig_handler_func *proc; | |
| /* Argument to PROC. */ | |
| gdb_client_data client_data; | |
| /* User-friendly name of this handler. */ | |
| const char *name; | |
| }; | |
| /* PROC is a function to be invoked when the READY flag is set. This | |
| happens when the event has been marked with | |
| MARK_ASYNC_EVENT_HANDLER. The actual work to be done in response | |
| to an event will be carried out by PROC at a later time, within | |
| process_event. This provides a deferred execution of event | |
| handlers. */ | |
| struct async_event_handler | |
| { | |
| /* If ready, call this handler from the main event loop, using | |
| invoke_event_handler. */ | |
| int ready; | |
| /* Pointer to next handler. */ | |
| struct async_event_handler *next_handler; | |
| /* Function to call to do the work. */ | |
| async_event_handler_func *proc; | |
| /* Argument to PROC. */ | |
| gdb_client_data client_data; | |
| /* User-friendly name of this handler. */ | |
| const char *name; | |
| }; | |
| /* All the async_signal_handlers gdb is interested in are kept onto | |
| this list. */ | |
| static struct | |
| { | |
| /* Pointer to first in handler list. */ | |
| async_signal_handler *first_handler; | |
| /* Pointer to last in handler list. */ | |
| async_signal_handler *last_handler; | |
| } | |
| sighandler_list; | |
| /* All the async_event_handlers gdb is interested in are kept onto | |
| this list. */ | |
| static struct | |
| { | |
| /* Pointer to first in handler list. */ | |
| async_event_handler *first_handler; | |
| /* Pointer to last in handler list. */ | |
| async_event_handler *last_handler; | |
| } | |
| async_event_handler_list; | |
| /* This event is signalled whenever an asynchronous handler needs to | |
| defer an action to the event loop. */ | |
| static struct serial_event *async_signal_handlers_serial_event; | |
| /* Callback registered with ASYNC_SIGNAL_HANDLERS_SERIAL_EVENT. */ | |
| static void | |
| async_signals_handler (int error, gdb_client_data client_data) | |
| { | |
| /* Do nothing. Handlers are run by invoke_async_signal_handlers | |
| from instead. */ | |
| } | |
| void | |
| initialize_async_signal_handlers (void) | |
| { | |
| async_signal_handlers_serial_event = make_serial_event (); | |
| add_file_handler (serial_event_fd (async_signal_handlers_serial_event), | |
| async_signals_handler, NULL, "async-signals"); | |
| } | |
| /* Create an asynchronous handler, allocating memory for it. | |
| Return a pointer to the newly created handler. | |
| This pointer will be used to invoke the handler by | |
| invoke_async_signal_handler. | |
| PROC is the function to call with CLIENT_DATA argument | |
| whenever the handler is invoked. */ | |
| async_signal_handler * | |
| create_async_signal_handler (sig_handler_func * proc, | |
| gdb_client_data client_data, | |
| const char *name) | |
| { | |
| async_signal_handler *async_handler_ptr; | |
| async_handler_ptr = XNEW (async_signal_handler); | |
| async_handler_ptr->ready = 0; | |
| async_handler_ptr->next_handler = NULL; | |
| async_handler_ptr->proc = proc; | |
| async_handler_ptr->client_data = client_data; | |
| async_handler_ptr->name = name; | |
| if (sighandler_list.first_handler == NULL) | |
| sighandler_list.first_handler = async_handler_ptr; | |
| else | |
| sighandler_list.last_handler->next_handler = async_handler_ptr; | |
| sighandler_list.last_handler = async_handler_ptr; | |
| return async_handler_ptr; | |
| } | |
| /* Mark the handler (ASYNC_HANDLER_PTR) as ready. This information | |
| will be used when the handlers are invoked, after we have waited | |
| for some event. The caller of this function is the interrupt | |
| handler associated with a signal. */ | |
| void | |
| mark_async_signal_handler (async_signal_handler *async_handler_ptr) | |
| { | |
| if (debug_event_loop != debug_event_loop_kind::OFF) | |
| { | |
| /* This is called by signal handlers, so we print it "by hand" using | |
| the async-signal-safe methods. */ | |
| const char head[] = ("[event-loop] mark_async_signal_handler: marking" | |
| "async signal handler `"); | |
| gdb_stdlog->write_async_safe (head, strlen (head)); | |
| gdb_stdlog->write_async_safe (async_handler_ptr->name, | |
| strlen (async_handler_ptr->name)); | |
| const char tail[] = "`\n"; | |
| gdb_stdlog->write_async_safe (tail, strlen (tail)); | |
| } | |
| async_handler_ptr->ready = 1; | |
| serial_event_set (async_signal_handlers_serial_event); | |
| } | |
| /* See event-loop.h. */ | |
| void | |
| clear_async_signal_handler (async_signal_handler *async_handler_ptr) | |
| { | |
| event_loop_debug_printf ("clearing async signal handler `%s`", | |
| async_handler_ptr->name); | |
| async_handler_ptr->ready = 0; | |
| } | |
| /* See event-loop.h. */ | |
| int | |
| async_signal_handler_is_marked (async_signal_handler *async_handler_ptr) | |
| { | |
| return async_handler_ptr->ready; | |
| } | |
| /* Call all the handlers that are ready. Returns true if any was | |
| indeed ready. */ | |
| int | |
| invoke_async_signal_handlers (void) | |
| { | |
| async_signal_handler *async_handler_ptr; | |
| int any_ready = 0; | |
| /* We're going to handle all pending signals, so no need to wake up | |
| the event loop again the next time around. Note this must be | |
| cleared _before_ calling the callbacks, to avoid races. */ | |
| serial_event_clear (async_signal_handlers_serial_event); | |
| /* Invoke all ready handlers. */ | |
| while (1) | |
| { | |
| for (async_handler_ptr = sighandler_list.first_handler; | |
| async_handler_ptr != NULL; | |
| async_handler_ptr = async_handler_ptr->next_handler) | |
| { | |
| if (async_handler_ptr->ready) | |
| break; | |
| } | |
| if (async_handler_ptr == NULL) | |
| break; | |
| any_ready = 1; | |
| async_handler_ptr->ready = 0; | |
| /* Async signal handlers have no connection to whichever was the | |
| current UI, and thus always run on the main one. */ | |
| current_ui = main_ui; | |
| event_loop_debug_printf ("invoking async signal handler `%s`", | |
| async_handler_ptr->name); | |
| (*async_handler_ptr->proc) (async_handler_ptr->client_data); | |
| } | |
| return any_ready; | |
| } | |
| /* Delete an asynchronous handler (ASYNC_HANDLER_PTR). | |
| Free the space allocated for it. */ | |
| void | |
| delete_async_signal_handler (async_signal_handler ** async_handler_ptr) | |
| { | |
| async_signal_handler *prev_ptr; | |
| if (sighandler_list.first_handler == (*async_handler_ptr)) | |
| { | |
| sighandler_list.first_handler = (*async_handler_ptr)->next_handler; | |
| if (sighandler_list.first_handler == NULL) | |
| sighandler_list.last_handler = NULL; | |
| } | |
| else | |
| { | |
| prev_ptr = sighandler_list.first_handler; | |
| while (prev_ptr && prev_ptr->next_handler != (*async_handler_ptr)) | |
| prev_ptr = prev_ptr->next_handler; | |
| gdb_assert (prev_ptr); | |
| prev_ptr->next_handler = (*async_handler_ptr)->next_handler; | |
| if (sighandler_list.last_handler == (*async_handler_ptr)) | |
| sighandler_list.last_handler = prev_ptr; | |
| } | |
| xfree ((*async_handler_ptr)); | |
| (*async_handler_ptr) = NULL; | |
| } | |
| /* See async-event.h. */ | |
| async_event_handler * | |
| create_async_event_handler (async_event_handler_func *proc, | |
| gdb_client_data client_data, | |
| const char *name) | |
| { | |
| async_event_handler *h; | |
| h = XNEW (struct async_event_handler); | |
| h->ready = 0; | |
| h->next_handler = NULL; | |
| h->proc = proc; | |
| h->client_data = client_data; | |
| h->name = name; | |
| if (async_event_handler_list.first_handler == NULL) | |
| async_event_handler_list.first_handler = h; | |
| else | |
| async_event_handler_list.last_handler->next_handler = h; | |
| async_event_handler_list.last_handler = h; | |
| return h; | |
| } | |
| /* Mark the handler (ASYNC_HANDLER_PTR) as ready. This information | |
| will be used by gdb_do_one_event. The caller will be whoever | |
| created the event source, and wants to signal that the event is | |
| ready to be handled. */ | |
| void | |
| mark_async_event_handler (async_event_handler *async_handler_ptr) | |
| { | |
| event_loop_debug_printf ("marking async event handler `%s` " | |
| "(previous state was %d)", | |
| async_handler_ptr->name, | |
| async_handler_ptr->ready); | |
| async_handler_ptr->ready = 1; | |
| } | |
| /* See event-loop.h. */ | |
| void | |
| clear_async_event_handler (async_event_handler *async_handler_ptr) | |
| { | |
| event_loop_debug_printf ("clearing async event handler `%s`", | |
| async_handler_ptr->name); | |
| async_handler_ptr->ready = 0; | |
| } | |
| /* See event-loop.h. */ | |
| bool | |
| async_event_handler_marked (async_event_handler *handler) | |
| { | |
| return handler->ready; | |
| } | |
| /* Check if asynchronous event handlers are ready, and call the | |
| handler function for one that is. */ | |
| int | |
| check_async_event_handlers () | |
| { | |
| async_event_handler *async_handler_ptr; | |
| for (async_handler_ptr = async_event_handler_list.first_handler; | |
| async_handler_ptr != NULL; | |
| async_handler_ptr = async_handler_ptr->next_handler) | |
| { | |
| if (async_handler_ptr->ready) | |
| { | |
| event_loop_debug_printf ("invoking async event handler `%s`", | |
| async_handler_ptr->name); | |
| (*async_handler_ptr->proc) (async_handler_ptr->client_data); | |
| return 1; | |
| } | |
| } | |
| return 0; | |
| } | |
| /* Delete an asynchronous handler (ASYNC_HANDLER_PTR). | |
| Free the space allocated for it. */ | |
| void | |
| delete_async_event_handler (async_event_handler **async_handler_ptr) | |
| { | |
| async_event_handler *prev_ptr; | |
| if (async_event_handler_list.first_handler == *async_handler_ptr) | |
| { | |
| async_event_handler_list.first_handler | |
| = (*async_handler_ptr)->next_handler; | |
| if (async_event_handler_list.first_handler == NULL) | |
| async_event_handler_list.last_handler = NULL; | |
| } | |
| else | |
| { | |
| prev_ptr = async_event_handler_list.first_handler; | |
| while (prev_ptr && prev_ptr->next_handler != *async_handler_ptr) | |
| prev_ptr = prev_ptr->next_handler; | |
| gdb_assert (prev_ptr); | |
| prev_ptr->next_handler = (*async_handler_ptr)->next_handler; | |
| if (async_event_handler_list.last_handler == (*async_handler_ptr)) | |
| async_event_handler_list.last_handler = prev_ptr; | |
| } | |
| xfree (*async_handler_ptr); | |
| *async_handler_ptr = NULL; | |
| } |