[RFC,1/7] gdbsupport: Add an event-pipe class.

Message ID 20210607170932.3954-2-jhb@FreeBSD.org
State New
Headers show
Series
  • FreeBSD target async mode and related refactoring
Related show

Commit Message

John Baldwin June 7, 2021, 5:09 p.m.
This pulls out the implementation of an event pipe used to implement
target async support in both linux-low.cc (gdbserver) and linux-nat.c
(gdb).

gdbsupport/ChangeLog:

	* Makefile.in: Rebuild.
	* Makefile.am (libgdbsupport_a_SOURCES): Add event-pipe.cc.
	* event-pipe.h: New file.
	* event-pipe.cc: New file.
---
 gdbsupport/ChangeLog     |   7 +++
 gdbsupport/Makefile.am   |   1 +
 gdbsupport/Makefile.in   |  21 ++++----
 gdbsupport/event-pipe.cc | 100 +++++++++++++++++++++++++++++++++++++++
 gdbsupport/event-pipe.h  |  55 +++++++++++++++++++++
 5 files changed, 175 insertions(+), 9 deletions(-)
 create mode 100644 gdbsupport/event-pipe.cc
 create mode 100644 gdbsupport/event-pipe.h

-- 
2.31.1

Comments

Hi,

I have just few style related remarks.

On Mon, Jun 07, 2021 at 10:09:26AM -0700, John Baldwin wrote:
> This pulls out the implementation of an event pipe used to implement

> target async support in both linux-low.cc (gdbserver) and linux-nat.c

> (gdb).

> 

> gdbsupport/ChangeLog:

> 

> 	* Makefile.in: Rebuild.

> 	* Makefile.am (libgdbsupport_a_SOURCES): Add event-pipe.cc.

> 	* event-pipe.h: New file.

> 	* event-pipe.cc: New file.

> ---

>  gdbsupport/ChangeLog     |   7 +++

>  gdbsupport/Makefile.am   |   1 +

>  gdbsupport/Makefile.in   |  21 ++++----

>  gdbsupport/event-pipe.cc | 100 +++++++++++++++++++++++++++++++++++++++

>  gdbsupport/event-pipe.h  |  55 +++++++++++++++++++++

>  5 files changed, 175 insertions(+), 9 deletions(-)

>  create mode 100644 gdbsupport/event-pipe.cc

>  create mode 100644 gdbsupport/event-pipe.h

> 

> diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog

> index b790a97230..c953d87fbf 100644

> --- a/gdbsupport/ChangeLog

> +++ b/gdbsupport/ChangeLog

> @@ -1,3 +1,10 @@

> +2021-06-04  John Baldwin  <jhb@FreeBSD.org>

> +

> +	* Makefile.in: Rebuild.

> +	* Makefile.am (libgdbsupport_a_SOURCES): Add event-pipe.cc.

> +	* event-pipe.h: New file.

> +	* event-pipe.cc: New file.

> +

>  2021-05-17  Andrew Burgess  <andrew.burgess@embecosm.com>

>  

>  	* .dir-locals.el: Set sentence-end-double-space for all modes, and

> diff --git a/gdbsupport/Makefile.am b/gdbsupport/Makefile.am

> index 6d4678c8c9..a7d78f8c26 100644

> --- a/gdbsupport/Makefile.am

> +++ b/gdbsupport/Makefile.am

> @@ -48,6 +48,7 @@ libgdbsupport_a_SOURCES = \

>      environ.cc \

>      errors.cc \

>      event-loop.cc \

> +    event-pipe.cc \

>      fileio.cc \

>      filestuff.cc \

>      format.cc \

> diff --git a/gdbsupport/Makefile.in b/gdbsupport/Makefile.in

> index d7f2d4914b..7ff5531998 100644

> --- a/gdbsupport/Makefile.in

> +++ b/gdbsupport/Makefile.in

> @@ -150,15 +150,16 @@ am_libgdbsupport_a_OBJECTS = agent.$(OBJEXT) btrace-common.$(OBJEXT) \

>  	common-exceptions.$(OBJEXT) common-inferior.$(OBJEXT) \

