[RFC,09/17] Introduce async-event.[ch]

Message ID 20190224165153.5062-10-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey Feb. 24, 2019, 4:51 p.m. UTC
  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 common/, but because gdbserver does not currently use it, it
seemed better, for size reasons, to split it out.

gdb/ChangeLog
2019-02-24  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.
---
 gdb/ChangeLog       |  17 +++
 gdb/Makefile.in     |   2 +
 gdb/async-event.c   | 325 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/async-event.h   |  71 ++++++++++
 gdb/event-loop.c    | 305 -----------------------------------------
 gdb/event-loop.h    |  51 ++-----
 gdb/event-top.c     |   1 +
 gdb/infrun.c        |   1 +
 gdb/record-btrace.c |   1 +
 gdb/record-full.c   |   1 +
 gdb/remote-notif.c  |   1 +
 gdb/remote.c        |   1 +
 gdb/tui/tui-win.c   |   1 +
 13 files changed, 430 insertions(+), 348 deletions(-)
 create mode 100644 gdb/async-event.c
 create mode 100644 gdb/async-event.h
  

Comments

Pedro Alves Sept. 26, 2019, 2:05 p.m. UTC | #1
On 2/24/19 4:51 PM, Tom Tromey wrote:
> 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 common/, but because gdbserver does not currently use it, it
> seemed better, for size reasons, to split it out.

Seems fine.  Going forward, I wonder whether we'll split event loop
things into more files, and whether using a name prefix like "event-loop-"
or "el-", like "el-async-event.[ch]" would help keeping things a bit
closer together.  Just a thought; not a request.

Thanks,
Pedro Alves
  
Tom Tromey Oct. 4, 2019, 10:17 p.m. UTC | #2
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> On 2/24/19 4:51 PM, Tom Tromey wrote:
>> 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 common/, but because gdbserver does not currently use it, it
>> seemed better, for size reasons, to split it out.

Pedro> Seems fine.  Going forward, I wonder whether we'll split event loop
Pedro> things into more files, and whether using a name prefix like "event-loop-"
Pedro> or "el-", like "el-async-event.[ch]" would help keeping things a bit
Pedro> closer together.  Just a thought; not a request.

I don't have plans to do anything more in this area, and I didn't feel
quite strongly enough about it to do the renaming, so I've just left it
as-is.

I somewhat wish we could remove all this code in favor of a pre-canned
event loop solution, like libevent.  Too bad dependencies are such a
pain.

Tom
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 61b0b9d01bd..c7a9cb62d10 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -926,6 +926,7 @@  COMMON_SFILES = \
 	agent.c \
 	annotate.c \
 	arch-utils.c \
+	async-event.c \
 	auto-load.c \
 	auxv.c \
 	ax-gdb.c \
@@ -1197,6 +1198,7 @@  HFILES_NO_SRCDIR = \
 	arch-utils.h \
 	arm-linux-tdep.h \
 	arm-tdep.h \
+	async-event.h \
 	auto-load.h \
 	auxv.h \
 	ax.h \
diff --git a/gdb/async-event.c b/gdb/async-event.c
new file mode 100644
index 00000000000..dd65c17468b
--- /dev/null
+++ b/gdb/async-event.c
@@ -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;
+}
diff --git a/gdb/async-event.h b/gdb/async-event.h
new file mode 100644
index 00000000000..408f7764f7c
--- /dev/null
+++ b/gdb/async-event.h
@@ -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 */
diff --git a/gdb/event-loop.c b/gdb/event-loop.c
index b9d9e7e098e..08536f57902 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -19,7 +19,6 @@ 
 
 #include "defs.h"
 #include "event-loop.h"
-#include "ser-event.h"
 
 #include <chrono>
 
@@ -34,7 +33,6 @@ 
 #include <sys/types.h>
 #include "common/gdb_sys_time.h"
 #include "common/gdb_select.h"
-#include "top.h"
 
 /* Tell create_file_handler what events we are interested in.
    This is used by the select version of the event loop.  */
@@ -92,50 +90,6 @@  typedef struct 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.
    These are the input file descriptor, and the target file
    descriptor.  We have two flavors of the notifier, one for platforms
