Introduce a serial interface for select'able events
[external/binutils.git] / gdb / ser-event.c
1 /* Serial interface for a selectable event.
2    Copyright (C) 2016 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 #include "defs.h"
20 #include "ser-event.h"
21 #include "serial.h"
22 #include "common/filestuff.h"
23
24 /* On POSIX hosts, a serial_event is basically an abstraction for the
25    classical self-pipe trick.
26
27    On Windows, a serial_event is a wrapper around a native Windows
28    event object.  Because we want to interface with gdb_select, which
29    takes file descriptors, we need to wrap that Windows event object
30    in a file descriptor.  As _open_osfhandle can not be used with
31    event objects, we instead create a dummy file wrap that in a file
32    descriptor with _open_osfhandle, and pass that as selectable
33    descriptor to callers.  As Windows' gdb_select converts file
34    descriptors back to Windows handles by calling serial->wait_handle,
35    nothing ever actually waits on that file descriptor.  */
36
37 struct serial_event_state
38   {
39 #ifdef USE_WIN32API
40     /* The Windows event object, created with CreateEvent.  */
41     HANDLE event;
42 #else
43     /* The write side of the pipe.  The read side is in
44        serial->fd.  */
45     int write_fd;
46 #endif
47   };
48
49 /* Open a new serial event.  */
50
51 static int
52 serial_event_open (struct serial *scb, const char *name)
53 {
54   struct serial_event_state *state;
55
56   state = XNEW (struct serial_event_state);
57   scb->state = state;
58
59 #ifndef USE_WIN32API
60   {
61     int fds[2];
62
63     if (gdb_pipe_cloexec (fds) == -1)
64       internal_error (__FILE__, __LINE__,
65                       "creating serial event pipe failed.");
66
67     fcntl (fds[0], F_SETFL, O_NONBLOCK);
68     fcntl (fds[1], F_SETFL, O_NONBLOCK);
69
70     scb->fd = fds[0];
71     state->write_fd = fds[1];
72   }
73 #else
74   {
75     /* A dummy file object that can be wrapped in a file descriptor.
76        We don't need to store this handle because closing the file
77        descriptor automatically closes this.  */
78     HANDLE dummy_file;
79
80     /* A manual-reset event.  */
81     state->event = CreateEvent (0, TRUE, FALSE, 0);
82
83     /* The dummy file handle.  Created just so we have something
84        wrappable in a file descriptor.  */
85     dummy_file = CreateFile ("nul", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
86     scb->fd = _open_osfhandle ((intptr_t) dummy_file, 0);
87   }
88 #endif
89
90   return 0;
91 }
92
93 static void
94 serial_event_close (struct serial *scb)
95 {
96   struct serial_event_state *state = (struct serial_event_state *) scb->state;
97
98   close (scb->fd);
99 #ifndef USE_WIN32API
100   close (state->write_fd);
101 #else
102   CloseHandle (state->event);
103 #endif
104
105   scb->fd = -1;
106
107   xfree (state);
108   scb->state = NULL;
109 }
110
111 #ifdef USE_WIN32API
112
113 /* Implementation of the wait_handle method.  Returns the native
114    Windows event object handle.  */
115
116 static void
117 serial_event_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
118 {
119   struct serial_event_state *state = (struct serial_event_state *) scb->state;
120
121   *read = state->event;
122 }
123
124 #endif
125
126 /* The serial_ops for struct serial_event objects.  Note we never
127    register this serial type with serial_add_interface, because this
128    is internal implementation detail never to be used by remote
129    targets for protocol transport.  */
130
131 static const struct serial_ops serial_event_ops =
132 {
133   "event",
134   serial_event_open,
135   serial_event_close,
136   NULL, /* fdopen */
137   NULL, /* readchar */
138   NULL, /* write */
139   NULL, /* flush_output */
140   NULL, /* flush_input */
141   NULL, /* send_break */
142   NULL, /* go_raw */
143   NULL, /* get_tty_state */
144   NULL, /* copy_tty_state */
145   NULL, /* set_tty_state */
146   NULL, /* print_tty_state */
147   NULL, /* noflush_set_tty_state */
148   NULL, /* setbaudrate */
149   NULL, /* setstopbits */
150   NULL, /* setparity */
151   NULL, /* drain_output */
152   NULL, /* async */
153   NULL, /* read_prim */
154   NULL, /* write_prim */
155   NULL, /* avail */
156 #ifdef USE_WIN32API
157   serial_event_wait_handle,
158 #endif
159 };
160
161 /* See ser-event.h.  */
162
163 struct serial_event *
164 make_serial_event (void)
165 {
166   return (struct serial_event *) serial_open_ops (&serial_event_ops);
167 }
168
169 /* See ser-event.h.  */
170
171 int
172 serial_event_fd (struct serial_event *event)
173 {
174   struct serial *ser = (struct serial *) event;
175
176   return ser->fd;
177 }
178
179 /* See ser-event.h.  */
180
181 void
182 serial_event_set (struct serial_event *event)
183 {
184   struct serial *ser = (struct serial *) event;
185   struct serial_event_state *state = (struct serial_event_state *) ser->state;
186 #ifndef USE_WIN32API
187   int r;
188   char c = '+';         /* Anything.  */
189
190   do
191     {
192       r = write (state->write_fd, &c, 1);
193     }
194   while (r < 0 && errno == EINTR);
195 #else
196   SetEvent (state->event);
197 #endif
198 }
199
200 /* See ser-event.h.  */
201
202 void
203 serial_event_clear (struct serial_event *event)
204 {
205   struct serial *ser = (struct serial *) event;
206   struct serial_event_state *state = (struct serial_event_state *) ser->state;
207 #ifndef USE_WIN32API
208   int r;
209
210   do
211     {
212       char c;
213
214       r = read (ser->fd, &c, 1);
215     }
216   while (r > 0 || (r < 0 && errno == EINTR));
217 #else
218   ResetEvent (state->event);
219 #endif
220 }