>  	common-regcache.$(OBJEXT) common-utils.$(OBJEXT) \

>  	environ.$(OBJEXT) errors.$(OBJEXT) event-loop.$(OBJEXT) \

> -	fileio.$(OBJEXT) filestuff.$(OBJEXT) format.$(OBJEXT) \

> -	gdb-dlfcn.$(OBJEXT) gdb_tilde_expand.$(OBJEXT) \

> -	gdb_wait.$(OBJEXT) gdb_vecs.$(OBJEXT) job-control.$(OBJEXT) \

> -	netstuff.$(OBJEXT) new-op.$(OBJEXT) pathstuff.$(OBJEXT) \

> -	print-utils.$(OBJEXT) ptid.$(OBJEXT) rsp-low.$(OBJEXT) \

> -	run-time-clock.$(OBJEXT) safe-strerror.$(OBJEXT) \

> -	scoped_mmap.$(OBJEXT) search.$(OBJEXT) signals.$(OBJEXT) \

> -	signals-state-save-restore.$(OBJEXT) tdesc.$(OBJEXT) \

> -	thread-pool.$(OBJEXT) xml-utils.$(OBJEXT) $(am__objects_1)

> +	event-pipe.$(OBJEXT) fileio.$(OBJEXT) filestuff.$(OBJEXT) \

> +	format.$(OBJEXT) gdb-dlfcn.$(OBJEXT) \

> +	gdb_tilde_expand.$(OBJEXT) gdb_wait.$(OBJEXT) \

> +	gdb_vecs.$(OBJEXT) job-control.$(OBJEXT) netstuff.$(OBJEXT) \

> +	new-op.$(OBJEXT) pathstuff.$(OBJEXT) print-utils.$(OBJEXT) \

> +	ptid.$(OBJEXT) rsp-low.$(OBJEXT) run-time-clock.$(OBJEXT) \

> +	safe-strerror.$(OBJEXT) scoped_mmap.$(OBJEXT) search.$(OBJEXT) \

> +	signals.$(OBJEXT) signals-state-save-restore.$(OBJEXT) \

> +	tdesc.$(OBJEXT) thread-pool.$(OBJEXT) xml-utils.$(OBJEXT) \

> +	$(am__objects_1)

>  libgdbsupport_a_OBJECTS = $(am_libgdbsupport_a_OBJECTS)

>  AM_V_P = $(am__v_P_@AM_V@)

>  am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)

> @@ -371,6 +372,7 @@ libgdbsupport_a_SOURCES = \

>      environ.cc \

>      errors.cc \

>      event-loop.cc \

> +    event-pipe.cc \

>      fileio.cc \

>      filestuff.cc \

>      format.cc \

> @@ -476,6 +478,7 @@ distclean-compile:

>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/environ.Po@am__quote@

>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Po@am__quote@

>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-loop.Po@am__quote@

> +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-pipe.Po@am__quote@

>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileio.Po@am__quote@

>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filestuff.Po@am__quote@

>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Po@am__quote@

> diff --git a/gdbsupport/event-pipe.cc b/gdbsupport/event-pipe.cc

> new file mode 100644

> index 0000000000..b701be0b5a

> --- /dev/null

> +++ b/gdbsupport/event-pipe.cc

> @@ -0,0 +1,100 @@

> +/* Event pipe for GDB, the GNU debugger.

> +

> +   Copyright (C) 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 "gdbsupport/common-defs.h"

> +#include "gdbsupport/event-pipe.h"

> +#include "gdbsupport/filestuff.h"

> +

> +#include <errno.h>

> +#include <fcntl.h>

> +#include <unistd.h>

> +

> +event_pipe::~event_pipe ()

> +{

> +  if (active ())

> +    close ();

> +}

> +

> +/* Create a new pipe.  */

> +

> +bool

> +event_pipe::open ()