@@ -230,61 +184,12 @@  static struct
   }
 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,
 				 gdb_client_data client_data);
-static int check_async_event_handlers (void);
 static int gdb_wait_for_event (int);
 static int update_wait_timeout (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,
    wait for something to happen (via gdb_wait_for_event), then process
    it.  Returns >0 if something was done otherwise returns <0 (this
@@ -864,216 +769,6 @@  gdb_wait_for_event (int block)
   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
    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
diff --git a/gdb/event-loop.h b/gdb/event-loop.h
index f11b008848d..16bde6474db 100644
--- a/gdb/event-loop.h
+++ b/gdb/event-loop.h
@@ -71,11 +71,7 @@ 
    Corollary tasks are the creation and deletion of event sources.  */
 
 typedef void *gdb_client_data;
-struct async_signal_handler;
-struct async_event_handler;
 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);
 
 /* Exported functions from event-loop.c */
@@ -85,54 +81,23 @@  extern int gdb_do_one_event (void);
 extern void delete_file_handler (int fd);
 extern void add_file_handler (int fd, handler_func *proc, 
 			      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, 
 			 timer_handler_func *proc, 
 			 gdb_client_data client_data);
 extern void delete_timer (int id);
 
-/* 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);
+/* Must be defined by client.  */
 
-/* Mark the handler (ASYNC_HANDLER_PTR) as NOT ready.  */
+extern void handle_event_loop_exception (const gdb_exception &);
 
-extern void clear_async_event_handler (struct async_event_handler *handler);
+/* Must be defined by client.  Returns true if any signal handler was
+   ready.  */
 
-extern void initialize_async_signal_handlers (void);
+extern int invoke_async_signal_handlers ();
 
-/* Must be defined by client.  */
+/* Must be defined by client.  Returns true if any event handler was
+   ready.  */
 
-extern void handle_event_loop_exception (const gdb_exception &);
+extern int check_async_event_handlers ();
 
 #endif /* EVENT_LOOP_H */
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 0cc144d397c..5829957e513 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -40,6 +40,7 @@ 
 #include "common/buffer.h"
 #include "ser-event.h"
 #include "common/gdb_select.h"
+#include "async-event.h"
 
 /* readline include files.  */
 #include "readline/readline.h"
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b32635fc422..0eaf1b608b6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -68,6 +68,7 @@ 
 #include "common/gdb_optional.h"
 #include "arch-utils.h"
 #include "common/scope-exit.h"
+#include "async-event.h"
 
 /* Prototypes for local functions */
 
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index dc26938f0b9..5319a1b2bb8 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -41,6 +41,7 @@ 
 #include "common/vec.h"
 #include "inferior.h"
 #include <algorithm>
+#include "async-event.h"
 
 static const target_info record_btrace_target_info = {
   "record-btrace",
diff --git a/gdb/record-full.c b/gdb/record-full.c
index ea0eddb536d..95ccc2c797e 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -38,6 +38,7 @@ 
 #include "infrun.h"
 #include "common/gdb_unlinker.h"
 #include "common/byte-vector.h"
+#include "async-event.h"
 
 #include <signal.h>
 
diff --git a/gdb/remote-notif.c b/gdb/remote-notif.c
index ae9a94d9c94..72916023420 100644
--- a/gdb/remote-notif.c
+++ b/gdb/remote-notif.c
@@ -40,6 +40,7 @@ 
 #include "inferior.h"
 #include "infrun.h"
 #include "gdbcmd.h"
+#include "async-event.h"
 
 int notif_debug = 0;
 
diff --git a/gdb/remote.c b/gdb/remote.c
index 36136e3e3ee..d6561dda61f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -76,6 +76,7 @@ 
 #include "common/environ.h"
 #include "common/byte-vector.h"
 #include <unordered_map>
+#include "async-event.h"
 
 /* The remote target.  */
 
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index a24f25928e2..fa1ee89603d 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -33,6 +33,7 @@ 
 #include "top.h"
 #include "source.h"
 #include "event-loop.h"
+#include "async-event.h"
 
 #include "tui/tui.h"
 #include "tui/tui-io.h"