diff options
-rw-r--r-- | gdb/ChangeLog | 41 | ||||
-rwxr-xr-x | gdb/configure | 12 | ||||
-rw-r--r-- | gdb/configure.ac | 12 | ||||
-rw-r--r-- | gdb/ser-base.c | 186 | ||||
-rw-r--r-- | gdb/ser-base.h | 4 | ||||
-rw-r--r-- | gdb/ser-pipe.c | 4 | ||||
-rw-r--r-- | gdb/ser-tcp.c | 65 | ||||
-rw-r--r-- | gdb/ser-unix.c | 221 | ||||
-rw-r--r-- | gdb/ser-unix.h | 4 | ||||
-rw-r--r-- | gdb/serial.h | 6 |
10 files changed, 347 insertions, 208 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 86a6b56..af6d7e5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,44 @@ +2005-04-20 Mark Mitchell <mark@codesourcery.com> + + * configure.ac: On MinGW, define USE_WIN32API and link with + -lws2_32. + * ser-tcp.c (<winsock2.h>): Include, for Windows. + (ETIMEDOUT): Define, for Windows. + (ioctl): Likewise. + (closesocket): Define, for POSIX. + (net_open): Adjust for differences in socket functions between + Windows and UNIX. + (net_close): Likweise. + (net_read_prim): New function. + (net_write_prim): Likewise. + (_initialize_ser_tcp): Initialize winsock. Fill in read_prim and + write_prim. + * ser-unix.h (ser_unix_readcchar): Remove. + (ser_unix_read_prim): Declare. + (ser_unix_write_prim): Likewise. + * ser-unix.c (generic_readchar): Move to ser-base.c. + (ser_unix_wait_for): Likewise. + (do_unix_readchar): Likewise. + (ser_unix_readchar): Likewise. + (_initialize_ser_hardwire): Initialize read_prim and write_prim. + (ser_unix_read_prim): New function. + (ser_unix_write_prim): Likewise. + * ser-base.h (generic_readchar): Declare. + (ser_base_readchar): Likewise. + * ser-base.c (<winsock2.h>): Include, for windows. + (fd_event): Use the read primitive specified by the serial + interface. + (ser_base_wait_for): Moved from ser-unix.c + (do_ser_base_read_char): Likewise. + (generic_readchar): Likewise. + (ser_base_readchar): Likewise. + (ser_base_write): Use the write primitive specified by the serial + interface. + * ser-pipe.c (_initialize_ser_pipe): Use ser_base_readchar, not + ser_unix_readchar. Initialize read_prim and write_prim. + * serial.c (struct serial_ops): Add read_prim and write_prim. + * configure: Regenerate. + 2005-04-19 Ben Elliston <bje@au.ibm.com> * c-lang.c (c_create_fundamental_type): Comment fix. diff --git a/gdb/configure b/gdb/configure index 39af594..cd0acf7 100755 --- a/gdb/configure +++ b/gdb/configure @@ -20034,6 +20034,18 @@ if test x$gdb_cv_os_cygwin = xyes; then esac fi +# The ser-tcp.c module requires sockets. +case ${host} in + *mingw32*) + +cat >>confdefs.h <<\_ACEOF +#define USE_WIN32API 1 +_ACEOF + + WIN32LIBS="$WIN32LIBS -lws2_32" + ;; +esac + LIBGUI="../libgui/src/libgui.a" GUI_CFLAGS_X="-I${srcdir}/../libgui/src" diff --git a/gdb/configure.ac b/gdb/configure.ac index 6113b0d..554c465 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1187,6 +1187,18 @@ if test x$gdb_cv_os_cygwin = xyes; then ;; esac fi + +# The ser-tcp.c module requires sockets. +case ${host} in + *mingw32*) + AC_DEFINE(USE_WIN32API, 1, + [Define if we should use the Windows API, instead of the + POSIX API. On Windows, we use the Windows API when + building for MinGW, but the POSIX API when building + for Cygwin.]) + WIN32LIBS="$WIN32LIBS -lws2_32" + ;; +esac AC_SUBST(WIN32LIBS) LIBGUI="../libgui/src/libgui.a" diff --git a/gdb/ser-base.c b/gdb/ser-base.c index b17b11a..07ec503 100644 --- a/gdb/ser-base.c +++ b/gdb/ser-base.c @@ -24,6 +24,9 @@ #include "serial.h" #include "ser-unix.h" #include "event-loop.h" +#ifdef USE_WIN32API +#include <winsock2.h> +#endif static timer_handler_func push_event; static handler_func fd_event; @@ -136,11 +139,7 @@ fd_event (int error, void *context) 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; @@ -174,6 +173,181 @@ push_event (void *context) 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) + /* 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; + } + } + } + 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) { @@ -181,7 +355,7 @@ ser_base_write (struct serial *scb, const char *str, int len) while (len > 0) { - cc = write (scb->fd, str, len); + cc = scb->ops->write_prim (scb, str, len); if (cc < 0) return 1; diff --git a/gdb/ser-base.h b/gdb/ser-base.h index 5467fc8..8604629 100644 --- a/gdb/ser-base.h +++ b/gdb/ser-base.h @@ -25,6 +25,9 @@ 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); @@ -46,5 +49,6 @@ 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 diff --git a/gdb/ser-pipe.c b/gdb/ser-pipe.c index b6bb8d5..f127f5d 100644 --- a/gdb/ser-pipe.c +++ b/gdb/ser-pipe.c @@ -144,7 +144,7 @@ _initialize_ser_pipe (void) ops->next = 0; ops->open = pipe_open; ops->close = pipe_close; - ops->readchar = ser_unix_readchar; + ops->readchar = ser_base_readchar; ops->write = ser_base_write; ops->flush_output = ser_base_flush_output; ops->flush_input = ser_base_flush_input; @@ -158,5 +158,7 @@ _initialize_ser_pipe (void) ops->setstopbits = ser_base_setstopbits; ops->drain_output = ser_base_drain_output; ops->async = ser_base_async; + ops->read_prim = ser_unix_read_prim; + ops->write_prim = ser_unix_write_prim; serial_add_interface (ops); } diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c index f908d25..abe6ed4 100644 --- a/gdb/ser-tcp.c +++ b/gdb/ser-tcp.c @@ -34,11 +34,19 @@ #endif #include <sys/time.h> + +#ifdef USE_WIN32API +#include <winsock2.h> +#define ETIMEDOUT WSAETIMEDOUT +#define close closesocket +#define ioctl ioctlsocket +#else #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/tcp.h> +#endif #include <signal.h> #include "gdb_string.h" @@ -62,6 +70,11 @@ net_open (struct serial *scb, const char *name) int use_udp; struct hostent *hostent; struct sockaddr_in sockaddr; +#ifdef USE_WIN32API + u_long ioarg; +#else + int ioarg; +#endif use_udp = 0; if (strncmp (name, "udp:", 4) == 0) @@ -108,14 +121,25 @@ net_open (struct serial *scb, const char *name) sizeof (struct in_addr)); /* set socket nonblocking */ - tmp = 1; - ioctl (scb->fd, FIONBIO, &tmp); + ioarg = 1; + ioctl (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 && errno != EINPROGRESS) + if (n < 0 +#ifdef USE_WIN32API + /* Under Windows, calling "connect" with a non-blocking socket + results in WSAEWOULDBLOCK, not WSAEINPROGRESS. */ + && WSAGetLastError() != WSAEWOULDBLOCK +#else + && errno != EINPROGRESS +#endif + ) { +#ifdef USE_WIN32API + errno = WSAGetLastError(); +#endif net_close (scb); return -1; } @@ -165,7 +189,11 @@ net_open (struct serial *scb, const char *name) { int res, err, len; len = sizeof(err); - res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, &err, &len); + /* 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) @@ -176,8 +204,8 @@ net_open (struct serial *scb, const char *name) } /* turn off nonblocking */ - tmp = 0; - ioctl (scb->fd, FIONBIO, &tmp); + ioarg = 0; + ioctl (scb->fd, FIONBIO, &ioarg); if (use_udp == 0) { @@ -206,16 +234,35 @@ net_close (struct serial *scb) scb->fd = -1; } +static int +net_read_prim (struct serial *scb, size_t count) +{ + return recv (scb->fd, scb->buf, count, 0); +} + +static int +net_write_prim (struct serial *scb, const void *buf, size_t count) +{ + return send (scb->fd, buf, count, 0); +} + void _initialize_ser_tcp (void) { - struct serial_ops *ops = XMALLOC (struct serial_ops); + struct serial_ops *ops; +#ifdef USE_WIN32API + 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_unix_readchar; + ops->readchar = ser_base_readchar; ops->write = ser_base_write; ops->flush_output = ser_base_flush_output; ops->flush_input = ser_base_flush_input; @@ -229,5 +276,7 @@ _initialize_ser_tcp (void) ops->setstopbits = ser_base_setstopbits; ops->drain_output = ser_base_drain_output; ops->async = ser_base_async; + ops->read_prim = net_read_prim; + ops->write_prim = net_write_prim; serial_add_interface (ops); } diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c index 14df459..b76a6bc 100644 --- a/gdb/ser-unix.c +++ b/gdb/ser-unix.c @@ -70,9 +70,6 @@ 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); @@ -422,7 +419,7 @@ hardwire_raw (struct serial *scb) */ /* FIXME: cagney/1999-09-16: Don't replace this with the equivalent - ser_unix*() until the old TERMIOS/SGTTY/... timer code has been + 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 @@ -542,13 +539,13 @@ wait_for (struct serial *scb, int timeout) 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 + ser_base*() 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*() + 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_unix_readchar() doesn't expect + times out due to no data while ser_base_readchar() doesn't expect that. */ static int @@ -863,191 +860,7 @@ hardwire_close (struct serial *scb) close (scb->fd); scb->fd = -1; } - -/* 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); -} void _initialize_ser_hardwire (void) @@ -1058,7 +871,7 @@ _initialize_ser_hardwire (void) ops->next = 0; ops->open = hardwire_open; ops->close = hardwire_close; - /* FIXME: Don't replace this with the equivalent ser_unix*() until + /* 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; @@ -1075,5 +888,29 @@ _initialize_ser_hardwire (void) ops->setstopbits = hardwire_setstopbits; ops->drain_output = hardwire_drain_output; ops->async = ser_base_async; + ops->read_prim = ser_unix_read_prim; + ops->write_prim = ser_unix_write_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; +} + +int +ser_unix_write_prim (struct serial *scb, const void *buf, size_t len) +{ + /* ??? Historically, GDB has not retried calls to "write" that + result in EINTR. */ + return write (scb->fd, buf, len); +} diff --git a/gdb/ser-unix.h b/gdb/ser-unix.h index 5ba01f9..03dbdef 100644 --- a/gdb/ser-unix.h +++ b/gdb/ser-unix.h @@ -22,6 +22,8 @@ #ifndef SER_UNIX_H #define SER_UNIX_H -extern int ser_unix_readchar (struct serial *scb, int timeout); +extern int ser_unix_read_prim (struct serial *scb, size_t count); +extern int ser_unix_write_prim (struct serial *scb, const void *buf, + size_t count); #endif diff --git a/gdb/serial.h b/gdb/serial.h index d83b201..89b66b4 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -232,6 +232,12 @@ struct serial_ops 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); + /* Perform a low-level write operation, writing (at most) COUNT + bytes from BUF. */ + int (*write_prim)(struct serial *scb, const void *buf, size_t count); }; /* Add a new serial interface to the interface list */ |