> +{

> +  if (fds[0] != -1)

> +    return false;

> +

> +  if (gdb_pipe_cloexec (fds) == -1)

> +    return false;

> +

> +  if (fcntl (fds[0], F_SETFL, O_NONBLOCK) == -1 ||

> +      fcntl (fds[1], F_SETFL, O_NONBLOCK) == -1) {

> +    close ();

> +    return false;

> +  }

> +


According to coding standards, this should be written more like:

    if (fcntl (fds[0], F_SETFL, O_NONBLOCK) == -1
        || fcntl (fds[1], F_SETFL, O_NONBLOCK) == -1)
      {
        close ();
        return false;
      }

> +  return true;

> +}

> +

> +void

> +event_pipe::close ()

> +{

> +  ::close (fds[0]);

> +  ::close (fds[1]);

> +  fds[0] = -1;

> +  fds[1] = -1;

> +}

> +

> +/* Get rid of any pending events in the pipe.  */

> +

> +void

> +event_pipe::flush ()

> +{

> +  int ret;

> +  char buf;

> +

> +  do

> +    {

> +      ret = read (fds[0], &buf, 1);

> +    }

> +  while (ret >= 0 || (ret == -1 && errno == EINTR));

> +}

> +

> +/* Put something (anything, doesn't matter what, or how much) in event

> +   pipe, so that the select/poll in the event-loop realizes we have

> +   something to process.  */

> +

> +void

> +event_pipe::mark ()

> +{

> +  int ret;

> +

> +  /* It doesn't really matter what the pipe contains, as long we end

> +     up with something in it.  Might as well flush the previous

> +     left-overs.  */

> +  flush ();

> +

> +  do

> +    {

> +      ret = write (fds[1], "+", 1);

> +    }

> +  while (ret == -1 && errno == EINTR);

> +

> +  /* Ignore EAGAIN.  If the pipe is full, the event loop will already

> +     be awakened anyway.  */

> +}

> diff --git a/gdbsupport/event-pipe.h b/gdbsupport/event-pipe.h

> new file mode 100644

> index 0000000000..1717ea6790

> --- /dev/null

> +++ b/gdbsupport/event-pipe.h

> @@ -0,0 +1,55 @@

> +/* Event pipe for GDB, the GNU debugger.

> +

> +   Copyright (C) 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/>.  */

> +

> +#ifndef COMMON_EVENT_PIPE_H

> +#define COMMON_EVENT_PIPE_H

> +

> +/* An event pipe used as a waitable file in the event loop in place of

> +   some other event not associated with a file descriptor.  */

> +

> +class event_pipe

> +{

> +public:

> +  event_pipe() = default;

> +  ~event_pipe();

> +

> +  /* Create a new pipe.  */

> +  bool open ();

> +

> +  /* Close the pipe.  */

> +  void close ();

> +

> +  /* True if the event pipe has been initialized.  */

> +  bool active () const { return fds[0] != -1; }

> +

> +  /* The file descriptor of the waitable file to use in the event

> +     loop.  */

> +  int event_fd () const { return fds[0]; }

> +

> +  /* Flush the event pipe.  */

> +  void flush ();

> +

> +  /* Put something in the pipe, so the event loop wakes up.  */

> +  void mark ();

> +private:

> +  int fds[2] = { -1, -1 };


Member names are usually prefixed with `m_`, so I guess this could be
renamed `m_fds`.

Best,
Lancelot.

> +};

> +

> +#endif /* COMMON_EVENT_PIPE_H */

> +

> -- 

> 2.31.1

>
Pedro Alves June 27, 2021, 4:12 p.m. | #2
On 2021-06-07 6:09 p.m., John Baldwin wrote:
> This pulls out the implementation of an event pipe used to implement

> target async support in both linux-low.cc (gdbserver) and linux-nat.c

> (gdb).

> 


Seems like a good idea, thanks.

> +  /* Create a new pipe.  */

> +  bool open ();

> +

> +  /* Close the pipe.  */

> +  void close ();

> +

> +  /* True if the event pipe has been initialized.  */

> +  bool active () const { return fds[0] != -1; }

> +


Did you consider "is_open" instead of "active"?  I think reading "active()" at the call
sites can make one wonder whether "active" is a different state from being
open, like e.g., the pipe is open but not registered in the event loop.

