PATCH: Windows sockets

Mark Mitchell
2005-03-26T01:27:29Z

Here's the first "interesting" patch for Windows support. This patch
modifies ser-tcp.c to support Windows, so that we can use a GDB
running on Windows to talk to a gdbserver process.

Here is a sumary of the changes in this patch:

1. Link with -lws2_32 on MinGW so we can use sockets.

2. In defs.h, define WINAPI so that source files know whether they are
supposed to use the Windows API.

3. Move ser_unix_readchar and friends (which were only barely
UNIX-specific) into ser-base.c, renaming appropriately.

4. Add a new member (read_prim) to struct serial_ops, and use it from
ser_base_readchar. The reason for this is that sockets must be
read with "recv" on Windows; plain "read" does not work. So, we
need a way to indicate which low-level primitive to use to read
from a file descriptor.

5. Make a handful of minor changes to ter-tcp.c to account for
differences in the BSD and Windows sockets APIs.

6. Tweak safe_strerror to deal with Windows sockets error codes.

Tested on x86_64-unknown-linux-gnu, to make sure I didn't break UNIX,
and cursorily on Windows (with other patches, not yet submitted).

OK to apply?

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2005-03-25 Mark Mitchell <mark@codesourcery.com>

* configure.ac: Link with -lws2_32 on mingw.
* configure: Regenerated.
* defs.h (WINAPI): Define, conditionally.
* ser-base.c (winsock2.h): Include it.
(fd_event): Use read_prim.
(ser_base_wait_for): Moved here from ser-unix.c.
(do_ser_base_readchar): Likewise.
(generic_readchar): Likewise.
(ser_base_readchar): Likewise.
* ser-base.h (generic_readchar): Declare.
(ser_base_readchar): Likewise.
* ser-pipe.c (_initialize_ser_pipe): Adjust for name changes.
* ser-tcp.c (winsock2.h): Include it.
(ETIMEDOUT): Define on Windows.
(closesocket): Define on UNIX.
(ioctlsocket): Likewise.
(net_open): Adjust for differences in socket functions between
Windows and UNIX.
(_initialize_ser_tcp): Adjust for name changes.
(net_read_prim): New function.
(net_write): Likewise.
* ser-unix.c (generic_readchar): Remove.
(ser_unix_wait_for): Likewise.
(do_unix_readchar): Likewise.
(ser_unix_readchar): Likewise.
(_initialize_ser_hardwire): Adjust for name changes.
(ser_unix_read_prim): New function.
* ser-unix.h (ser_unix_readchar): Remove.
(ser_unix_read_prim): Declare.
* serial.h (struct serial_ops): Add read_prim.
* utils.c (winerror.h): Include it.
(safe_strerror): Handle winsock errors.

Index: configure.ac
===================================================================
RCS file: /cvs/src/src/gdb/configure.ac,v
retrieving revision 1.17
diff -c -5 -p -r1.17 configure.ac
*** configure.ac 25 Mar 2005 19:47:23 -0000 1.17
--- configure.ac 26 Mar 2005 01:00:29 -0000
*************** if test x$gdb_cv_os_cygwin = xyes; then
*** 1185,1194 ****
--- 1185,1201 ----
case "${target}" in
*cygwin*) WIN32LIBS="$WIN32LIBS -limagehlp"
;;
esac
fi
+
+ # The ser-tcp.c module requires sockets.
+ case ${host} in
+ *mingw32*)
+ WIN32LIBS="$WIN32LIBS -lwsock32"
+ ;;
+ esac
AC_SUBST(WIN32LIBS)

LIBGUI="../libgui/src/libgui.a"
GUI_CFLAGS_X="-I${srcdir}/../libgui/src"
AC_SUBST(LIBGUI)
Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.182
diff -c -5 -p -r1.182 defs.h
*** defs.h 17 Mar 2005 22:11:09 -0000 1.182
--- defs.h 26 Mar 2005 01:00:29 -0000
*************** extern int use_windows;
*** 1149,1158 ****
--- 1149,1162 ----

#ifndef SLASH_STRING
#define SLASH_STRING "/"
#endif

