--- /dev/null
+/* Serial interface for a selectable event.
+   Copyright (C) 2016 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 "ser-event.h"
+#include "serial.h"
+#include "common/filestuff.h"
+
+/* On POSIX hosts, a serial_event is basically an abstraction for the
+   classical self-pipe trick.
+
+   On Windows, a serial_event is a wrapper around a native Windows
+   event object.  Because we want to interface with gdb_select, which
+   takes file descriptors, we need to wrap that Windows event object
+   in a file descriptor.  As _open_osfhandle can not be used with
+   event objects, we instead create a dummy file wrap that in a file
+   descriptor with _open_osfhandle, and pass that as selectable
+   descriptor to callers.  As Windows' gdb_select converts file
+   descriptors back to Windows handles by calling serial->wait_handle,
+   nothing ever actually waits on that file descriptor.  */
+
+struct serial_event_state
+  {
+#ifdef USE_WIN32API
+    /* The Windows event object, created with CreateEvent.  */
+    HANDLE event;
+#else
+    /* The write side of the pipe.  The read side is in
+       serial->fd.  */
+    int write_fd;
+#endif
+  };
+
+/* Open a new serial event.  */
+
+static int
+serial_event_open (struct serial *scb, const char *name)
+{
+  struct serial_event_state *state;
+
+  state = XNEW (struct serial_event_state);
+  scb->state = state;
+
+#ifndef USE_WIN32API
+  {
+    int fds[2];
+
+    if (gdb_pipe_cloexec (fds) == -1)
+      internal_error (__FILE__, __LINE__,
+                     "creating serial event pipe failed.");
+
+    fcntl (fds[0], F_SETFL, O_NONBLOCK);
+    fcntl (fds[1], F_SETFL, O_NONBLOCK);
+
+    scb->fd = fds[0];
+    state->write_fd = fds[1];
+  }
+#else
+  {
+    /* A dummy file object that can be wrapped in a file descriptor.
+       We don't need to store this handle because closing the file
+       descriptor automatically closes this.  */
+    HANDLE dummy_file;
+
+    /* A manual-reset event.  */
+    state->event = CreateEvent (0, TRUE, FALSE, 0);
+
+    /* The dummy file handle.  Created just so we have something
+       wrappable in a file descriptor.  */
+    dummy_file = CreateFile ("nul", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+    scb->fd = _open_osfhandle ((intptr_t) dummy_file, 0);
+  }
+#endif
+
+  return 0;
+}
+
+static void
+serial_event_close (struct serial *scb)
+{
+  struct serial_event_state *state = (struct serial_event_state *) scb->state;
+
+  close (scb->fd);
+#ifndef USE_WIN32API
+  close (state->write_fd);
+#else
+  CloseHandle (state->event);
+#endif
+
+  scb->fd = -1;
+
+  xfree (state);
+  scb->state = NULL;
+}
+
+#ifdef USE_WIN32API
+
+/* Implementation of the wait_handle method.  Returns the native
+   Windows event object handle.  */
+
+static void
+serial_event_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
+{
+  struct serial_event_state *state = (struct serial_event_state *) scb->state;
+
+  *read = state->event;
+}
+
+#endif
+
+/* The serial_ops for struct serial_event objects.  Note we never
+   register this serial type with serial_add_interface, because this
+   is internal implementation detail never to be used by remote
+   targets for protocol transport.  */
+
+static const struct serial_ops serial_event_ops =
+{
+  "event",
+  serial_event_open,
+  serial_event_close,
+  NULL, /* fdopen */
+  NULL, /* readchar */
+  NULL, /* write */
+  NULL, /* flush_output */
+  NULL, /* flush_input */
+  NULL, /* send_break */
+  NULL, /* go_raw */
+  NULL, /* get_tty_state */
+  NULL, /* copy_tty_state */
+  NULL, /* set_tty_state */
+  NULL, /* print_tty_state */
+  NULL, /* noflush_set_tty_state */
+  NULL, /* setbaudrate */
+  NULL, /* setstopbits */
+  NULL, /* setparity */
+  NULL, /* drain_output */
+  NULL, /* async */
+  NULL, /* read_prim */
+  NULL, /* write_prim */
+  NULL, /* avail */
+#ifdef USE_WIN32API
+  serial_event_wait_handle,
+#endif
+};
+
+/* See ser-event.h.  */
+
+struct serial_event *
+make_serial_event (void)
+{
+  return (struct serial_event *) serial_open_ops (&serial_event_ops);
+}
+
+/* See ser-event.h.  */
+
+int
+serial_event_fd (struct serial_event *event)
+{
+  struct serial *ser = (struct serial *) event;
+
+  return ser->fd;
+}
+
+/* See ser-event.h.  */
+
+void
+serial_event_set (struct serial_event *event)
+{
+  struct serial *ser = (struct serial *) event;
+  struct serial_event_state *state = (struct serial_event_state *) ser->state;
+#ifndef USE_WIN32API
+  int r;
+  char c = '+';                /* Anything.  */
+
+  do
+    {
+      r = write (state->write_fd, &c, 1);
+    }
+  while (r < 0 && errno == EINTR);
+#else
+  SetEvent (state->event);
+#endif
+}
+
+/* See ser-event.h.  */
+
+void
+serial_event_clear (struct serial_event *event)
+{
+  struct serial *ser = (struct serial *) event;
+  struct serial_event_state *state = (struct serial_event_state *) ser->state;
+#ifndef USE_WIN32API
+  int r;
+
+  do
+    {
+      char c;
+
+      r = read (ser->fd, &c, 1);
+    }
+  while (r > 0 || (r < 0 && errno == EINTR));
+#else
+  ResetEvent (state->event);
+#endif
+}
 
--- /dev/null
+/* Serial interface for a selectable event.
+   Copyright (C) 2016 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 SER_EVENT_H
+#define SER_EVENT_H
+
+/* This is used to be able to signal the event loop (or any other
+   select/poll) of events, in a race-free manner.
+
+   For example, a signal handler can defer non-async-signal-safe work
+   to the event loop, by having the signal handler set a struct
+   serial_event object, and having the event loop wait for that same
+   object to the readable.  Once readable, the event loop breaks out
+   of select/poll and calls a registered callback that does the
+   deferred work.  */
+
+struct serial_event;
+
+/* Make a new serial_event object.  */
+struct serial_event *make_serial_event (void);
+
+/* Return the FD that can be used by select/poll to wait for the
+   event.  The only valid operation on this object is to wait until it
+   is readable.  */
+extern int serial_event_fd (struct serial_event *event);
+
+/* Set the event.  This signals the file descriptor returned by
+   serial_event_fd as readable.  */
+extern void serial_event_set (struct serial_event *event);
+
+/* Clear the event.  The file descriptor returned by serial_event_fd
+   is not longer readable after this, until a new serial_event_set
+   call is made.  */
+extern void serial_event_clear (struct serial_event *event);
+
+#endif
 
   return NULL;
 }
 