> diff --git a/gdbsupport/event-pipe.h b/gdbsupport/event-pipe.h

> new file mode 100644

> index 0000000000..1717ea6790

> --- /dev/null

> +++ b/gdbsupport/event-pipe.h

> @@ -0,0 +1,55 @@

> +/* Event pipe for GDB, the GNU debugger.

> +

> +   Copyright (C) 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/>.  */

> +

> +#ifndef COMMON_EVENT_PIPE_H

> +#define COMMON_EVENT_PIPE_H

> +

> +/* An event pipe used as a waitable file in the event loop in place of

> +   some other event not associated with a file descriptor.  */


Note this comment can be a little bit unclear given we also have
create_async_event_handler / mark_async_event_handler, for events not associated
with a file descriptor.

We need to use a pipe iff we need to wake up the select/poll in the event loop
from a signal handler, otherwise we can use the cheaper mark_async_event_handler
from mainline code.

Maybe mention in the comment that this is used for implementing the well-known
self-pipe trick?
John Baldwin July 12, 2021, 4:07 p.m. | #3
On 6/27/21 9:12 AM, Pedro Alves wrote:
> On 2021-06-07 6:09 p.m., John Baldwin wrote:

>> This pulls out the implementation of an event pipe used to implement

>> target async support in both linux-low.cc (gdbserver) and linux-nat.c

>> (gdb).

>>

> 

> Seems like a good idea, thanks.

> 

>> +  /* Create a new pipe.  */

>> +  bool open ();

>> +

>> +  /* Close the pipe.  */

>> +  void close ();

>> +

>> +  /* True if the event pipe has been initialized.  */

>> +  bool active () const { return fds[0] != -1; }

>> +

> 

> Did you consider "is_open" instead of "active"?  I think reading "active()" at the call

> sites can make one wonder whether "active" is a different state from being

> open, like e.g., the pipe is open but not registered in the event loop.


Hmmm, I hadn't considered is_open.  I think was just going off the names of the existing
macros in the Linux targets, but I prefer is_open and will switch to that.

>> diff --git a/gdbsupport/event-pipe.h b/gdbsupport/event-pipe.h

>> new file mode 100644

>> index 0000000000..1717ea6790

>> --- /dev/null

>> +++ b/gdbsupport/event-pipe.h

>> @@ -0,0 +1,55 @@

>> +/* Event pipe for GDB, the GNU debugger.

>> +

>> +   Copyright (C) 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/>.  */

>> +

>> +#ifndef COMMON_EVENT_PIPE_H

>> +#define COMMON_EVENT_PIPE_H

>> +

>> +/* An event pipe used as a waitable file in the event loop in place of

>> +   some other event not associated with a file descriptor.  */

> 

> Note this comment can be a little bit unclear given we also have

> create_async_event_handler / mark_async_event_handler, for events not associated

> with a file descriptor.

> 

> We need to use a pipe iff we need to wake up the select/poll in the event loop

> from a signal handler, otherwise we can use the cheaper mark_async_event_handler

> from mainline code.

> 

> Maybe mention in the comment that this is used for implementing the well-known

> self-pipe trick?


Yeah, I wanted to find a way to mention that anyway, and these are good points.
Here is what I came up with:

/* An event pipe used as a waitable file in the event loop in place of
    some other event associated with a signal.  The handler for the
    signal marks the event pipe to force a wakeup in the event loop.
    This uses the well-known self-pipe trick.  */

-- 
John Baldwin
Pedro Alves July 13, 2021, 12:27 p.m. | #4
On 2021-07-12 5:07 p.m., John Baldwin wrote:
> On 6/27/21 9:12 AM, Pedro Alves wrote:


>>> +/* An event pipe used as a waitable file in the event loop in place of

>>> +   some other event not associated with a file descriptor.  */

>>

>> Note this comment can be a little bit unclear given we also have

>> create_async_event_handler / mark_async_event_handler, for events not associated

>> with a file descriptor.

>>

>> We need to use a pipe iff we need to wake up the select/poll in the event loop

>> from a signal handler, otherwise we can use the cheaper mark_async_event_handler

>> from mainline code.

>>