+ #if defined(__WIN32__) && !defined(__CYGWIN__)
+ #define WINAPI
+ #endif
+
/* Provide default definitions of PIDGET, TIDGET, and MERGEPID.
The name ``TIDGET'' is a historical accident. Many uses of TIDGET
in the code actually refer to a lightweight process id, i.e,
something that can be considered a process id in its own right for
certain purposes. */
Index: ser-base.c
===================================================================
RCS file: /cvs/src/src/gdb/ser-base.c,v
retrieving revision 1.2
diff -c -5 -p -r1.2 ser-base.c
*** ser-base.c 25 Mar 2005 20:06:36 -0000 1.2
--- ser-base.c 26 Mar 2005 01:00:29 -0000
***************
*** 22,31 ****
--- 22,34 ----

#include "defs.h"
#include "serial.h"
#include "ser-unix.h"
#include "event-loop.h"
+ #ifdef WINAPI
+ #include <winsock2.h>
+ #endif

static timer_handler_func push_event;
static handler_func fd_event;

/* Event handling for ASYNC serial code.
*************** fd_event (int error, void *context)
*** 134,148 ****
{
/* Prime the input FIFO. The readchar() function is used to
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);
if (nr == 0)
{
scb->bufcnt = SERIAL_EOF;
}
else if (nr > 0)
--- 137,147 ----
{
/* Prime the input FIFO. The readchar() function is used to
pull characters out of the buffer. See also
generic_readchar(). */
int nr;
! nr = scb->ops->read_prim (scb, BUFSIZ);
if (nr == 0)
{
scb->bufcnt = SERIAL_EOF;
}
else if (nr > 0)
*************** push_event (void *context)
*** 172,181 ****
--- 171,359 ----
scb->async_handler (scb, scb->async_context);
/* re-schedule */
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 = 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
+ 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)
+ 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 = 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;
+ }
+ }
+ }
+ reschedule (scb);
+ return ch;
+ }
+
+ int
+ ser_base_readchar (struct serial *scb, int timeout)
+ {
+ return generic_readchar (scb, timeout, do_ser_base_readchar);
+ }
+
int
ser_base_write (struct serial *scb, const char *str, int len)
{
int cc;

Index: ser-base.h
===================================================================
RCS file: /cvs/src/src/gdb/ser-base.h,v
retrieving revision 1.2
diff -c -5 -p -r1.2 ser-base.h
*** ser-base.h 25 Mar 2005 20:06:36 -0000 1.2
--- ser-base.h 26 Mar 2005 01:00:29 -0000
***************
*** 23,32 ****
--- 23,35 ----
#define SER_BASE_H

struct serial;
struct ui_file;

+ extern int generic_readchar (struct serial *scb, int timeout,
+ int (*do_readchar) (struct serial *scb,
+ int timeout));
extern void reschedule (struct serial *scb);
extern int ser_base_flush_output (struct serial *scb);
extern int ser_base_flush_input (struct serial *scb);
extern int ser_base_send_break (struct serial *scb);
extern void ser_base_raw (struct serial *scb);
*************** extern int ser_base_setstopbits (struct
*** 44,50 ****
--- 47,54 ----
extern int ser_base_drain_output (struct serial *scb);

extern int ser_base_write (struct serial *scb, const char *str, int len);

extern void ser_base_async (struct serial *scb, int async_p);
+ extern int ser_base_readchar (struct serial *scb, int timeout);

#endif
Index: ser-pipe.c
===================================================================
RCS file: /cvs/src/src/gdb/ser-pipe.c,v
retrieving revision 1.15
diff -c -5 -p -r1.15 ser-pipe.c
*** ser-pipe.c 25 Mar 2005 20:06:36 -0000 1.15
--- ser-pipe.c 26 Mar 2005 01:00:29 -0000
*************** _initialize_ser_pipe (void)
*** 142,152 ****
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "pipe";
ops->next = 0;
ops->open = pipe_open;
ops->close = pipe_close;
! ops->readchar = ser_unix_readchar;
ops->write = ser_base_write;
ops->flush_output = ser_base_flush_output;
ops->flush_input = ser_base_flush_input;
ops->send_break = ser_base_send_break;
ops->go_raw = ser_base_raw;
--- 142,152 ----
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "pipe";
ops->next = 0;
ops->open = pipe_open;
ops->close = pipe_close;
! ops->readchar = ser_base_readchar;
ops->write = ser_base_write;
ops->flush_output = ser_base_flush_output;
ops->flush_input = ser_base_flush_input;
ops->send_break = ser_base_send_break;
ops->go_raw = ser_base_raw;
*************** _initialize_ser_pipe (void)
*** 156,162 ****
--- 156,163 ----
ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
ops->setbaudrate = ser_base_setbaudrate;
ops->setstopbits = ser_base_setstopbits;
ops->drain_output = ser_base_drain_output;
ops->async = ser_base_async;
+ ops->read_prim = ser_unix_read_prim;
serial_add_interface (ops);
}
Index: ser-tcp.c
===================================================================
RCS file: /cvs/src/src/gdb/ser-tcp.c,v
retrieving revision 1.20
diff -c -5 -p -r1.20 ser-tcp.c
*** ser-tcp.c 25 Mar 2005 20:06:36 -0000 1.20
--- ser-tcp.c 26 Mar 2005 01:00:29 -0000
***************
*** 32,46 ****
--- 32,54 ----
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h> /* For FIONBIO. */
#endif

#include <sys/time.h>
+
+ #ifdef WINAPI
+ #include <winsock2.h>
+ #define ETIMEDOUT WSAETIMEDOUT
+ #else
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
+ #define closesocket close
+ #define ioctlsocket ioctl
+ #endif

#include <signal.h>
#include "gdb_string.h"

static int net_open (struct serial *scb, const char *name);
*************** net_open (struct serial *scb, const char
*** 60,69 ****
--- 68,82 ----
char *port_str, hostname[100];
int n, port, tmp;
int use_udp;
struct hostent *hostent;
struct sockaddr_in sockaddr;
+ #ifdef WINAPI
+ u_long ioarg;
+ #else
+ int ioarg;
+ #endif

use_udp = 0;
if (strncmp (name, "udp:", 4) == 0)
{
use_udp = 1;
*************** net_open (struct serial *scb, const char
*** 106,123 ****
sockaddr.sin_port = htons (port);
memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
sizeof (struct in_addr));

/* set socket nonblocking */
! tmp = 1;
! ioctl (scb->fd, FIONBIO, &tmp);

/* Use Non-blocking connect. connect() will return 0 if connected already. */
n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));

! if (n < 0 && errno != EINPROGRESS)
{
net_close (scb);
return -1;
}

if (n)
--- 119,147 ----
sockaddr.sin_port = htons (port);
memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
sizeof (struct in_addr));

