Home | History | Annotate | Line # | Download | only in gdb
      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