>> Maybe mention in the comment that this is used for implementing the well-known

>> self-pipe trick?

> 

> Yeah, I wanted to find a way to mention that anyway, and these are good points.

> Here is what I came up with:

> 

> /* An event pipe used as a waitable file in the event loop in place of

>    some other event associated with a signal.  The handler for the

>    signal marks the event pipe to force a wakeup in the event loop.

>    This uses the well-known self-pipe trick.  */

> 


LGTM.

Patch

diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog
index b790a97230..c953d87fbf 100644
--- a/gdbsupport/ChangeLog
+++ b/gdbsupport/ChangeLog
@@ -1,3 +1,10 @@ 
+2021-06-04  John Baldwin  <jhb@FreeBSD.org>
+
+	* Makefile.in: Rebuild.
+	* Makefile.am (libgdbsupport_a_SOURCES): Add event-pipe.cc.
+	* event-pipe.h: New file.
+	* event-pipe.cc: New file.
+
 2021-05-17  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* .dir-locals.el: Set sentence-end-double-space for all modes, and
diff --git a/gdbsupport/Makefile.am b/gdbsupport/Makefile.am
index 6d4678c8c9..a7d78f8c26 100644
--- a/gdbsupport/Makefile.am
+++ b/gdbsupport/Makefile.am
@@ -48,6 +48,7 @@  libgdbsupport_a_SOURCES = \
     environ.cc \
     errors.cc \
     event-loop.cc \
+    event-pipe.cc \
     fileio.cc \
     filestuff.cc \
     format.cc \
diff --git a/gdbsupport/Makefile.in b/gdbsupport/Makefile.in
index d7f2d4914b..7ff5531998 100644
--- a/gdbsupport/Makefile.in
+++ b/gdbsupport/Makefile.in
@@ -150,15 +150,16 @@  am_libgdbsupport_a_OBJECTS = agent.$(OBJEXT) btrace-common.$(OBJEXT) \
 	common-exceptions.$(OBJEXT) common-inferior.$(OBJEXT) \
 	common-regcache.$(OBJEXT) common-utils.$(OBJEXT) \
 	environ.$(OBJEXT) errors.$(OBJEXT) event-loop.$(OBJEXT) \