+/* Create a new serial for OPS.  */
+
+static struct serial *
+new_serial (const struct serial_ops *ops)
+{
+  struct serial *scb;
+
+  scb = XCNEW (struct serial);
+
+  scb->ops = ops;
+
+  scb->bufp = scb->buf;
+  scb->error_fd = -1;
+  scb->refcnt = 1;
+
+  return scb;
+}
+
+static struct serial *serial_open_ops_1 (const struct serial_ops *ops,
+                                        const char *open_name);
+
 /* Open up a device or a network socket, depending upon the syntax of NAME.  */
 
 struct serial *
   if (!ops)
     return NULL;
 
-  scb = XNEW (struct serial);
+  return serial_open_ops_1 (ops, open_name);
+}
 
-  scb->ops = ops;
+/* Open up a serial for OPS, passing OPEN_NAME to the open method.  */
 
-  scb->bufcnt = 0;
-  scb->bufp = scb->buf;
-  scb->error_fd = -1;
-  scb->refcnt = 1;
+static struct serial *
+serial_open_ops_1 (const struct serial_ops *ops, const char *open_name)
+{
+  struct serial *scb;
+
+  scb = new_serial (ops);
 
   /* `...->open (...)' would get expanded by the open(2) syscall macro.  */
   if ((*scb->ops->open) (scb, open_name))
     }
 
   scb->next = scb_base;
-  scb->debug_p = 0;
-  scb->async_state = 0;
-  scb->async_handler = NULL;
-  scb->async_context = NULL;
   scb_base = scb;
 
   if (serial_logfile != NULL)
   return scb;
 }
 
+/* See serial.h.  */
+
+struct serial *
+serial_open_ops (const struct serial_ops *ops)
+{
+  return serial_open_ops_1 (ops, NULL);
+}
+
 /* Open a new serial stream using a file handle, using serial
    interface ops OPS.  */
 
   if (!ops)
     return NULL;
 
-  scb = XCNEW (struct serial);
-
-  scb->ops = ops;
-
-  scb->bufcnt = 0;
-  scb->bufp = scb->buf;
-  scb->error_fd = -1;
-  scb->refcnt = 1;
+  scb = new_serial (ops);
 
   scb->next = scb_base;
-  scb->debug_p = 0;
-  scb->async_state = 0;
-  scb->async_handler = NULL;
-  scb->async_context = NULL;
   scb_base = scb;
 
   if ((ops->fdopen) != NULL)