/* set socket nonblocking */
! ioarg = 1;
! ioctlsocket (scb->fd, FIONBIO, &ioarg);

/* Use Non-blocking connect. connect() will return 0 if connected already. */
n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));

! if (n < 0
! #ifdef WINAPI
! /* Under Windows, calling "connect" with a non-blocking socket
! results in WSAEWOULDBLOCK, not WSAEINPROGRESS. */
! && WSAGetLastError() != WSAEWOULDBLOCK
! #else
! && errno != EINPROGRESS
! #endif
! )
{
+ #ifdef WINAPI
+ errno = WSAGetLastError();
+ #endif
net_close (scb);
return -1;
}

if (n)
*************** net_open (struct serial *scb, const char
*** 163,185 ****

/* Got something. Is it an error? */
{
int res, err, len;
len = sizeof(err);
! res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, &err, &len);
if (res < 0 || err)
{
if (err)
errno = err;
net_close (scb);
return -1;
}
}

/* turn off nonblocking */
! tmp = 0;
! ioctl (scb->fd, FIONBIO, &tmp);

if (use_udp == 0)
{
/* Disable Nagle algorithm. Needed in some cases. */
tmp = 1;
--- 187,213 ----

/* Got something. Is it an error? */
{
int res, err, len;
len = sizeof(err);
! /* On Windows, the fourth parameter to getsockopt is a "char *";
! on UNIX systems it is generally "void *". The cast to "void *"
! is OK everywhere, since in C "void *" can be implicitly
! converted to any pointer type. */
! res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len);
if (res < 0 || err)
{
if (err)
errno = err;
net_close (scb);
return -1;
}
}

