/* Generic serial interface functions.
- Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
- 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2003,
+ 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GDB.
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. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "serial.h"
-#include "ser-unix.h"
+#include "ser-base.h"
#include "event-loop.h"
+#include "gdb_select.h"
+#include "gdb_string.h"
+#include <sys/time.h>
+#ifdef USE_WIN32API
+#include <winsock2.h>
+#endif
+
+
static timer_handler_func push_event;
static handler_func fd_event;
pull characters out of the buffer. See also
generic_readchar(). */
int nr;
- do
- {
- nr = read (scb->fd, scb->buf, BUFSIZ);
- }
- while (nr == -1 && errno == EINTR);
+ nr = scb->ops->read_prim (scb, BUFSIZ);
if (nr == 0)
{
scb->bufcnt = SERIAL_EOF;
reschedule (scb);
}
+/* Wait for input on scb, with timeout seconds. Returns 0 on success,
+ otherwise SERIAL_TIMEOUT or SERIAL_ERROR. */
+
+static int
+ser_base_wait_for (struct serial *scb, int timeout)
+{
+ while (1)
+ {
+ int numfds;
+ struct timeval tv;
+ fd_set readfds, exceptfds;
+
+ /* NOTE: Some OS's can scramble the READFDS when the select()
+ call fails (ex the kernel with Red Hat 5.2). Initialize all
+ arguments before each call. */
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO (&readfds);
+ FD_ZERO (&exceptfds);
+ FD_SET (scb->fd, &readfds);
+ FD_SET (scb->fd, &exceptfds);
+
+ if (timeout >= 0)
+ numfds = gdb_select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
+ else
+ numfds = gdb_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
+do_ser_base_readchar (struct serial *scb, int timeout)
+{
+ int status;
+ int delta;
+
+ /* 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
+ deprecated_ui_loop_hook signals that we should exit by
+ returning 1. */
+
+ if (deprecated_ui_loop_hook)
+ {
+ if (deprecated_ui_loop_hook (0))
+ return SERIAL_TIMEOUT;
+ }
+
+ status = ser_base_wait_for (scb, delta);
+ if (timeout > 0)
+ 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;
+
+ status = scb->ops->read_prim (scb, BUFSIZ);
+
+ if (status <= 0)
+ {
+ if (status == 0)
+ /* 0 chars means timeout. (We may need to distinguish between EOF
+ & timeouts someday.) */
+ return SERIAL_TIMEOUT;
+ else
+ /* Got an error from read. */
+ return SERIAL_ERROR;
+ }
+
+ scb->bufcnt = status;
+ scb->bufcnt--;
+ scb->bufp = scb->buf;
+ return *scb->bufp++;
+}
+
+/* Perform operations common to both old and new readchar. */
+
+/* Return the next character from the input FIFO. If the FIFO is
+ empty, call the SERIAL specific routine to try and read in more
+ characters.
+
+ Initially data from the input FIFO is returned (fd_event()
+ pre-reads the input into that FIFO. Once that has been emptied,
+ further data is obtained by polling the input FD using the device
+ specific readchar() function. Note: reschedule() is called after
+ every read. This is because there is no guarentee that the lower
+ level fd_event() poll_event() code (which also calls reschedule())
+ will be called. */
+
+int
+generic_readchar (struct serial *scb, int timeout,
+ int (do_readchar) (struct serial *scb, int timeout))
+{
+ int ch;
+ if (scb->bufcnt > 0)
+ {
+ ch = *scb->bufp;
+ scb->bufcnt--;
+ scb->bufp++;
+ }
+ else if (scb->bufcnt < 0)
+ {
+ /* Some errors/eof are are sticky. */
+ ch = scb->bufcnt;
+ }
+ else
+ {
+ ch = do_readchar (scb, timeout);
+ if (ch < 0)
+ {
+ switch ((enum serial_rc) ch)
+ {
+ case SERIAL_EOF:
+ case SERIAL_ERROR:
+ /* Make the error/eof stick. */
+ scb->bufcnt = ch;
+ break;
+ case SERIAL_TIMEOUT:
+ scb->bufcnt = 0;
+ break;
+ }
+ }
+ }
+ /* 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;
+
+ /* 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);
+ }
+ }
+
+ reschedule (scb);
+ return ch;
+}
+
+int
+ser_base_readchar (struct serial *scb, int timeout)
+{
+ return generic_readchar (scb, timeout, do_ser_base_readchar);
+}
+
int
-ser_unix_write (struct serial *scb, const char *str, int len)
+ser_base_write (struct serial *scb, const char *str, int len)
{
int cc;
while (len > 0)
{
- cc = write (scb->fd, str, len);
+ cc = scb->ops->write_prim (scb, str, len);
if (cc < 0)
return 1;
}
int
-ser_unix_nop_flush_output (struct serial *scb)
+ser_base_flush_output (struct serial *scb)
{
return 0;
}
int
-ser_unix_flush_input (struct serial *scb)
+ser_base_flush_input (struct serial *scb)
{
if (scb->bufcnt >= 0)
{
}
int
-ser_unix_nop_send_break (struct serial *scb)
+ser_base_send_break (struct serial *scb)
{
return 0;
}
int
-ser_unix_nop_drain_output (struct serial *scb)
+ser_base_drain_output (struct serial *scb)
{
return 0;
}
void
-ser_unix_nop_raw (struct serial *scb)
+ser_base_raw (struct serial *scb)
{
return; /* Always in raw mode */
}
serial_ttystate
-ser_unix_nop_get_tty_state (struct serial *scb)
+ser_base_get_tty_state (struct serial *scb)
{
/* allocate a dummy */
return (serial_ttystate) XMALLOC (int);
}
int
-ser_unix_nop_set_tty_state (struct serial *scb, serial_ttystate ttystate)
+ser_base_set_tty_state (struct serial *scb, serial_ttystate ttystate)
{
return 0;
}
int
-ser_unix_nop_noflush_set_tty_state (struct serial *scb,
- serial_ttystate new_ttystate,
- serial_ttystate old_ttystate)
+ser_base_noflush_set_tty_state (struct serial *scb,
+ serial_ttystate new_ttystate,
+ serial_ttystate old_ttystate)
{
return 0;
}
void
-ser_unix_nop_print_tty_state (struct serial *scb,
- serial_ttystate ttystate,
- struct ui_file *stream)
+ser_base_print_tty_state (struct serial *scb,
+ serial_ttystate ttystate,
+ struct ui_file *stream)
{
/* Nothing to print. */
return;
}
int
-ser_unix_nop_setbaudrate (struct serial *scb, int rate)
+ser_base_setbaudrate (struct serial *scb, int rate)
{
return 0; /* Never fails! */
}
int
-ser_unix_nop_setstopbits (struct serial *scb, int num)
+ser_base_setstopbits (struct serial *scb, int num)
{
return 0; /* Never fails! */
}
/* Put the SERIAL device into/out-of ASYNC mode. */
void
-ser_unix_async (struct serial *scb,
+ser_base_async (struct serial *scb,
int async_p)
{
if (async_p)