mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-06 12:09:26 +08:00
1d506c26d9
This commit is the result of the following actions: - Running gdb/copyright.py to update all of the copyright headers to include 2024, - Manually updating a few files the copyright.py script told me to update, these files had copyright headers embedded within the file, - Regenerating gdbsupport/Makefile.in to refresh it's copyright date, - Using grep to find other files that still mentioned 2023. If these files were updated last year from 2022 to 2023 then I've updated them this year to 2024. I'm sure I've probably missed some dates. Feel free to fix them up as you spot them.
373 lines
11 KiB
C
373 lines
11 KiB
C
/* Async events for the GDB event loop.
|
||
Copyright (C) 1999-2024 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;
|
||
}
|