/* turn off nonblocking */
! ioarg = 0;
! ioctlsocket (scb->fd, FIONBIO, &ioarg);

if (use_udp == 0)
{
/* Disable Nagle algorithm. Needed in some cases. */
tmp = 1;
*************** static void
*** 200,224 ****
net_close (struct serial *scb)
{
if (scb->fd < 0)
return;

! close (scb->fd);
scb->fd = -1;
}

void
_initialize_ser_tcp (void)
{
! struct serial_ops *ops = XMALLOC (struct serial_ops);
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "tcp";
ops->next = 0;
ops->open = net_open;
ops->close = net_close;
! ops->readchar = ser_unix_readchar;
! ops->write = ser_base_write;
ops->flush_output = ser_base_flush_output;
ops->flush_input = ser_base_flush_input;
ops->send_break = ser_base_send_break;
ops->go_raw = ser_base_raw;
ops->get_tty_state = ser_base_get_tty_state;
--- 228,293 ----
net_close (struct serial *scb)
{
if (scb->fd < 0)
return;

! closesocket (scb->fd);
scb->fd = -1;
}

+ static int
+ net_read_prim (struct serial *scb, size_t count)
+ {
+ #ifdef WINAPI
+ /* Under Windows, we must use "recv" to read data from sockets. */
+ return recv (scb->fd, scb->buf, count, 0);
+ #else
+ return ser_unix_read_prim (scb, count);
+ #endif
+ }
+
+ static int
+ net_write (struct serial *scb, const char *str, int len)
+ {
+ #ifdef WINAPI
+ /* Under Windows, we must use "send" to send data to and from
+ sockets. */
+ int cc;
+
+ while (len > 0)
+ {
+ cc = send (scb->fd, str, len, 0);
+
+ if (cc < 0)
+ return 1;
+ len -= cc;
+ str += cc;
+ }
+ return 0;
+ #else
+ return ser_base_write (scb, str, len);
+ #endif
+ }
+
void
_initialize_ser_tcp (void)
{
! struct serial_ops *ops;
! #ifdef WINAPI
! WSADATA wsa_data;
! if (WSAStartup (MAKEWORD (1, 0), &wsa_data) != 0)
! /* WinSock is unavailable. */
! return;
! #endif
! ops = XMALLOC (struct serial_ops);
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "tcp";
ops->next = 0;
ops->open = net_open;
ops->close = net_close;
! ops->readchar = ser_base_readchar;
! ops->write = net_write;
ops->flush_output = ser_base_flush_output;
ops->flush_input = ser_base_flush_input;
ops->send_break = ser_base_send_break;
ops->go_raw = ser_base_raw;
ops->get_tty_state = ser_base_get_tty_state;
*************** _initialize_ser_tcp (void)
*** 227,233 ****
--- 296,303 ----
ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
ops->setbaudrate = ser_base_setbaudrate;
ops->setstopbits = ser_base_setstopbits;
ops->drain_output = ser_base_drain_output;
ops->async = ser_base_async;
+ ops->read_prim = net_read_prim;
serial_add_interface (ops);
}
Index: ser-unix.c
===================================================================
RCS file: /cvs/src/src/gdb/ser-unix.c,v
retrieving revision 1.24
diff -c -5 -p -r1.24 ser-unix.c
*** ser-unix.c 25 Mar 2005 20:06:36 -0000 1.24
--- ser-unix.c 26 Mar 2005 01:00:30 -0000
*************** struct hardwire_ttystate
*** 68,80 ****
static int hardwire_open (struct serial *scb, const char *name);
static void hardwire_raw (struct serial *scb);
static int wait_for (struct serial *scb, int timeout);
static int hardwire_readchar (struct serial *scb, int timeout);
static int do_hardwire_readchar (struct serial *scb, int timeout);
- static int generic_readchar (struct serial *scb, int timeout,
- int (*do_readchar) (struct serial *scb,
- int timeout));
static int rate_to_code (int rate);
static int hardwire_setbaudrate (struct serial *scb, int rate);
static void hardwire_close (struct serial *scb);
static int get_tty_state (struct serial *scb,
struct hardwire_ttystate * state);
--- 68,77 ----
*************** hardwire_raw (struct serial *scb)
*** 420,430 ****
For termio{s}, we actually just setup VTIME if necessary, and let the
timeout occur in the read() in hardwire_read().
*/

/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
! ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
flushed. . */

/* NOTE: cagney/1999-09-30: Much of the code below is dead. The only
possible values of the TIMEOUT parameter are ONE and ZERO.
Consequently all the code that tries to handle the possability of
--- 417,427 ----
For termio{s}, we actually just setup VTIME if necessary, and let the
timeout occur in the read() in hardwire_read().
*/

/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
! ser_base*() until the old TERMIOS/SGTTY/... timer code has been
flushed. . */

/* NOTE: cagney/1999-09-30: Much of the code below is dead. The only
possible values of the TIMEOUT parameter are ONE and ZERO.
Consequently all the code that tries to handle the possability of
*************** wait_for (struct serial *scb, int timeou
*** 540,556 ****
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, EOF if line
dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */

/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
! ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
flushed. */

/* NOTE: cagney/1999-09-16: This function is not identical to
! ser_unix_readchar() as part of replacing it with ser_unix*()
merging will be required - this code handles the case where read()
! times out due to no data while ser_unix_readchar() doesn't expect
that. */

static int
do_hardwire_readchar (struct serial *scb, int timeout)
{
--- 537,553 ----
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, EOF if line
dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */

/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
! ser_base*() until the old TERMIOS/SGTTY/... timer code has been
flushed. */

/* NOTE: cagney/1999-09-16: This function is not identical to
! ser_base_readchar() as part of replacing it with ser_base*()
merging will be required - this code handles the case where read()
! times out due to no data while ser_base_readchar() doesn't expect
that. */

static int
do_hardwire_readchar (struct serial *scb, int timeout)
{
*************** hardwire_close (struct serial *scb)
*** 861,1066 ****
return;

close (scb->fd);
scb->fd = -1;
}
-
\f
- /* Wait for input on scb, with timeout seconds. Returns 0 on success,
- otherwise SERIAL_TIMEOUT or SERIAL_ERROR. */
-
- static int
- ser_unix_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 = 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
- do_unix_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_unix_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;
-
- while (1)
- {
- status = read (scb->fd, scb->buf, BUFSIZ);
- if (status != -1 || errno != EINTR)
- break;
- }
-
- if (status <= 0)
- {
- if (status == 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 = 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. */
-
- static 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;
- }
- }
- }
- reschedule (scb);
- return ch;
- }
-
- int
- ser_unix_readchar (struct serial *scb, int timeout)
- {
- return generic_readchar (scb, timeout, do_unix_readchar);
- }
\f
void
_initialize_ser_hardwire (void)
{
struct serial_ops *ops = XMALLOC (struct serial_ops);
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "hardwire";
ops->next = 0;
ops->open = hardwire_open;
ops->close = hardwire_close;
! /* FIXME: Don't replace this with the equivalent ser_unix*() until
the old TERMIOS/SGTTY/... timer code has been flushed. cagney
1999-09-16. */
ops->readchar = hardwire_readchar;
ops->write = ser_base_write;
ops->flush_output = hardwire_flush_output;
--- 858,879 ----
return;

close (scb->fd);
scb->fd = -1;
}
\f
\f
void
_initialize_ser_hardwire (void)
{
struct serial_ops *ops = XMALLOC (struct serial_ops);
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "hardwire";
ops->next = 0;
ops->open = hardwire_open;
ops->close = hardwire_close;
! /* FIXME: Don't replace this with the equivalent ser_base*() until
the old TERMIOS/SGTTY/... timer code has been flushed. cagney
1999-09-16. */
ops->readchar = hardwire_readchar;
ops->write = ser_base_write;
ops->flush_output = hardwire_flush_output;
*************** _initialize_ser_hardwire (void)
*** 1073,1079 ****
--- 886,907 ----
ops->noflush_set_tty_state = hardwire_noflush_set_tty_state;
ops->setbaudrate = hardwire_setbaudrate;
ops->setstopbits = hardwire_setstopbits;
ops->drain_output = hardwire_drain_output;
ops->async = ser_base_async;
+ ops->read_prim = ser_unix_read_prim;
serial_add_interface (ops);
}
+
+ int
+ ser_unix_read_prim (struct serial *scb, size_t count)
+ {
+ int status;
+
+ while (1)
+ {
+ status = read (scb->fd, scb->buf, count);
+ if (status != -1 || errno != EINTR)
+ break;
+ }
+ return status;
+ }
Index: ser-unix.h
===================================================================
RCS file: /cvs/src/src/gdb/ser-unix.h,v
retrieving revision 1.5
diff -c -5 -p -r1.5 ser-unix.h
*** ser-unix.h 25 Mar 2005 19:47:23 -0000 1.5
--- ser-unix.h 26 Mar 2005 01:00:30 -0000
***************
*** 20,27 ****
Boston, MA 02111-1307, USA. */

#ifndef SER_UNIX_H
#define SER_UNIX_H

! extern int ser_unix_readchar (struct serial *scb, int timeout);

#endif
--- 20,27 ----
Boston, MA 02111-1307, USA. */

#ifndef SER_UNIX_H
#define SER_UNIX_H

! extern int ser_unix_read_prim (struct serial *scb, size_t count);

#endif
Index: serial.h
===================================================================
RCS file: /cvs/src/src/gdb/serial.h,v
retrieving revision 1.10
diff -c -5 -p -r1.10 serial.h
*** serial.h 14 Jan 2005 01:59:20 -0000 1.10
--- serial.h 26 Mar 2005 01:00:30 -0000
*************** struct serial_ops
*** 230,239 ****
--- 230,242 ----
int (*drain_output) (struct serial *);
/* Change the serial device into/out of asynchronous mode, call
the specified function when ever there is something
interesting. */
void (*async) (struct serial *scb, int async_p);
+ /* Perform a low-level read operation, reading (at most) COUNT
+ bytes into SCB->BUF. */
+ int (*read_prim)(struct serial *scb, size_t count);
};

