diff options
Diffstat (limited to 'gdb/ser-event.c')
-rw-r--r-- | gdb/ser-event.c | 220 |
1 files changed, 220 insertions, 0 deletions
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 +} |