xref: /netbsd-src/external/gpl3/gdb/dist/gdb/ser-event.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
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
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
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
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 *
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
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
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
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