Re: Enable --build-id for moxie-elf-ld
[deliverable/binutils-gdb.git] / gdb / ser-base.c
index 2f12dfcdc172fc1a0c1e550473a12b24145fa431..f7e76ce575096b1d0864f55c92db83e5f455a1b6 100644 (file)
@@ -1,7 +1,6 @@
 /* Generic serial interface functions.
 
-   Copyright (C) 1992-1996, 1998-2001, 2003-2012 Free Software
-   Foundation, Inc.
+   Copyright (C) 1992-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -24,8 +23,7 @@
 #include "event-loop.h"
 
 #include "gdb_select.h"
-#include "gdb_string.h"
-#include <sys/time.h>
+#include "gdbsupport/gdb_sys_time.h"
 #ifdef USE_WIN32API
 #include <winsock2.h>
 #endif
@@ -48,7 +46,7 @@ enum {
   /* >= 0 (TIMER_SCHEDULED) */
   /* The ID of the currently scheduled timer event.  This state is
      rarely encountered.  Timer events are one-off so as soon as the
-     event is delivered the state is shanged to NOTHING_SCHEDULED.  */
+     event is delivered the state is changed to NOTHING_SCHEDULED.  */
   FD_SCHEDULED = -1,
   /* The fd_event() handler is scheduled.  It is called when ever the
      file descriptor becomes ready.  */
