aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog14
-rw-r--r--gdb/Makefile.in6
-rw-r--r--gdb/ser-event.c220
-rw-r--r--gdb/ser-event.h51
-rw-r--r--gdb/serial.c61
-rw-r--r--gdb/serial.h7
6 files changed, 334 insertions, 25 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b77e5e4..55fd901 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,19 @@
2016-04-12 Pedro Alves <palves@redhat.com>
+ * Makefile.in (SFILES): Add ser-event.c.
+ (HFILES_NO_SRCDIR): Add ser-event.h.
+ (COMMON_OBS): Add ser-event.o.
+ * ser-event.c, ser-event.h: New files.
+ * serial.c (new_serial): New function, factored out from
+ (serial_fdopen_ops): ... this.
+ (serial_open_ops_1): New function, factored out from
+ (serial_open): ... this.
+ (serial_open_ops): New function.
+ * serial.h (struct serial): Forware declare.
+ (serial_open_ops): New declaration.
+
+2016-04-12 Pedro Alves <palves@redhat.com>
+
* serial.c (serial_open, serial_fdopen_ops, do_serial_close):
Remove references to name.
* serial.h (struct serial) <name>: Delete.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ccd5c23..2af78a5 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -870,7 +870,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
prologue-value.c psymtab.c \
regcache.c reggroups.c remote.c remote-fileio.c remote-notif.c reverse.c \
sentinel-frame.c \
- serial.c ser-base.c ser-unix.c skip.c \
+ serial.c ser-base.c ser-unix.c ser-event.c skip.c \
solib.c solib-target.c source.c \
stabsread.c stack.c probe.c stap-probe.c std-regs.c \
symfile.c symfile-debug.c symfile-mem.c symmisc.c symtab.c \
@@ -987,7 +987,7 @@ common/common-exceptions.h target/target.h common/symbol.h \
common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
-tid-parse.h
+tid-parse.h ser-event.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -1065,7 +1065,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
ada-typeprint.o c-typeprint.o f-typeprint.o m2-typeprint.o \
ada-valprint.o c-valprint.o cp-valprint.o d-valprint.o f-valprint.o \
m2-valprint.o \
- serial.o mdebugread.o top.o utils.o \
+ ser-event.o serial.o mdebugread.o top.o utils.o \
ui-file.o \
user-regs.o \
frame.o frame-unwind.o doublest.o \
diff --git a/gdb/ser-event.c b/gdb/ser-event.c
new file mode 100644
index 0000000..4851672
--- /dev/null
+++ b/gdb/ser-event.c
@@ -0,0 +1,220 @@
+/* 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
+}
diff --git a/gdb/ser-event.h b/gdb/ser-event.h
new file mode 100644
index 0000000..b6654c4
--- /dev/null
+++ b/gdb/ser-event.h
@@ -0,0 +1,51 @@
+/* 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
diff --git a/gdb/serial.c b/gdb/serial.c
index 5d242b9..a95f85e 100644
--- a/gdb/serial.c
+++ b/gdb/serial.c
@@ -179,6 +179,27 @@ serial_for_fd (int fd)
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 *
@@ -210,14 +231,17 @@ serial_open (const char *name)
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))
@@ -227,10 +251,6 @@ serial_open (const char *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)
@@ -243,6 +263,14 @@ serial_open (const char *name)
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. */
@@ -261,20 +289,9 @@ serial_fdopen_ops (const int fd, const struct serial_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)
diff --git a/gdb/serial.h b/gdb/serial.h
index b339f66..10b0643 100644
--- a/gdb/serial.h
+++ b/gdb/serial.h
@@ -34,6 +34,9 @@ struct ui_file;
typedef void *serial_ttystate;
struct serial;
+struct serial_ops;
+
+/* Create a new serial for OPS. The new serial is not opened. */
/* Try to open NAME. Returns a new `struct serial *' on success, NULL
on failure. The new serial object has a reference count of 1.
@@ -44,6 +47,10 @@ struct serial;
extern struct serial *serial_open (const char *name);
+/* Open a new serial stream using OPS. */
+
+extern struct serial *serial_open_ops (const struct serial_ops *ops);
+
/* Returns true if SCB is open. */
extern int serial_is_open (struct serial *scb);