-	fileio.$(OBJEXT) filestuff.$(OBJEXT) format.$(OBJEXT) \
-	gdb-dlfcn.$(OBJEXT) gdb_tilde_expand.$(OBJEXT) \
-	gdb_wait.$(OBJEXT) gdb_vecs.$(OBJEXT) job-control.$(OBJEXT) \
-	netstuff.$(OBJEXT) new-op.$(OBJEXT) pathstuff.$(OBJEXT) \
-	print-utils.$(OBJEXT) ptid.$(OBJEXT) rsp-low.$(OBJEXT) \
-	run-time-clock.$(OBJEXT) safe-strerror.$(OBJEXT) \
-	scoped_mmap.$(OBJEXT) search.$(OBJEXT) signals.$(OBJEXT) \
-	signals-state-save-restore.$(OBJEXT) tdesc.$(OBJEXT) \
-	thread-pool.$(OBJEXT) xml-utils.$(OBJEXT) $(am__objects_1)
+	event-pipe.$(OBJEXT) fileio.$(OBJEXT) filestuff.$(OBJEXT) \
+	format.$(OBJEXT) gdb-dlfcn.$(OBJEXT) \
+	gdb_tilde_expand.$(OBJEXT) gdb_wait.$(OBJEXT) \
+	gdb_vecs.$(OBJEXT) job-control.$(OBJEXT) netstuff.$(OBJEXT) \
+	new-op.$(OBJEXT) pathstuff.$(OBJEXT) print-utils.$(OBJEXT) \
+	ptid.$(OBJEXT) rsp-low.$(OBJEXT) run-time-clock.$(OBJEXT) \
+	safe-strerror.$(OBJEXT) scoped_mmap.$(OBJEXT) search.$(OBJEXT) \
+	signals.$(OBJEXT) signals-state-save-restore.$(OBJEXT) \
+	tdesc.$(OBJEXT) thread-pool.$(OBJEXT) xml-utils.$(OBJEXT) \
+	$(am__objects_1)
 libgdbsupport_a_OBJECTS = $(am_libgdbsupport_a_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -371,6 +372,7 @@  libgdbsupport_a_SOURCES = \
     environ.cc \
     errors.cc \
     event-loop.cc \
+    event-pipe.cc \
     fileio.cc \
     filestuff.cc \
     format.cc \
@@ -476,6 +478,7 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/environ.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-loop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-pipe.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileio.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filestuff.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Po@am__quote@
diff --git a/gdbsupport/event-pipe.cc b/gdbsupport/event-pipe.cc
new file mode 100644
index 0000000000..b701be0b5a
--- /dev/null
+++ b/gdbsupport/event-pipe.cc
@@ -0,0 +1,100 @@ 
+/* Event pipe for GDB, the GNU debugger.
+
+   Copyright (C) 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 "gdbsupport/common-defs.h"
+#include "gdbsupport/event-pipe.h"
+#include "gdbsupport/filestuff.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+event_pipe::~event_pipe ()
+{
+  if (active ())
+    close ();
+}
+
+/* Create a new pipe.  */
+
+bool
+event_pipe::open ()
+{
+  if (fds[0] != -1)
+    return false;
+
+  if (gdb_pipe_cloexec (fds) == -1)
+    return false;
+
+  if (fcntl (fds[0], F_SETFL, O_NONBLOCK) == -1 ||
+      fcntl (fds[1], F_SETFL, O_NONBLOCK) == -1) {
+    close ();
+    return false;
+  }
+
+  return true;
+}
+
+void
+event_pipe::close ()
+{
+  ::close (fds[0]);
+  ::close (fds[1]);
+  fds[0] = -1;
+  fds[1] = -1;
+}
+
+/* Get rid of any pending events in the pipe.  */
+
+void
+event_pipe::flush ()
+{
+  int ret;
+  char buf;
+
+  do
+    {
+      ret = read (fds[0], &buf, 1);
+    }
+  while (ret >= 0 || (ret == -1 && errno == EINTR));
+}
+
+/* Put something (anything, doesn't matter what, or how much) in event
+   pipe, so that the select/poll in the event-loop realizes we have
+   something to process.  */
+
+void
+event_pipe::mark ()
+{
+  int ret;
+
+  /* It doesn't really matter what the pipe contains, as long we end
+     up with something in it.  Might as well flush the previous
+     left-overs.  */
+  flush ();
+
+  do
+    {
+      ret = write (fds[1], "+", 1);
+    }
+  while (ret == -1 && errno == EINTR);
+
+  /* Ignore EAGAIN.  If the pipe is full, the event loop will already
+     be awakened anyway.  */
+}
diff --git a/gdbsupport/event-pipe.h b/gdbsupport/event-pipe.h
new file mode 100644
index 0000000000..1717ea6790
--- /dev/null
+++ b/gdbsupport/event-pipe.h
@@ -0,0 +1,55 @@ 
+/* Event pipe for GDB, the GNU debugger.
+
+   Copyright (C) 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/>.  */
+
+#ifndef COMMON_EVENT_PIPE_H
+#define COMMON_EVENT_PIPE_H
+
+/* An event pipe used as a waitable file in the event loop in place of
+   some other event not associated with a file descriptor.  */
+
+class event_pipe
+{
+public:
+  event_pipe() = default;
+  ~event_pipe();
+
+  /* Create a new pipe.  */
+  bool open ();
+
+  /* Close the pipe.  */
+  void close ();
+
+  /* True if the event pipe has been initialized.  */
+  bool active () const { return fds[0] != -1; }
+
+  /* The file descriptor of the waitable file to use in the event
+     loop.  */
+  int event_fd () const { return fds[0]; }
+
+  /* Flush the event pipe.  */
+  void flush ();
+
+  /* Put something in the pipe, so the event loop wakes up.  */
+  void mark ();
+private:
+  int fds[2] = { -1, -1 };
+};
+
+#endif /* COMMON_EVENT_PIPE_H */
+