@@ -155,7 +153,7 @@ run_async_handler_and_reschedule (struct serial *scb)
 static void
 fd_event (int error, void *context)
 {
-  struct serial *scb = context;
+  struct serial *scb = (struct serial *) context;
   if (error != 0)
     {
       scb->bufcnt = SERIAL_ERROR;
@@ -166,7 +164,13 @@ fd_event (int error, void *context)
          pull characters out of the buffer.  See also
          generic_readchar().  */
       int nr;
-      nr = scb->ops->read_prim (scb, BUFSIZ);
+
+      do
+       {
+         nr = scb->ops->read_prim (scb, BUFSIZ);
+       }
+      while (nr < 0 && errno == EINTR);
+
       if (nr == 0)
        {
          scb->bufcnt = SERIAL_EOF;
@@ -187,12 +191,12 @@ fd_event (int error, void *context)
 /* PUSH_EVENT: The input FIFO is non-empty (or there is a pending
    error).  Nag the client until all the data has been read.  In the
    case of errors, the client will need to close or de-async the
-   device before naging stops.  */
+   device before nagging stops.  */
 
 static void
 push_event (void *context)
 {
-  struct serial *scb = context;
+  struct serial *scb = (struct serial *) context;
 
   scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */
   run_async_handler_and_reschedule (scb);
@@ -201,6 +205,11 @@ push_event (void *context)
 /* Wait for input on scb, with timeout seconds.  Returns 0 on success,
    otherwise SERIAL_TIMEOUT or SERIAL_ERROR.  */
 
+/* NOTE: Some of the code below is dead.  The only possible values of
+   the TIMEOUT parameter are ONE and ZERO.  OTOH, we should probably
+   get rid of the deprecated_ui_loop_hook call in do_ser_base_readchar
+   instead and support infinite time outs here.  */
+
 static int
 ser_base_wait_for (struct serial *scb, int timeout)
 {
@@ -209,6 +218,7 @@ ser_base_wait_for (struct serial *scb, int timeout)
       int numfds;
       struct timeval tv;
       fd_set readfds, exceptfds;
+      int nfds;
 
       /* NOTE: Some OS's can scramble the READFDS when the select()
          call fails (ex the kernel with Red Hat 5.2).  Initialize all
@@ -222,10 +232,13 @@ ser_base_wait_for (struct serial *scb, int timeout)
       FD_SET (scb->fd, &readfds);
       FD_SET (scb->fd, &exceptfds);
 
+      QUIT;
+
+      nfds = scb->fd + 1;
       if (timeout >= 0)
-       numfds = gdb_select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
+       numfds = interruptible_select (nfds, &readfds, 0, &exceptfds, &tv);
       else
-       numfds = gdb_select (scb->fd + 1, &readfds, 0, &exceptfds, 0);
+       numfds = interruptible_select (nfds, &readfds, 0, &exceptfds, 0);
 
       if (numfds <= 0)
        {
@@ -242,10 +255,82 @@ ser_base_wait_for (struct serial *scb, int timeout)
     }
 }
 
-/* Read a character with user-specified timeout.  TIMEOUT is number of seconds
-   to wait, or -1 to wait forever.  Use timeout of 0 to effect a poll.  Returns
-   char if successful.  Returns -2 if timeout expired, EOF if line dropped
-   dead, or -3 for any other error (see errno in that case).  */
+/* Read any error output we might have.  */
+
+static void
+ser_base_read_error_fd (struct serial *scb, int close_fd)
+{
+  if (scb->error_fd != -1)
+    {
+      ssize_t s;
+      char buf[GDB_MI_MSG_WIDTH + 1];
+
+      for (;;)
+       {
+         char *current;
+         char *newline;
+         int to_read = GDB_MI_MSG_WIDTH;
+         int num_bytes = -1;
+
+         if (scb->ops->avail)
+           num_bytes = (scb->ops->avail)(scb, scb->error_fd);
+
+         if (num_bytes != -1)
+           to_read = (num_bytes < to_read) ? num_bytes : to_read;
+
+         if (to_read == 0)
+           break;
+
+         s = read (scb->error_fd, &buf, to_read);
+         if ((s == -1) || (s == 0 && !close_fd))
+           break;
+
+         if (s == 0 && close_fd)
+           {
+             /* End of file.  */
+             if (serial_is_async_p (scb))
+               delete_file_handler (scb->error_fd);
+             close (scb->error_fd);
+             scb->error_fd = -1;
+             break;
+           }
+
+         /* In theory, embedded newlines are not a problem.
+            But for MI, we want each output line to have just
+            one newline for legibility.  So output things
+            in newline chunks.  */
+         gdb_assert (s > 0 && s <= GDB_MI_MSG_WIDTH);
+         buf[s] = '\0';
+         current = buf;
+         while ((newline = strstr (current, "\n")) != NULL)
+           {
+             *newline = '\0';
+             fputs_unfiltered (current, gdb_stderr);
+             fputs_unfiltered ("\n", gdb_stderr);
+             current = newline + 1;
+           }
+
+         fputs_unfiltered (current, gdb_stderr);
+       }
+    }
+}
+
+/* Event-loop callback for a serial's error_fd.  Flushes any error
+   output we might have.  */
+
+static void
+handle_error_fd (int error, gdb_client_data client_data)
+{
+  serial *scb = (serial *) client_data;
+
+  ser_base_read_error_fd (scb, 0);
+}
+
+/* Read a character with user-specified timeout.  TIMEOUT is number of
+   seconds to wait, or -1 to wait forever.  Use timeout of 0 to effect
+   a poll.  Returns char if successful.  Returns SERIAL_TIMEOUT if
+   timeout expired, SERIAL_EOF if line dropped dead, or SERIAL_ERROR
+   for any other error (see errno in that case).  */
 
 static int
 do_ser_base_readchar (struct serial *scb, int timeout)
@@ -292,12 +377,21 @@ do_ser_base_readchar (struct serial *scb, int timeout)
          status = SERIAL_TIMEOUT;
          break;
        }
+
+      /* We also need to check and consume the stderr because it could
+        come before the stdout for some stubs.  If we just sit and wait
+        for stdout, we would hit a deadlock for that case.  */
+      ser_base_read_error_fd (scb, 0);
     }
 
   if (status < 0)
     return status;
 
-  status = scb->ops->read_prim (scb, BUFSIZ);
+  do
+    {
+      status = scb->ops->read_prim (scb, BUFSIZ);
+    }
+  while (status < 0 && errno == EINTR);
 
   if (status <= 0)
     {
@@ -362,54 +456,9 @@ generic_readchar (struct serial *scb, int timeout,
            }
        }
     }
-  /* Read any error output we might have.  */
-  if (scb->error_fd != -1)
-    {
-      ssize_t s;
-      char buf[81];
-
-      for (;;)
-        {
-         char *current;
-         char *newline;
-         int to_read = 80;
-
-         int num_bytes = -1;
-         if (scb->ops->avail)
-           num_bytes = (scb->ops->avail)(scb, scb->error_fd);
-         if (num_bytes != -1)
-           to_read = (num_bytes < to_read) ? num_bytes : to_read;
-
-         if (to_read == 0)
-           break;
 
-         s = read (scb->error_fd, &buf, to_read);
-         if (s == -1)
-           break;
-         if (s == 0)
-           {
-             /* EOF */
-             close (scb->error_fd);
-             scb->error_fd = -1;
-             break;
-           }
-
-         /* In theory, embedded newlines are not a problem.
-            But for MI, we want each output line to have just
-            one newline for legibility.  So output things
-            in newline chunks.  */
-         buf[s] = '\0';
-         current = buf;
-         while ((newline = strstr (current, "\n")) != NULL)
-           {
-             *newline = '\0';
-             fputs_unfiltered (current, gdb_stderr);
-             fputs_unfiltered ("\n", gdb_stderr);
-             current = newline + 1;
-           }
-         fputs_unfiltered (current, gdb_stderr);
-       }
-    }
+  /* Read any error output we might have.  */
+  ser_base_read_error_fd (scb, 1);
 
   reschedule (scb);
   return ch;
@@ -422,17 +471,24 @@ ser_base_readchar (struct serial *scb, int timeout)
 }
 
 int
-ser_base_write (struct serial *scb, const char *str, int len)
+ser_base_write (struct serial *scb, const void *buf, size_t count)
 {
+  const char *str = (const char *) buf;
   int cc;
 
-  while (len > 0)
+  while (count > 0)
     {
-      cc = scb->ops->write_prim (scb, str, len); 
+      QUIT;
+
+      cc = scb->ops->write_prim (scb, str, count);
 
       if (cc < 0)
-       return 1;
-      len -= cc;
+       {
+         if (errno == EINTR)
+           continue;
+         return 1;
+       }
+      count -= cc;
       str += cc;
     }
   return 0;
@@ -479,14 +535,14 @@ serial_ttystate
 ser_base_get_tty_state (struct serial *scb)
 {
   /* Allocate a dummy.  */
-  return (serial_ttystate) XMALLOC (int);
+  return (serial_ttystate) XNEW (int);
 }
 
 serial_ttystate
 ser_base_copy_tty_state (struct serial *scb, serial_ttystate ttystate)
 {
   /* Allocate another dummy.  */
-  return (serial_ttystate) XMALLOC (int);
+  return (serial_ttystate) XNEW (int);
 }
 
 int
@@ -495,14 +551,6 @@ ser_base_set_tty_state (struct serial *scb, serial_ttystate ttystate)
   return 0;
 }
 
-int
-ser_base_noflush_set_tty_state (struct serial *scb,
-                               serial_ttystate new_ttystate,
-                               serial_ttystate old_ttystate)
-{
-  return 0;
-}
-
 void
 ser_base_print_tty_state (struct serial *scb, 
                          serial_ttystate ttystate,
@@ -524,6 +572,14 @@ ser_base_setstopbits (struct serial *scb, int num)
   return 0;                    /* Never fails!  */
 }
 
+/* Implement the "setparity" serial_ops callback.  */
+
+int
+ser_base_setparity (struct serial *scb, int parity)
+{
+  return 0;                    /* Never fails!  */
+}
+
 /* Put the SERIAL device into/out-of ASYNC mode.  */
 
 void
@@ -538,6 +594,9 @@ ser_base_async (struct serial *scb,
        fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n",
                            scb->fd);
       reschedule (scb);
+
+      if (scb->error_fd != -1)
+       add_file_handler (scb->error_fd, handle_error_fd, scb);
     }
   else
     {
@@ -556,5 +615,8 @@ ser_base_async (struct serial *scb,
          delete_timer (scb->async_state);
          break;
        }
+
+      if (scb->error_fd != -1)
+       delete_file_handler (scb->error_fd);
     }
 }
This page took 0.030355 seconds and 4 git commands to generate.