| /* 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; |
| } |