mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-30 13:33:53 +08:00
6b36ddeb1e
The `ready` flag of async event handlers is cleared by the async event handler system right before invoking the associated callback, in check_async_event_handlers. This is not ideal with how the infrun subsystem consumes events: all targets' async event handler callbacks essentially just invoke `inferior_event_handler`, which eventually calls `fetch_inferior_event` and `do_target_wait`. `do_target_wait` picks an inferior at random, and thus a target at random (it could be the target whose `ready` flag was cleared, or not), and pulls one event from it. So it's possible that: - the async event handler for a target A is called - we end up consuming an event for target B - all threads of target B are stopped, target_async(0) is called on it, so its async event handler is cleared (e.g. record_btrace_target::async) As a result, target A still has events to report while its async event handler is left unmarked, so these events are not consumed. To counter this, at the end of their async event handler callbacks, targets check if they still have something to report and re-mark their async event handler (e.g. remote_async_inferior_event_handler). The linux_nat target does not suffer from this because it doesn't use an async event handler at the moment. It only uses a pipe registered with the event loop. It is written to in the SIGCHLD handler (and in other spots that want to get target wait method called) and read from in the target's wait method. So if linux_nat happened to be target A in the example above, the pipe would just stay readable, and the event loop would wake up again, until linux_nat's wait method is finally called and consumes the contents of the pipe. I think it would be nicer if targets using async_event_handler worked in a similar way, where the flag would stay set until the target's wait method is actually called. As a first step towards that, this patch moves the responsibility of clearing the ready flags of async event handlers to the invoked callback. All async event handler callbacks are modified to clear their ready flag before doing anything else. So in practice, nothing changes with this patch. It's only the responsibility of clearing the flag that is shifted toward the callee. gdb/ChangeLog: * async-event.h (async_event_handler_func): Add documentation. * async-event.c (check_async_event_handlers): Don't clear async_event_handler ready flag. * infrun.c (infrun_async_inferior_event_handler): Clear ready flag. * record-btrace.c (record_btrace_handle_async_inferior_event): Likewise. * record-full.c (record_full_async_inferior_event_handler): Likewise. * remote-notif.c (remote_async_get_pending_events_handler): Likewise. * remote.c (remote_async_inferior_event_handler): Likewise. Change-Id: I179ef8e99580eae642d332846fd13664dbddc0c1
362 lines
11 KiB
C
362 lines
11 KiB
C
/* Async events for the GDB event loop.
|
||
Copyright (C) 1999-2021 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;
|
||
}
|
||
|
||
/* 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;
|
||
}
|