123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- /* Async events for the GDB event loop.
- Copyright (C) 1999-2022 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"
- /* 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`",
- async_handler_ptr->name);
- 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;
- }
|