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