Introduce async-event.[ch]
This patch splits out some gdb-specific code from event-loop, into new files async-event.[ch]. Strictly speaking this code could perhaps be put into gdbsupport/, but because gdbserver does not currently use it, it seemed better, for size reasons, to split it out. gdb/ChangeLog 2020-04-13 Tom Tromey <tom@tromey.com> * tui/tui-win.c: Include async-event.h. * remote.c: Include async-event.h. * remote-notif.c: Include async-event.h. * record-full.c: Include async-event.h. * record-btrace.c: Include async-event.h. * infrun.c: Include async-event.h. * event-top.c: Include async-event.h. * event-loop.h: Move some declarations to async-event.h. * event-loop.c: Don't include ser-event.h or top.h. Move some code to async-event.c. * async-event.h: New file. * async-event.c: New file. * Makefile.in (COMMON_SFILES): Add async-event.c. (HFILES_NO_SRCDIR): Add async-event.h.
This commit is contained in:
parent
c1cd3163d9
commit
93b54c8ed3
13 changed files with 430 additions and 345 deletions
|
@ -1,3 +1,20 @@
|
||||||
|
2020-04-13 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
|
* tui/tui-win.c: Include async-event.h.
|
||||||
|
* remote.c: Include async-event.h.
|
||||||
|
* remote-notif.c: Include async-event.h.
|
||||||
|
* record-full.c: Include async-event.h.
|
||||||
|
* record-btrace.c: Include async-event.h.
|
||||||
|
* infrun.c: Include async-event.h.
|
||||||
|
* event-top.c: Include async-event.h.
|
||||||
|
* event-loop.h: Move some declarations to async-event.h.
|
||||||
|
* event-loop.c: Don't include ser-event.h or top.h. Move some
|
||||||
|
code to async-event.c.
|
||||||
|
* async-event.h: New file.
|
||||||
|
* async-event.c: New file.
|
||||||
|
* Makefile.in (COMMON_SFILES): Add async-event.c.
|
||||||
|
(HFILES_NO_SRCDIR): Add async-event.h.
|
||||||
|
|
||||||
2020-04-13 Tom Tromey <tom@tromey.com>
|
2020-04-13 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
* utils.c (flush_streams): New function.
|
* utils.c (flush_streams): New function.
|
||||||
|
|
|
@ -955,6 +955,7 @@ COMMON_SFILES = \
|
||||||
alloc.c \
|
alloc.c \
|
||||||
annotate.c \
|
annotate.c \
|
||||||
arch-utils.c \
|
arch-utils.c \
|
||||||
|
async-event.c \
|
||||||
auto-load.c \
|
auto-load.c \
|
||||||
auxv.c \
|
auxv.c \
|
||||||
ax-gdb.c \
|
ax-gdb.c \
|
||||||
|
@ -1212,6 +1213,7 @@ HFILES_NO_SRCDIR = \
|
||||||
arm-linux-tdep.h \
|
arm-linux-tdep.h \
|
||||||
arm-nbsd-tdep.h \
|
arm-nbsd-tdep.h \
|
||||||
arm-tdep.h \
|
arm-tdep.h \
|
||||||
|
async-event.h \
|
||||||
auto-load.h \
|
auto-load.h \
|
||||||
auxv.h \
|
auxv.h \
|
||||||
ax.h \
|
ax.h \
|
||||||
|
|
325
gdb/async-event.c
Normal file
325
gdb/async-event.c
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
/* Async events for the GDB event loop.
|
||||||
|
Copyright (C) 1999-2019 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. */
|
||||||
|
|
||||||
|
typedef struct async_signal_handler
|
||||||
|
{
|
||||||
|
int ready; /* If ready, call this handler
|
||||||
|
from the main event loop, using
|
||||||
|
invoke_async_handler. */
|
||||||
|
struct async_signal_handler *next_handler; /* Ptr to next handler. */
|
||||||
|
sig_handler_func *proc; /* Function to call to do the work. */
|
||||||
|
gdb_client_data client_data; /* Argument to async_handler_func. */
|
||||||
|
}
|
||||||
|
async_signal_handler;
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
typedef struct async_event_handler
|
||||||
|
{
|
||||||
|
/* If ready, call this handler from the main event loop, using
|
||||||
|
invoke_event_handler. */
|
||||||
|
int ready;
|
||||||
|
|
||||||
|
/* Point 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;
|
||||||
|
}
|
||||||
|
async_event_handler;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
(*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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create an asynchronous event handler, allocating memory for it.
|
||||||
|
Return a pointer to the newly created handler. PROC is the
|
||||||
|
function to call with CLIENT_DATA argument whenever the handler is
|
||||||
|
invoked. */
|
||||||
|
async_event_handler *
|
||||||
|
create_async_event_handler (async_event_handler_func *proc,
|
||||||
|
gdb_client_data client_data)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
async_handler_ptr->ready = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See event-loop.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_async_event_handler (async_event_handler *async_handler_ptr)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
async_handler_ptr->ready = 0;
|
||||||
|
(*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;
|
||||||
|
}
|
71
gdb/async-event.h
Normal file
71
gdb/async-event.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* Async events for the GDB event loop.
|
||||||
|
Copyright (C) 1999-2019 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/>. */
|
||||||
|
|
||||||
|
#ifndef ASYNC_EVENT_H
|
||||||
|
#define ASYNC_EVENT_H
|
||||||
|
|
||||||
|
#include "event-loop.h"
|
||||||
|
|
||||||
|
struct async_signal_handler;
|
||||||
|
struct async_event_handler;
|
||||||
|
typedef void (sig_handler_func) (gdb_client_data);
|
||||||
|
typedef void (async_event_handler_func) (gdb_client_data);
|
||||||
|
|
||||||
|
extern struct async_signal_handler *
|
||||||
|
create_async_signal_handler (sig_handler_func *proc,
|
||||||
|
gdb_client_data client_data);
|
||||||
|
extern void delete_async_signal_handler (struct async_signal_handler **);
|
||||||
|
|
||||||
|
/* Call the handler from HANDLER the next time through the event
|
||||||
|
loop. */
|
||||||
|
extern void mark_async_signal_handler (struct async_signal_handler *handler);
|
||||||
|
|
||||||
|
/* Returns true if HANDLER is marked ready. */
|
||||||
|
|
||||||
|
extern int
|
||||||
|
async_signal_handler_is_marked (struct async_signal_handler *handler);
|
||||||
|
|
||||||
|
/* Mark HANDLER as NOT ready. */
|
||||||
|
|
||||||
|
extern void clear_async_signal_handler (struct async_signal_handler *handler);
|
||||||
|
|
||||||
|
/* Create and register an asynchronous event source in the event loop,
|
||||||
|
and set PROC as its callback. CLIENT_DATA is passed as argument to
|
||||||
|
PROC upon its invocation. Returns a pointer to an opaque structure
|
||||||
|
used to mark as ready and to later delete this event source from
|
||||||
|
the event loop. */
|
||||||
|
extern struct async_event_handler *
|
||||||
|
create_async_event_handler (async_event_handler_func *proc,
|
||||||
|
gdb_client_data client_data);
|
||||||
|
|
||||||
|
/* Remove the event source pointed by HANDLER_PTR created by
|
||||||
|
CREATE_ASYNC_EVENT_HANDLER from the event loop, and release it. */
|
||||||
|
extern void
|
||||||
|
delete_async_event_handler (struct async_event_handler **handler_ptr);
|
||||||
|
|
||||||
|
/* Call the handler from HANDLER the next time through the event
|
||||||
|
loop. */
|
||||||
|
extern void mark_async_event_handler (struct async_event_handler *handler);
|
||||||
|
|
||||||
|
/* Mark the handler (ASYNC_HANDLER_PTR) as NOT ready. */
|
||||||
|
|
||||||
|
extern void clear_async_event_handler (struct async_event_handler *handler);
|
||||||
|
|
||||||
|
extern void initialize_async_signal_handlers (void);
|
||||||
|
|
||||||
|
#endif /* ASYNC_EVENT_H */
|
306
gdb/event-loop.c
306
gdb/event-loop.c
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "event-loop.h"
|
#include "event-loop.h"
|
||||||
#include "event-top.h"
|
|
||||||
#include "ser-event.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
@ -35,7 +33,6 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "gdbsupport/gdb_sys_time.h"
|
#include "gdbsupport/gdb_sys_time.h"
|
||||||
#include "gdbsupport/gdb_select.h"
|
#include "gdbsupport/gdb_select.h"
|
||||||
#include "top.h"
|
|
||||||
|
|
||||||
/* Tell create_file_handler what events we are interested in.
|
/* Tell create_file_handler what events we are interested in.
|
||||||
This is used by the select version of the event loop. */
|
This is used by the select version of the event loop. */
|
||||||
|
@ -60,50 +57,6 @@ typedef struct file_handler
|
||||||
}
|
}
|
||||||
file_handler;
|
file_handler;
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
|
|
||||||
typedef struct async_signal_handler
|
|
||||||
{
|
|
||||||
int ready; /* If ready, call this handler
|
|
||||||
from the main event loop, using
|
|
||||||
invoke_async_handler. */
|
|
||||||
struct async_signal_handler *next_handler; /* Ptr to next handler. */
|
|
||||||
sig_handler_func *proc; /* Function to call to do the work. */
|
|
||||||
gdb_client_data client_data; /* Argument to async_handler_func. */
|
|
||||||
}
|
|
||||||
async_signal_handler;
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
typedef struct async_event_handler
|
|
||||||
{
|
|
||||||
/* If ready, call this handler from the main event loop, using
|
|
||||||
invoke_event_handler. */
|
|
||||||
int ready;
|
|
||||||
|
|
||||||
/* Point 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;
|
|
||||||
}
|
|
||||||
async_event_handler;
|
|
||||||
|
|
||||||
/* Gdb_notifier is just a list of file descriptors gdb is interested in.
|
/* Gdb_notifier is just a list of file descriptors gdb is interested in.
|
||||||
These are the input file descriptor, and the target file
|
These are the input file descriptor, and the target file
|
||||||
descriptor. We have two flavors of the notifier, one for platforms
|
descriptor. We have two flavors of the notifier, one for platforms
|
||||||
|
@ -198,61 +151,12 @@ static struct
|
||||||
}
|
}
|
||||||
timer_list;
|
timer_list;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
static int invoke_async_signal_handlers (void);
|
|
||||||
static void create_file_handler (int fd, int mask, handler_func *proc,
|
static void create_file_handler (int fd, int mask, handler_func *proc,
|
||||||
gdb_client_data client_data);
|
gdb_client_data client_data);
|
||||||
static int check_async_event_handlers (void);
|
|
||||||
static int gdb_wait_for_event (int);
|
static int gdb_wait_for_event (int);
|
||||||
static int update_wait_timeout (void);
|
static int update_wait_timeout (void);
|
||||||
static int poll_timers (void);
|
static int poll_timers (void);
|
||||||
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process one high level event. If nothing is ready at this time,
|
/* Process one high level event. If nothing is ready at this time,
|
||||||
wait for something to happen (via gdb_wait_for_event), then process
|
wait for something to happen (via gdb_wait_for_event), then process
|
||||||
it. Returns >0 if something was done otherwise returns <0 (this
|
it. Returns >0 if something was done otherwise returns <0 (this
|
||||||
|
@ -800,216 +704,6 @@ gdb_wait_for_event (int block)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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. */
|
|
||||||
|
|
||||||
static 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;
|
|
||||||
(*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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create an asynchronous event handler, allocating memory for it.
|
|
||||||
Return a pointer to the newly created handler. PROC is the
|
|
||||||
function to call with CLIENT_DATA argument whenever the handler is
|
|
||||||
invoked. */
|
|
||||||
async_event_handler *
|
|
||||||
create_async_event_handler (async_event_handler_func *proc,
|
|
||||||
gdb_client_data client_data)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
async_handler_ptr->ready = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See event-loop.h. */
|
|
||||||
|
|
||||||
void
|
|
||||||
clear_async_event_handler (async_event_handler *async_handler_ptr)
|
|
||||||
{
|
|
||||||
async_handler_ptr->ready = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if asynchronous event handlers are ready, and call the
|
|
||||||
handler function for one that is. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
check_async_event_handlers (void)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
async_handler_ptr->ready = 0;
|
|
||||||
(*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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a timer that will expire in MS milliseconds from now. When
|
/* Create a timer that will expire in MS milliseconds from now. When
|
||||||
the timer is ready, PROC will be executed. At creation, the timer
|
the timer is ready, PROC will be executed. At creation, the timer
|
||||||
is added to the timers queue. This queue is kept sorted in order
|
is added to the timers queue. This queue is kept sorted in order
|
||||||
|
|
|
@ -71,11 +71,7 @@
|
||||||
Corollary tasks are the creation and deletion of event sources. */
|
Corollary tasks are the creation and deletion of event sources. */
|
||||||
|
|
||||||
typedef void *gdb_client_data;
|
typedef void *gdb_client_data;
|
||||||
struct async_signal_handler;
|
|
||||||
struct async_event_handler;
|
|
||||||
typedef void (handler_func) (int, gdb_client_data);
|
typedef void (handler_func) (int, gdb_client_data);
|
||||||
typedef void (sig_handler_func) (gdb_client_data);
|
|
||||||
typedef void (async_event_handler_func) (gdb_client_data);
|
|
||||||
typedef void (timer_handler_func) (gdb_client_data);
|
typedef void (timer_handler_func) (gdb_client_data);
|
||||||
|
|
||||||
/* Exported functions from event-loop.c */
|
/* Exported functions from event-loop.c */
|
||||||
|
@ -84,50 +80,23 @@ extern int gdb_do_one_event (void);
|
||||||
extern void delete_file_handler (int fd);
|
extern void delete_file_handler (int fd);
|
||||||
extern void add_file_handler (int fd, handler_func *proc,
|
extern void add_file_handler (int fd, handler_func *proc,
|
||||||
gdb_client_data client_data);
|
gdb_client_data client_data);
|
||||||
extern struct async_signal_handler *
|
|
||||||
create_async_signal_handler (sig_handler_func *proc,
|
|
||||||
gdb_client_data client_data);
|
|
||||||
extern void delete_async_signal_handler (struct async_signal_handler **);
|
|
||||||
extern int create_timer (int milliseconds,
|
extern int create_timer (int milliseconds,
|
||||||
timer_handler_func *proc,
|
timer_handler_func *proc,
|
||||||
gdb_client_data client_data);
|
gdb_client_data client_data);
|
||||||
extern void delete_timer (int id);
|
extern void delete_timer (int id);
|
||||||
|
|
||||||
/* Call the handler from HANDLER the next time through the event
|
/* Must be defined by client. */
|
||||||
loop. */
|
|
||||||
extern void mark_async_signal_handler (struct async_signal_handler *handler);
|
|
||||||
|
|
||||||
/* Returns true if HANDLER is marked ready. */
|
extern void handle_event_loop_exception (const gdb_exception &);
|
||||||
|
|
||||||
extern int
|
/* Must be defined by client. Returns true if any signal handler was
|
||||||
async_signal_handler_is_marked (struct async_signal_handler *handler);
|
ready. */
|
||||||
|
|
||||||
/* Mark HANDLER as NOT ready. */
|
extern int invoke_async_signal_handlers ();
|
||||||
|
|
||||||
extern void clear_async_signal_handler (struct async_signal_handler *handler);
|
/* Must be defined by client. Returns true if any event handler was
|
||||||
|
ready. */
|
||||||
|
|
||||||
/* Create and register an asynchronous event source in the event loop,
|
extern int check_async_event_handlers ();
|
||||||
and set PROC as its callback. CLIENT_DATA is passed as argument to
|
|
||||||
PROC upon its invocation. Returns a pointer to an opaque structure
|
|
||||||
used to mark as ready and to later delete this event source from
|
|
||||||
the event loop. */
|
|
||||||
extern struct async_event_handler *
|
|
||||||
create_async_event_handler (async_event_handler_func *proc,
|
|
||||||
gdb_client_data client_data);
|
|
||||||
|
|
||||||
/* Remove the event source pointed by HANDLER_PTR created by
|
|
||||||
CREATE_ASYNC_EVENT_HANDLER from the event loop, and release it. */
|
|
||||||
extern void
|
|
||||||
delete_async_event_handler (struct async_event_handler **handler_ptr);
|
|
||||||
|
|
||||||
/* Call the handler from HANDLER the next time through the event
|
|
||||||
loop. */
|
|
||||||
extern void mark_async_event_handler (struct async_event_handler *handler);
|
|
||||||
|
|
||||||
/* Mark the handler (ASYNC_HANDLER_PTR) as NOT ready. */
|
|
||||||
|
|
||||||
extern void clear_async_event_handler (struct async_event_handler *handler);
|
|
||||||
|
|
||||||
extern void initialize_async_signal_handlers (void);
|
|
||||||
|
|
||||||
#endif /* EVENT_LOOP_H */
|
#endif /* EVENT_LOOP_H */
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "ser-event.h"
|
#include "ser-event.h"
|
||||||
#include "gdbsupport/gdb_select.h"
|
#include "gdbsupport/gdb_select.h"
|
||||||
#include "gdbsupport/gdb-sigmask.h"
|
#include "gdbsupport/gdb-sigmask.h"
|
||||||
|
#include "async-event.h"
|
||||||
|
|
||||||
/* readline include files. */
|
/* readline include files. */
|
||||||
#include "readline/readline.h"
|
#include "readline/readline.h"
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
#include "gdbsupport/forward-scope-exit.h"
|
#include "gdbsupport/forward-scope-exit.h"
|
||||||
#include "gdbsupport/gdb_select.h"
|
#include "gdbsupport/gdb_select.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include "async-event.h"
|
||||||
|
|
||||||
/* Prototypes for local functions */
|
/* Prototypes for local functions */
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "gdbarch.h"
|
#include "gdbarch.h"
|
||||||
#include "cli/cli-style.h"
|
#include "cli/cli-style.h"
|
||||||
|
#include "async-event.h"
|
||||||
|
|
||||||
static const target_info record_btrace_target_info = {
|
static const target_info record_btrace_target_info = {
|
||||||
"record-btrace",
|
"record-btrace",
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "infrun.h"
|
#include "infrun.h"
|
||||||
#include "gdbsupport/gdb_unlinker.h"
|
#include "gdbsupport/gdb_unlinker.h"
|
||||||
#include "gdbsupport/byte-vector.h"
|
#include "gdbsupport/byte-vector.h"
|
||||||
|
#include "async-event.h"
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "inferior.h"
|
#include "inferior.h"
|
||||||
#include "infrun.h"
|
#include "infrun.h"
|
||||||
#include "gdbcmd.h"
|
#include "gdbcmd.h"
|
||||||
|
#include "async-event.h"
|
||||||
|
|
||||||
bool notif_debug = false;
|
bool notif_debug = false;
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
#include "gdbsupport/byte-vector.h"
|
#include "gdbsupport/byte-vector.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include "async-event.h"
|
||||||
|
|
||||||
/* The remote target. */
|
/* The remote target. */
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
#include "event-loop.h"
|
#include "event-loop.h"
|
||||||
#include "gdbcmd.h"
|
#include "gdbcmd.h"
|
||||||
|
#include "async-event.h"
|
||||||
|
|
||||||
#include "tui/tui.h"
|
#include "tui/tui.h"
|
||||||
#include "tui/tui-io.h"
|
#include "tui/tui-io.h"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue