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