/* Add a new serial interface to the interface list */

extern void serial_add_interface (struct serial_ops * optable);
Index: utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.160
diff -c -5 -p -r1.160 utils.c
*** utils.c 18 Mar 2005 20:46:38 -0000 1.160
--- utils.c 26 Mar 2005 01:00:30 -0000
***************
*** 56,65 ****
--- 56,69 ----

#include "inferior.h" /* for signed_pointer_to_address */

#include <sys/param.h> /* For MAXPATHLEN */

+ #ifdef WINAPI
+ #include <winerror.h>
+ #endif
+
#include "gdb_curses.h"

#include "readline/readline.h"

#if !HAVE_DECL_MALLOC
*************** internal_warning (const char *file, int
*** 844,861 ****

char *
safe_strerror (int errnum)
{
char *msg;

! msg = strerror (errnum);
! if (msg == NULL)
{
! static char buf[32];
! xsnprintf (buf, sizeof buf, "(undocumented errno %d)", errnum);
msg = buf;
}
return (msg);
}

/* Print the system error message for errno, and also mention STRING
as the file name for which the error was encountered.
--- 848,879 ----

char *
safe_strerror (int errnum)
{
char *msg;
+ static char buf[32];

! #ifdef WINAPI
! /* The strerror function only works for functions that set errno.
! In the case of Windows sockets, we can get error numbers that
! strerror cannot handle. */
! if (errnum > WSABASEERR)
{
! xsnprintf (buf, sizeof buf, "(winsock error %d)", errnum);
msg = buf;
}
+ else
+ #endif
+ {
+ msg = strerror (errnum);
+
+ if (msg == NULL)
+ {
+ xsnprintf (buf, sizeof buf, "(undocumented errno %d)", errnum);
+ msg = buf;
+ }
+ }
return (msg);
}

/* Print the system error message for errno, and also mention STRING
as the file name for which the error was encountered.