This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: Windows sockets


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;
  }
- 
  
- /* 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)
  {
    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;
  }
  
  
  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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]