OSDN Git Service

Initial revision
authorjsm <jsm>
Mon, 12 Jul 1999 18:06:56 +0000 (18:06 +0000)
committerjsm <jsm>
Mon, 12 Jul 1999 18:06:56 +0000 (18:06 +0000)
gdb/ser-pipe.c [new file with mode: 0644]

diff --git a/gdb/ser-pipe.c b/gdb/ser-pipe.c
new file mode 100644 (file)
index 0000000..4dc2a7d
--- /dev/null
@@ -0,0 +1,397 @@
+/* Serial interface for a pipe to a separate program
+   Copyright 1999 Free Software Foundation, Inc.
+
+   Contributed by Cygnus Solutions.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "serial.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "signals.h"
+#include "gdb_string.h"
+
+extern int (*ui_loop_hook) PARAMS ((int));
+
+static int pipe_open PARAMS ((serial_t scb, const char *name));
+static void pipe_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int pipe_readchar PARAMS ((serial_t scb, int timeout));
+static int pipe_setbaudrate PARAMS ((serial_t scb, int rate));
+static int pipe_setstopbits PARAMS ((serial_t scb, int num));
+static int pipe_write PARAMS ((serial_t scb, const char *str, int len));
+/* FIXME: static void pipe_restore PARAMS ((serial_t scb)); */
+static void pipe_close PARAMS ((serial_t scb));
+static serial_ttystate pipe_get_tty_state PARAMS ((serial_t scb));
+static int pipe_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+static int pipe_return_0 PARAMS ((serial_t));
+static int pipe_noflush_set_tty_state PARAMS ((serial_t, serial_ttystate,
+                                              serial_ttystate));
+static void pipe_print_tty_state PARAMS ((serial_t, serial_ttystate));
+
+extern void _initialize_ser_pipe PARAMS ((void));
+
+/* Open up a raw pipe */
+
+static int
+pipe_open (scb, name)
+     serial_t scb;
+     const char *name;
+{
+#if !defined(O_NONBLOCK) || !defined(F_GETFL) || !defined(F_SETFL)
+  return -1;
+#else
+#if defined (__NetBSD__) || defined (__FreeBSD__)
+
+  /* check the BSD popen sources for where "r+" comes from :-) */
+  FILE *stream;
+  stream = popen (name + 1, "r+");
+  if (stream == NULL)
+    {
+      fprintf_unfiltered (gdb_stderr, "%s: popen failed\n", name + 1);
+      return -1;
+    }
+  scb->ttystate = stream;      /* borrow that space */
+  scb->fd = fileno (stream);
+
+#else
+
+  /* This chunk: */
+
+  /* Copyright (c) 1988, 1993
+   *      The Regents of the University of California.  All rights reserved.
+   *
+   * This code is derived from software written by Ken Arnold and
+   * published in UNIX Review, Vol. 6, No. 8.
+   */
+  int pdes[2];
+  int pid;
+  if (socketpair (AF_UNIX, SOCK_STREAM, 0, pdes) < 0)
+    return -1;
+
+  switch (pid = vfork ())
+    {
+    case -1:                   /* Error. */
+      close (pdes[0]);
+      close (pdes[1]);
+      return -1;
+    case 0:                    /* Child. */
+#if 0
+      /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
+         from previous popen() calls that remain open in the 
+         parent process are closed in the new child process. */
+      for (old = pidlist; old; old = old->next)
+       close (fileno (old->fp));       /* don't allow a flush */
+#endif
+      close (pdes[0]);
+      if (pdes[1] != STDOUT_FILENO)
+       {
+         dup2 (pdes[1], STDOUT_FILENO);
+         close (pdes[1]);
+       }
+      dup2 (STDOUT_FILENO, STDIN_FILENO);
+      execl ("/bin/sh", "sh", "-c", name + 1, NULL);
+      _exit (127);
+    }
+
+  /* Parent; assume fdopen can't fail. */
+  close (pdes[1]);
+  scb->fd = pdes[0];
+  scb->ttystate = NULL;
+#endif
+
+  /* Make it non-blocking */
+  {
+    int flags = fcntl (scb->fd, F_GETFL, 0);
+    if (fcntl (scb->fd, F_SETFL, flags | O_NONBLOCK) < 0)
+      {
+       perror ("ser-pipe");
+       pipe_close (scb);
+       return -1;
+      }
+  }
+
+  /* If we don't do this, GDB simply exits when the remote side dies.  */
+  signal (SIGPIPE, SIG_IGN);
+  return 0;
+#endif
+}
+
+static serial_ttystate
+pipe_get_tty_state (scb)
+     serial_t scb;
+{
+  /* return garbage */
+  return xmalloc (sizeof (int));
+}
+
+static int
+pipe_set_tty_state (scb, ttystate)
+     serial_t scb;
+     serial_ttystate ttystate;
+{
+  return 0;
+}
+
+static int
+pipe_return_0 (scb)
+     serial_t scb;
+{
+  return 0;
+}
+
+static void
+pipe_raw (scb)
+     serial_t scb;
+{
+  return;                      /* Always in raw mode */
+}
+
+/* Wait for input on scb, with timeout seconds.  Returns 0 on success,
+   otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
+
+   For termio{s}, we actually just setup VTIME if necessary, and let the
+   timeout occur in the read() in pipe_read().
+ */
+
+static int
+wait_for (scb, timeout)
+     serial_t scb;
+     int timeout;
+{
+  int numfds;
+  struct timeval tv;
+  fd_set readfds, exceptfds;
+
+  FD_ZERO (&readfds);
+  FD_ZERO (&exceptfds);
+
+  tv.tv_sec = timeout;
+  tv.tv_usec = 0;
+
+  FD_SET (scb->fd, &readfds);
+  FD_SET (scb->fd, &exceptfds);
+
+  while (1)
+    {
+      if (timeout >= 0)
+       numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
+      else
+       numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, 0);
+
+      if (numfds <= 0)
+       {
+         if (numfds == 0)
+           return SERIAL_TIMEOUT;
+         else if (errno == EINTR)
+           continue;
+         else
+           return SERIAL_ERROR;        /* Got an error from select or poll */
+       }
+
+      return 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 -2 if timeout expired, EOF if line dropped
+   dead, or -3 for any other error (see errno in that case). */
+
+static int
+pipe_readchar (scb, timeout)
+     serial_t scb;
+     int timeout;
+{
+  int status;
+  int delta;
+
+  if (scb->bufcnt-- > 0)
+    return *scb->bufp++;
+
+  /* We have to be able to keep the GUI alive here, so we break the original
+     timeout into steps of 1 second, running the "keep the GUI alive" hook 
+     each time through the loop.
+
+     Also, timeout = 0 means to poll, so we just set the delta to 0, so we
+     will only go through the loop once. */
+
+  delta = (timeout == 0 ? 0 : 1);
+  while (1)
+    {
+
+      /* N.B. The UI may destroy our world (for instance by calling
+         remote_stop,) in which case we want to get out of here as
+         quickly as possible.  It is not safe to touch scb, since
+         someone else might have freed it.  The ui_loop_hook signals that 
+         we should exit by returning 1. */
+
+      if (ui_loop_hook)
+       {
+         if (ui_loop_hook (0))
+           return SERIAL_TIMEOUT;
+       }
+
+      status = wait_for (scb, delta);
+      timeout -= delta;
+
+      /* If we got a character or an error back from wait_for, then we can 
+         break from the loop before the timeout is completed. */
+
+      if (status != SERIAL_TIMEOUT)
+       {
+         break;
+       }
+
+      /* If we have exhausted the original timeout, then generate
+         a SERIAL_TIMEOUT, and pass it out of the loop. */
+
+      else if (timeout == 0)
+       {
+         status == SERIAL_TIMEOUT;
+         break;
+       }
+    }
+
+  if (status < 0)
+    return status;
+
+  while (1)
+    {
+      scb->bufcnt = read (scb->fd, scb->buf, BUFSIZ);
+      if (scb->bufcnt != -1 || errno != EINTR)
+       break;
+    }
+
+  if (scb->bufcnt <= 0)
+    {
+      if (scb->bufcnt == 0)
+       return SERIAL_TIMEOUT;  /* 0 chars means timeout [may need to
+                                  distinguish between EOF & timeouts
+                                  someday] */
+      else
+       return SERIAL_ERROR;    /* Got an error from read */
+    }
+
+  scb->bufcnt--;
+  scb->bufp = scb->buf;
+  return *scb->bufp++;
+}
+
+static int
+pipe_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
+     serial_t scb;
+     serial_ttystate new_ttystate;
+     serial_ttystate old_ttystate;
+{
+  return 0;
+}
+
+static void
+pipe_print_tty_state (scb, ttystate)
+     serial_t scb;
+     serial_ttystate ttystate;
+{
+  /* Nothing to print.  */
+  return;
+}
+
+static int
+pipe_setbaudrate (scb, rate)
+     serial_t scb;
+     int rate;
+{
+  return 0;                    /* Never fails! */
+}
+
+static int
+pipe_setstopbits (scb, num)
+     serial_t scb;
+     int num;
+{
+  return 0;                    /* Never fails! */
+}
+
+static int
+pipe_write (scb, str, len)
+     serial_t scb;
+     const char *str;
+     int len;
+{
+  int cc;
+
+  while (len > 0)
+    {
+      cc = write (scb->fd, str, len);
+
+      if (cc < 0)
+       return 1;
+      len -= cc;
+      str += cc;
+    }
+  return 0;
+}
+
+static void
+pipe_close (scb)
+     serial_t scb;
+{
+  if (scb->fd < 0)
+    return;
+  if (scb->ttystate != NULL)
+    pclose ((FILE *) scb->ttystate);
+  else
+    close (scb->fd);
+  scb->ttystate = NULL;
+  scb->fd = -1;
+}
+
+static struct serial_ops pipe_ops =
+{
+  "pipe",
+  0,
+  pipe_open,
+  pipe_close,
+  pipe_readchar,
+  pipe_write,
+  pipe_return_0,               /* flush output */
+  pipe_return_0,               /* flush input */
+  pipe_return_0,               /* send break */
+  pipe_raw,
+  pipe_get_tty_state,
+  pipe_set_tty_state,
+  pipe_print_tty_state,
+  pipe_noflush_set_tty_state,
+  pipe_setbaudrate,
+  pipe_setstopbits,
+  pipe_return_0,               /* wait for output to drain */
+};
+
+void
+_initialize_ser_pipe ()
+{
+  serial_add_interface (&pipe_ops);
+}