This is the mail archive of the gdb-patches@sourceware.org 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]

Re: RFA: Various Windows (mingw32) additions, mostly relating to select or serial ports


On Fri, Feb 03, 2006 at 05:05:29PM -0500, Daniel Jacobowitz wrote:
> Fixes, all for a mingw32-hosted GDB:

Here is a revised version, in which the Windows select magic does not
live in event-loop.c, and including the NEWS entry.  I haven't changed
the pipe polling code; thanks to Ian for his suggestions, but I'm
not sufficiently sure they're workable.

Are there any bits of this patch that strike you as too ugly or in the
wrong place?

-- 
Daniel Jacobowitz
CodeSourcery

2006-02-03  Daniel Jacobowitz  <dan@codesourcery.com>

	* NEWS: Mention native Windows support.
	* Makefile.in (gdb_select_h, ser_tcp_h): New.
	(ALLDEPFILES): Add ser-mingw.c.
	(event-loop.o, mingw-hdep.o, ser-base.o, ser-tcp.o): Update.
	(ser-mingw.o): New rule.
	* configure: Regenerated.
	* configure.in: Add ser-mingw.o for mingw32.
	* ser-mingw.c: New file.
	* event-loop.c: Include "gdb_select.h".
	(gdb_select): Make global.  Update comments.  Call mingw_select
	instead of inlining MinGW-specific code.
	* ser-base.c: Include "gdb_select.h".
	(ser_base_wait_for): Use gdb_select.
	* serial.c (serial_for_fd): New function.
	(serial_fdopen): Try "terminal" before "hardwire".  Initialize
	the allocated struct serial.
	(serial_wait_handle): New function.
	* serial.h (serial_for_fd, serial_wait_handle): New prototypes.
	(struct serial_ops) [USE_WIN32API]: Add wait_handle.
	* gdb_select.h: New file.
	* ser-tcp.c: Include "ser-tcp.h".  Remove unused "ser-unix.h" include.
	(net_close, net_read_prim, net_write_prim): Make global.
	(net_open): Likewise.  Pass an exception set to select.  Whitespace fix.
	(_initialize_ser_tcp) [USE_WIN32API]: Do not register TCP support here.
	* ser-tcp.h: New file.
	* inflow.c (gdb_has_a_terminal): Don't initialize stdin_serial here.
	(initialize_stdin_serial): New function.
	* terminal.h (initialize_stdin_serial): New prototype.
	* top.c (gdb_init): Call initialize_stdin_serial.
	* config/i386/xm-mingw.h (mingw_select): New prototype.
	* mingw-hdep.c (gdb_select): New function, cloned from gdb_select in
	event-loop.c.  Add exception condition support.  Use serial_for_fd
	and serial_wait_handle.

Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/Makefile.in	2006-02-06 15:47:12.000000000 -0500
@@ -692,6 +692,7 @@ gdb_obstack_h = gdb_obstack.h $(obstack_
 gdb_proc_service_h = gdb_proc_service.h $(gregset_h)
 gdb_ptrace_h = gdb_ptrace.h
 gdb_regex_h = gdb_regex.h $(xregex_h)
+gdb_select_h = gdb_select.h
 gdb_stabs_h = gdb-stabs.h
 gdb_stat_h = gdb_stat.h
 gdb_string_h = gdb_string.h
@@ -764,6 +765,7 @@ scm_tags_h = scm-tags.h
 sentinel_frame_h = sentinel-frame.h
 serial_h = serial.h
 ser_base_h = ser-base.h
+ser_tcp_h = ser-tcp.h
 ser_unix_h = ser-unix.h
 shnbsd_tdep_h = shnbsd-tdep.h
 sh_tdep_h = sh-tdep.h
@@ -1440,7 +1442,7 @@ ALLDEPFILES = \
 	remote-st.c remote-utils.c dcache.c \
 	rs6000-nat.c rs6000-tdep.c \
 	s390-tdep.c s390-nat.c \
-	ser-go32.c ser-pipe.c ser-tcp.c \
+	ser-go32.c ser-pipe.c ser-tcp.c ser-mingw.c \
 	sh-tdep.c sh64-tdep.c shnbsd-tdep.c shnbsd-nat.c \
 	sol2-tdep.c \
 	solib-irix.c solib-svr4.c solib-sunos.c \
@@ -1920,7 +1922,7 @@ eval.o: eval.c $(defs_h) $(gdb_string_h)
 	$(f_lang_h) $(cp_abi_h) $(infcall_h) $(objc_lang_h) $(block_h) \
 	$(parser_defs_h) $(cp_support_h)
 event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
-	$(gdb_string_h) $(exceptions_h) $(gdb_assert_h)
+	$(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h)
 event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
 	$(terminal_h) $(event_loop_h) $(event_top_h) $(interps_h) \
 	$(exceptions_h) $(gdbcmd_h) $(readline_h) $(readline_history_h)
@@ -2280,7 +2282,8 @@ memattr.o: memattr.c $(defs_h) $(command
 	$(target_h) $(value_h) $(language_h) $(gdb_string_h)
 mem-break.o: mem-break.c $(defs_h) $(symtab_h) $(breakpoint_h) $(inferior_h) \
 	$(target_h)
-mingw-hdep.o: mingw-hdep.c $(defs_h) $(gdb_string_h)
+mingw-hdep.o: mingw-hdep.c $(defs_h) $(serial_h) $(gdb_assert_h) \
+	$(gdb_select_h) $(gdb_string_h)
 minsyms.o: minsyms.c $(defs_h) $(gdb_string_h) $(symtab_h) $(bfd_h) \
 	$(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(cp_abi_h)
 mips64obsd-nat.o: mips64obsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) \
@@ -2512,13 +2515,15 @@ ser-e7kpc.o: ser-e7kpc.c $(defs_h) $(ser
 ser-go32.o: ser-go32.c $(defs_h) $(gdbcmd_h) $(serial_h) $(gdb_string_h)
 serial.o: serial.c $(defs_h) $(serial_h) $(gdb_string_h) $(gdbcmd_h)
 ser-base.o: ser-base.c $(defs_h) $(serial_h) $(ser_base_h) $(event_loop_h) \
-	$(gdb_string_h)
+	$(gdb_select_h) $(gdb_string_h)
 ser-pipe.o: ser-pipe.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \
 	$(gdb_vfork_h) $(gdb_string_h)
-ser-tcp.o: ser-tcp.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \
+ser-tcp.o: ser-tcp.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_tcp_h) \
 	$(gdb_string_h)
 ser-unix.o: ser-unix.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \
 	$(terminal_h) $(gdb_string_h)
+ser-mingw.o: ser-mingw.c $(defs_h) $(serial_h) $(ser_base_h) \
+	$(ser_tcp_h) $(gdb_assert_h) $(gdb_string_h)
 sh3-rom.o: sh3-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \
 	$(serial_h) $(srec_h) $(arch_utils_h) $(regcache_h) $(gdb_string_h) \
 	$(sh_tdep_h)
Index: src/gdb/configure
===================================================================
--- src.orig/gdb/configure	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/configure	2006-02-06 15:44:41.000000000 -0500
@@ -20093,7 +20093,7 @@ SER_HARDWIRE="ser-base.o ser-unix.o ser-
 case ${host} in
   *go32* ) SER_HARDWIRE=ser-go32.o ;;
   *djgpp* ) SER_HARDWIRE=ser-go32.o ;;
-  *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o" ;;
+  *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o ser-mingw.o" ;;
 esac
 
 
Index: src/gdb/configure.ac
===================================================================
--- src.orig/gdb/configure.ac	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/configure.ac	2006-02-06 15:44:41.000000000 -0500
@@ -1,5 +1,6 @@
 dnl Autoconf configure script for GDB, the GNU debugger.
-dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+dnl 2005, 2006
 dnl Free Software Foundation, Inc.
 dnl
 dnl This file is part of GDB.
@@ -1198,7 +1199,7 @@ SER_HARDWIRE="ser-base.o ser-unix.o ser-
 case ${host} in
   *go32* ) SER_HARDWIRE=ser-go32.o ;;
   *djgpp* ) SER_HARDWIRE=ser-go32.o ;;
-  *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o" ;;
+  *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o ser-mingw.o" ;;
 esac
 AC_SUBST(SER_HARDWIRE)
 
Index: src/gdb/event-loop.c
===================================================================
--- src.orig/gdb/event-loop.c	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/event-loop.c	2006-02-06 15:47:01.000000000 -0500
@@ -1,5 +1,6 @@
 /* Event loop machinery for GDB, the GNU debugger.
-   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006
+   Free Software Foundation, Inc.
    Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
 
    This file is part of GDB.
@@ -37,6 +38,7 @@
 #include <sys/time.h>
 #include "exceptions.h"
 #include "gdb_assert.h"
+#include "gdb_select.h"
 
 typedef struct gdb_event gdb_event;
 typedef void (event_handler_func) (int);
@@ -731,92 +733,14 @@ handle_file_event (int event_file_desc)
     }
 }
 
-/* Wrapper for select.  This function is not yet exported from this
-   file because it is not sufficiently general.  For example,
-   ser-base.c uses select to check for socket activity, and this
-   function does not support sockets under Windows, so we do not want
-   to use gdb_select in ser-base.c.  */
+/* Wrapper for select.  */
 
-static int 
+int
 gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 	    struct timeval *timeout)
 {
 #ifdef USE_WIN32API
-  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
-  HANDLE h;
-  DWORD event;
-  DWORD num_handles;
-  int fd;
-  int num_ready;
-
-  num_ready = 0;
-  num_handles = 0;
-  for (fd = 0; fd < n; ++fd)
-    {
-      /* There is no support yet for WRITEFDS.  At present, this isn't
-	 used by GDB -- but we do not want to silently ignore WRITEFDS
-	 if something starts using it.  */
-      gdb_assert (!FD_ISSET (fd, writefds));
-      if (!FD_ISSET (fd, readfds) 
-	  && !FD_ISSET (fd, exceptfds))
-	continue;
-      h = (HANDLE) _get_osfhandle (fd);
-      if (h == INVALID_HANDLE_VALUE)
-	{
-	  /* If the underlying handle is INVALID_HANDLE_VALUE, then
-	     this descriptor is no more.  */
-	  if (FD_ISSET (fd, exceptfds))
-	    ++num_ready;
-	  continue;
-	}
-      /* The only exceptional condition we recognize is a closed file
-	 descriptor.  Since we have already checked for that
-	 condition, clear the exceptional bit for this descriptor.  */
-      FD_CLR (fd, exceptfds);
-      if (FD_ISSET (fd, readfds))
-      {
-	gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
-	handles[num_handles++] = h;
-      }
-    }
-  /* If we don't need to wait for any handles, we are done.  */
-  if (!num_handles)
-    return num_ready;
-  event = WaitForMultipleObjects (num_handles,
-				  handles,
-				  FALSE,
-				  timeout 
-				  ? (timeout->tv_sec * 1000 + timeout->tv_usec)
-				  : INFINITE);
-  /* EVENT can only be a value in the WAIT_ABANDONED_0 range if the
-     HANDLES included an abandoned mutex.  Since GDB doesn't use
-     mutexes, that should never occur.  */
-  gdb_assert (!(WAIT_ABANDONED_0 <= event
-		&& event < WAIT_ABANDONED_0 + num_handles));
-  if (event == WAIT_FAILED)
-    return -1;
-  if (event == WAIT_TIMEOUT)
-    return num_ready;
-  /* Run through the READFDS, clearing bits corresponding to descriptors
-     for which input is unavailable.  */
-  num_ready += num_handles; 
-  h = handles[event - WAIT_OBJECT_0];
-  for (fd = 0; fd < n; ++fd)
-    {
-      HANDLE fd_h;
-      if (!FD_ISSET (fd, readfds))
-	continue;
-      fd_h = (HANDLE) _get_osfhandle (fd);
-      /* This handle might be ready, even though it wasn't the handle
-	 returned by WaitForMultipleObjects.  */
-      if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
-	{
-	  FD_CLR (fd, readfds);
-	  --num_ready;
-	}
-    }
-
-  return num_ready;
+  return mingw_select (n, readfds, writefds, exceptfds, timeout);
 #else
   return select (n, readfds, writefds, exceptfds, timeout);
 #endif
Index: src/gdb/ser-base.c
===================================================================
--- src.orig/gdb/ser-base.c	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/ser-base.c	2006-02-06 15:44:41.000000000 -0500
@@ -1,7 +1,7 @@
 /* Generic serial interface functions.
 
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -25,6 +25,7 @@
 #include "ser-base.h"
 #include "event-loop.h"
 
+#include "gdb_select.h"
 #include "gdb_string.h"
 #include <sys/time.h>
 #ifdef USE_WIN32API
@@ -202,9 +203,9 @@ ser_base_wait_for (struct serial *scb, i
       FD_SET (scb->fd, &exceptfds);
 
       if (timeout >= 0)
-	numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
+	numfds = gdb_select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
       else
-	numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, 0);
+	numfds = gdb_select (scb->fd + 1, &readfds, 0, &exceptfds, 0);
 
       if (numfds <= 0)
 	{
Index: src/gdb/serial.c
===================================================================
--- src.orig/gdb/serial.c	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/serial.c	2006-02-06 15:44:41.000000000 -0500
@@ -1,7 +1,7 @@
 /* Generic serial interface routines
 
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002 Free Software Foundation, Inc.
+   2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -233,6 +233,22 @@ serial_open (const char *name)
   return scb;
 }
 
+/* Return the open serial device for FD, if found, or NULL if FD
+   is not already opened.  */
+
+struct serial *
+serial_for_fd (int fd)
+{
+  struct serial *scb;
+  struct serial_ops *ops;
+
+  for (scb = scb_base; scb; scb = scb->next)
+    if (scb->fd == fd)
+      return scb;
+
+  return NULL;
+}
+
 struct serial *
 serial_fdopen (const int fd)
 {
@@ -246,12 +262,14 @@ serial_fdopen (const int fd)
 	return scb;
       }
 
-  ops = serial_interface_lookup ("hardwire");
+  ops = serial_interface_lookup ("terminal");
+  if (!ops)
+    ops = serial_interface_lookup ("hardwire");
 
   if (!ops)
     return NULL;
 
-  scb = XMALLOC (struct serial);
+  scb = XCALLOC (1, struct serial);
 
   scb->ops = ops;
 
@@ -524,6 +542,19 @@ serial_debug_p (struct serial *scb)
   return scb->debug_p || global_serial_debug_p;
 }
 
+#ifdef USE_WIN32API
+void
+serial_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
+{
+  if (scb->ops->wait_handle)
+    scb->ops->wait_handle (scb, read, except);
+  else
+    {
+      *read = (HANDLE) _get_osfhandle (scb->fd);
+      *except = NULL;
+    }
+}
+#endif
 
 #if 0
 /* The connect command is #if 0 because I hadn't thought of an elegant
Index: src/gdb/serial.h
===================================================================
--- src.orig/gdb/serial.h	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/serial.h	2006-02-06 15:44:41.000000000 -0500
@@ -1,5 +1,6 @@
 /* Remote serial support interface definitions for GDB, the GNU Debugger.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+   2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -22,6 +23,10 @@
 #ifndef SERIAL_H
 #define SERIAL_H
 
+#ifdef USE_WIN32API
+#include <windows.h>
+#endif
+
 struct ui_file;
 
 /* For most routines, if a failure is indicated, then errno should be
@@ -41,6 +46,10 @@ struct serial;
 
 extern struct serial *serial_open (const char *name);
 
+/* Find an already opened serial stream using a file handle.  */
+
+extern struct serial *serial_for_fd (int fd);
+
 /* Open a new serial stream using a file handle.  */
 
 extern struct serial *serial_fdopen (const int fd);
@@ -238,6 +247,13 @@ struct serial_ops
     /* 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);
+
+#ifdef USE_WIN32API
+    /* Return a handle to wait on, indicating available data from SCB
+       when signaled, in *READ.  Return a handle indicating errors
+       in *EXCEPT.  */
+    void (*wait_handle) (struct serial *scb, HANDLE *read, HANDLE *except);
+#endif /* USE_WIN32API */
   };
 
 /* Add a new serial interface to the interface list */
@@ -248,4 +264,12 @@ extern void serial_add_interface (struct
 
 extern void serial_log_command (const char *);
 
+#ifdef USE_WIN32API
+
+/* Windows-only: find or create handles that we can wait on for this
+   serial device.  */
+extern void serial_wait_handle (struct serial *, HANDLE *, HANDLE *);
+
+#endif /* USE_WIN32API */
+
 #endif /* SERIAL_H */
Index: src/gdb/gdb_select.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/gdb_select.h	2006-02-06 15:44:41.000000000 -0500
@@ -0,0 +1,37 @@
+/* Slightly more portable version of <sys/select.h>.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#if !defined(GDB_SELECT_H)
+#define GDB_SELECT_H
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef USE_WIN32API
+#include <winsock2.h>
+#endif
+
+extern int gdb_select (int n, fd_set *readfds, fd_set *writefds,
+		       fd_set *exceptfds, struct timeval *timeout);
+
+#endif /* !defined(GDB_STRING_H) */
Index: src/gdb/ser-tcp.c
===================================================================
--- src.orig/gdb/ser-tcp.c	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/ser-tcp.c	2006-02-06 15:44:41.000000000 -0500
@@ -1,6 +1,6 @@
 /* Serial interface for raw TCP connections on Un*x like systems.
 
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001, 2005
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -23,7 +23,7 @@
 #include "defs.h"
 #include "serial.h"
 #include "ser-base.h"
-#include "ser-unix.h"
+#include "ser-tcp.h"
 
 #include <sys/types.h>
 
@@ -56,8 +56,6 @@
 typedef int socklen_t;
 #endif
 
-static int net_open (struct serial *scb, const char *name);
-static void net_close (struct serial *scb);
 void _initialize_ser_tcp (void);
 
 /* seconds to wait for connect */
@@ -67,7 +65,7 @@ void _initialize_ser_tcp (void);
 
 /* Open a tcp socket */
 
-static int
+int
 net_open (struct serial *scb, const char *name)
 {
   char *port_str, hostname[100];
@@ -153,7 +151,7 @@ net_open (struct serial *scb, const char
     {
       /* looks like we need to wait for the connect */
       struct timeval t;
-      fd_set rset, wset;
+      fd_set rset, wset, eset;
       int polls = 0;
       FD_ZERO (&rset);
 
@@ -174,10 +172,13 @@ net_open (struct serial *scb, const char
 	  
 	  FD_SET (scb->fd, &rset);
 	  wset = rset;
+	  eset = rset;
 	  t.tv_sec = 0;
 	  t.tv_usec = 1000000 / POLL_INTERVAL;
 	  
-	  n = select (scb->fd + 1, &rset, &wset, NULL, &t);
+	  /* Windows returns connection failure in eset rather than wset.
+	     How perverse.  */
+	  n = select (scb->fd + 1, &rset, &wset, &eset, &t);
 	  polls++;
 	} 
       while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL);
@@ -194,7 +195,7 @@ net_open (struct serial *scb, const char
   {
     int res, err;
     socklen_t len;
-    len = sizeof(err);
+    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
@@ -230,7 +231,7 @@ net_open (struct serial *scb, const char
   return 0;
 }
 
-static void
+void
 net_close (struct serial *scb)
 {
   if (scb->fd < 0)
@@ -240,13 +241,13 @@ net_close (struct serial *scb)
   scb->fd = -1;
 }
 
-static int
+int
 net_read_prim (struct serial *scb, size_t count)
 {
   return recv (scb->fd, scb->buf, count, 0);
 }
 
-static int
+int
 net_write_prim (struct serial *scb, const void *buf, size_t count)
 {
   return send (scb->fd, buf, count, 0);
@@ -255,13 +256,12 @@ net_write_prim (struct serial *scb, cons
 void
 _initialize_ser_tcp (void)
 {
-  struct serial_ops *ops;
 #ifdef USE_WIN32API
-  WSADATA wsa_data;
-  if (WSAStartup (MAKEWORD (1, 0), &wsa_data) != 0)
-    /* WinSock is unavailable.  */
-    return;
-#endif
+  /* Do nothing; the TCP serial operations will be initialized in
+     ser-mingw.c.  */
+  return;
+#else
+  struct serial_ops *ops;
   ops = XMALLOC (struct serial_ops);
   memset (ops, 0, sizeof (struct serial_ops));
   ops->name = "tcp";
@@ -285,4 +285,5 @@ _initialize_ser_tcp (void)
   ops->read_prim = net_read_prim;
   ops->write_prim = net_write_prim;
   serial_add_interface (ops);
+#endif /* USE_WIN32API */
 }
Index: src/gdb/ser-tcp.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/ser-tcp.h	2006-02-06 15:44:41.000000000 -0500
@@ -0,0 +1,32 @@
+/* Serial interface for raw TCP connections on Un*x like systems.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef SER_TCP_H
+#define SER_TCP_H
+
+struct serial;
+
+extern int net_open (struct serial *scb, const char *name);
+extern void net_close (struct serial *scb);
+extern int net_read_prim (struct serial *scb, size_t count);
+extern int net_write_prim (struct serial *scb, const void *buf, size_t count);
+
+#endif
Index: src/gdb/inflow.c
===================================================================
--- src.orig/gdb/inflow.c	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/inflow.c	2006-02-06 15:44:41.000000000 -0500
@@ -1,6 +1,6 @@
 /* Low level interface to ptrace, for GDB when running under Unix.
    Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
-   1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -129,7 +129,6 @@ gdb_has_a_terminal (void)
 #endif
 
       gdb_has_a_terminal_flag = no;
-      stdin_serial = serial_fdopen (0);
       if (stdin_serial != NULL)
 	{
 	  our_ttystate = serial_get_tty_state (stdin_serial);
@@ -730,6 +729,18 @@ gdb_setpgid (void)
   return retval;
 }
 
+/* Get all the current tty settings (including whether we have a
+   tty at all!).  We can't do this in _initialize_inflow because
+   serial_fdopen() won't work until the serial_ops_list is
+   initialized, but we don't want to do it lazily either, so
+   that we can guarantee stdin_serial is opened if there is
+   a terminal.  */
+void
+initialize_stdin_serial (void)
+{
+  stdin_serial = serial_fdopen (0);
+}
+
 void
 _initialize_inflow (void)
 {
Index: src/gdb/terminal.h
===================================================================
--- src.orig/gdb/terminal.h	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/terminal.h	2006-02-06 15:44:41.000000000 -0500
@@ -1,5 +1,6 @@
 /* Terminal interface definitions for GDB, the GNU Debugger.
-   Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1995, 1996, 1999, 2000
+   Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1995, 1996, 1999, 2000,
+   2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -88,4 +89,7 @@ extern int job_control;
    we lack job control.  */
 extern int gdb_setpgid (void);
 
+/* Set up a serial structure describing standard input.  In inflow.c.  */
+extern void initialize_stdin_serial (void);
+
 #endif /* !defined (TERMINAL_H) */
Index: src/gdb/top.c
===================================================================
--- src.orig/gdb/top.c	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/top.c	2006-02-06 15:44:41.000000000 -0500
@@ -1550,6 +1550,8 @@ gdb_init (char *argv0)
   init_cli_cmds();
   init_main ();			/* But that omits this file!  Do it now */
 
+  initialize_stdin_serial ();
+
   async_init_signals ();
 
   /* We need a default language for parsing expressions, so simple things like
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS	2006-02-06 15:21:55.000000000 -0500
+++ src/gdb/NEWS	2006-02-06 15:44:41.000000000 -0500
@@ -41,6 +41,12 @@ detach-fork <n>			Delete a fork from the
 
 Morpho Technologies ms2		ms1-elf
 
+* Improved Windows host support
+
+GDB now builds as a cross debugger hosted on i686-mingw32, including
+native console support, and remote communications using either
+network sockets or serial ports.
+
 * REMOVED features
 
 The ARM rdi-share module.
Index: src/gdb/ser-mingw.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/ser-mingw.c	2006-02-06 15:44:41.000000000 -0500
@@ -0,0 +1,796 @@
+/* Serial interface for local (hardwired) serial ports on Windows systems
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "serial.h"
+#include "ser-base.h"
+#include "ser-tcp.h"
+
+#include <windows.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+void _initialize_ser_windows (void);
+
+struct ser_windows_state
+{
+  int in_progress;
+  OVERLAPPED ov;
+  DWORD lastCommMask;
+  HANDLE except_event;
+};
+
+/* Open up a real live device for serial I/O.  */
+
+static int
+ser_windows_open (struct serial *scb, const char *name)
+{
+  HANDLE h;
+  struct ser_windows_state *state;
+  COMMTIMEOUTS timeouts;
+
+  /* Only allow COM ports.  */
+  if (strncmp (name, "COM", 3) != 0)
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  h = CreateFile (name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+		  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+  if (h == INVALID_HANDLE_VALUE)
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  scb->fd = _open_osfhandle ((long) h, O_RDWR);
+  if (scb->fd < 0)
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  if (!SetCommMask (h, EV_RXCHAR))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  timeouts.ReadIntervalTimeout = MAXDWORD;
+  timeouts.ReadTotalTimeoutConstant = 0;
+  timeouts.ReadTotalTimeoutMultiplier = 0;
+  timeouts.WriteTotalTimeoutConstant = 0;
+  timeouts.WriteTotalTimeoutMultiplier = 0;
+  if (!SetCommTimeouts (h, &timeouts))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  state = xmalloc (sizeof (struct ser_windows_state));
+  memset (state, 0, sizeof (struct ser_windows_state));
+  scb->state = state;
+
+  /* Create a manual reset event to watch the input buffer.  */
+  state->ov.hEvent = CreateEvent (0, TRUE, FALSE, 0);
+
+  /* Create a (currently unused) handle to record exceptions.  */
+  state->except_event = CreateEvent (0, TRUE, FALSE, 0);
+
+  return 0;
+}
+
+/* Wait for the output to drain away, as opposed to flushing (discarding)
+   it.  */
+
+static int
+ser_windows_drain_output (struct serial *scb)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+
+  return (FlushFileBuffers (h) != 0) ? 0 : -1;
+}
+
+static int
+ser_windows_flush_output (struct serial *scb)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+
+  return (PurgeComm (h, PURGE_TXCLEAR) != 0) ? 0 : -1;
+}
+
+static int
+ser_windows_flush_input (struct serial *scb)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+
+  return (PurgeComm (h, PURGE_RXCLEAR) != 0) ? 0 : -1;
+}
+
+static int
+ser_windows_send_break (struct serial *scb)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+
+  if (SetCommBreak (h) == 0)
+    return -1;
+
+  /* Delay for 250 milliseconds.  */
+  Sleep (250);
+
+  if (ClearCommBreak (h))
+    return -1;
+
+  return 0;
+}
+
+static void
+ser_windows_raw (struct serial *scb)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+  DCB state;
+
+  if (GetCommState (h, &state) == 0)
+    return;
+
+  state.fParity = FALSE;
+  state.fOutxCtsFlow = FALSE;
+  state.fOutxDsrFlow = FALSE;
+  state.fDtrControl = DTR_CONTROL_ENABLE;
+  state.fDsrSensitivity = FALSE;
+  state.fOutX = FALSE;
+  state.fInX = FALSE;
+  state.fNull = FALSE;
+  state.fAbortOnError = FALSE;
+  state.ByteSize = 8;
+  state.Parity = NOPARITY;
+
+  scb->current_timeout = 0;
+
+  if (SetCommState (h, &state) == 0)
+    warning (_("SetCommState failed\n"));
+}
+
+static int
+ser_windows_setstopbits (struct serial *scb, int num)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+  DCB state;
+
+  if (GetCommState (h, &state) == 0)
+    return -1;
+
+  switch (num)
+    {
+    case SERIAL_1_STOPBITS:
+      state.StopBits = ONESTOPBIT;
+      break;
+    case SERIAL_1_AND_A_HALF_STOPBITS:
+      state.StopBits = ONE5STOPBITS;
+      break;
+    case SERIAL_2_STOPBITS:
+      state.StopBits = TWOSTOPBITS;
+      break;
+    default:
+      return 1;
+    }
+
+  return (SetCommState (h, &state) != 0) ? 0 : -1;
+}
+
+static int
+ser_windows_setbaudrate (struct serial *scb, int rate)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+  DCB state;
+
+  if (GetCommState (h, &state) == 0)
+    return -1;
+
+  state.BaudRate = rate;
+
+  return (SetCommState (h, &state) != 0) ? 0 : -1;
+}
+
+static void
+ser_windows_close (struct serial *scb)
+{
+  struct ser_windows_state *state;
+
+  /* Stop any pending selects.  */
+  CancelIo ((HANDLE) _get_osfhandle (scb->fd));
+  state = scb->state;
+  CloseHandle (state->ov.hEvent);
+  CloseHandle (state->except_event);
+
+  if (scb->fd < 0)
+    return;
+
+  close (scb->fd);
+  scb->fd = -1;
+
+  xfree (scb->state);
+}
+
+static void
+ser_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
+{
+  struct ser_windows_state *state;
+  COMSTAT status;
+  DWORD errors;
+  HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+
+  state = scb->state;
+
+  *except = state->except_event;
+  *read = state->ov.hEvent;
+
+  if (state->in_progress)
+    return;
+
+  /* Reset the mask - we are only interested in any characters which
+     arrive after this point, not characters which might have arrived
+     and already been read.  */
+
+  /* This really, really shouldn't be necessary - just the second one.
+     But otherwise an internal flag for EV_RXCHAR does not get
+     cleared, and we get a duplicated event, if the last batch
+     of characters included at least two arriving close together.  */
+  if (!SetCommMask (h, 0))
+    warning (_("ser_windows_wait_handle: reseting mask failed"));
+
+  if (!SetCommMask (h, EV_RXCHAR))
+    warning (_("ser_windows_wait_handle: reseting mask failed (2)"));
+
+  /* There's a potential race condition here; we must check cbInQue
+     and not wait if that's nonzero.  */
+
+  ClearCommError (h, &errors, &status);
+  if (status.cbInQue > 0)
+    {
+      SetEvent (state->ov.hEvent);
+      return;
+    }
+
+  state->in_progress = 1;
+  ResetEvent (state->ov.hEvent);
+  state->lastCommMask = -2;
+  if (WaitCommEvent (h, &state->lastCommMask, &state->ov))
+    {
+      gdb_assert (state->lastCommMask & EV_RXCHAR);
+      SetEvent (state->ov.hEvent);
+    }
+  else
+    gdb_assert (GetLastError () == ERROR_IO_PENDING);
+}
+
+static int
+ser_windows_read_prim (struct serial *scb, size_t count)
+{
+  struct ser_windows_state *state;
+  OVERLAPPED ov;
+  DWORD bytes_read, bytes_read_tmp;
+  HANDLE h;
+  gdb_byte *p;
+
+  state = scb->state;
+  if (state->in_progress)
+    {
+      WaitForSingleObject (state->ov.hEvent, INFINITE);
+      state->in_progress = 0;
+      ResetEvent (state->ov.hEvent);
+    }
+
+  memset (&ov, 0, sizeof (OVERLAPPED));
+  ov.hEvent = CreateEvent (0, FALSE, FALSE, 0);
+  h = (HANDLE) _get_osfhandle (scb->fd);
+
+  if (!ReadFile (h, scb->buf, /* count */ 1, &bytes_read, &ov))
+    {
+      if (GetLastError () != ERROR_IO_PENDING
+	  || !GetOverlappedResult (h, &ov, &bytes_read, TRUE))
+	bytes_read = -1;
+    }
+
+  CloseHandle (ov.hEvent);
+  return bytes_read;
+}
+
+static int
+ser_windows_write_prim (struct serial *scb, const void *buf, size_t len)
+{
+  struct ser_windows_state *state;
+  OVERLAPPED ov;
+  DWORD bytes_written;
+  HANDLE h;
+
+  memset (&ov, 0, sizeof (OVERLAPPED));
+  ov.hEvent = CreateEvent (0, FALSE, FALSE, 0);
+  h = (HANDLE) _get_osfhandle (scb->fd);
+  if (!WriteFile (h, buf, len, &bytes_written, &ov))
+    {
+      if (GetLastError () != ERROR_IO_PENDING
+	  || !GetOverlappedResult (h, &ov, &bytes_written, TRUE))
+	bytes_written = -1;
+    }
+
+  CloseHandle (ov.hEvent);
+  return bytes_written;
+}
+
+struct ser_console_state
+{
+  HANDLE read_event;
+  HANDLE except_event;
+
+  HANDLE start_select;
+  HANDLE stop_select;
+};
+
+static DWORD WINAPI
+console_select_thread (void *arg)
+{
+  struct serial *scb = arg;
+  struct ser_console_state *state, state_copy;
+  int event_index, fd;
+  HANDLE h;
+
+  /* Copy useful information out of the control block, to make sure
+     that we do not race with freeing it.  */
+  state_copy = *(struct ser_console_state *) scb->state;
+  state = &state_copy;
+  fd = scb->fd;
+
+  h = (HANDLE) _get_osfhandle (fd);
+
+  while (1)
+    {
+      HANDLE wait_events[2];
+      INPUT_RECORD record;
+      DWORD n_records;
+
+      wait_events[0] = state->start_select;
+      wait_events[1] = state->stop_select;
+
+      if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE) != WAIT_OBJECT_0)
+	{
+	  CloseHandle (state->stop_select);
+	  return 0;
+	}
+
+    retry:
+      wait_events[0] = state->stop_select;
+      wait_events[1] = h;
+
+      event_index = WaitForMultipleObjects (2, wait_events, FALSE, INFINITE);
+
+      if (event_index == WAIT_OBJECT_0
+	  || WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0)
+	{
+	  CloseHandle (state->stop_select);
+	  return 0;
+	}
+
+      if (event_index != WAIT_OBJECT_0 + 1)
+	{
+	  /* Wait must have failed; assume an error has occured, e.g.
+	     the handle has been closed.  */
+	  SetEvent (state->except_event);
+	  continue;
+	}
+
+      /* We've got a pending event on the console.  See if it's
+	 of interest.  */
+      if (!PeekConsoleInput (h, &record, 1, &n_records) || n_records != 1)
+	{
+	  /* Something went wrong.  Maybe the console is gone.  */
+	  SetEvent (state->except_event);
+	  continue;
+	}
+
+      if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
+	{
+	  /* This is really a keypress.  */
+	  SetEvent (state->read_event);
+	  continue;
+	}
+
+      /* Otherwise discard it and wait again.  */
+      ReadConsoleInput (h, &record, 1, &n_records);
+      goto retry;
+    }
+}
+
+static int
+fd_is_pipe (int fd)
+{
+  if (PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, NULL, NULL))
+    return 1;
+  else
+    return 0;
+}
+
+static DWORD WINAPI
+pipe_select_thread (void *arg)
+{
+  struct serial *scb = arg;
+  struct ser_console_state *state, state_copy;
+  int event_index, fd;
+  HANDLE h;
+
+  /* Copy useful information out of the control block, to make sure
+     that we do not race with freeing it.  */
+  state_copy = *(struct ser_console_state *) scb->state;
+  state = &state_copy;
+  fd = scb->fd;
+
+  h = (HANDLE) _get_osfhandle (fd);
+
+  while (1)
+    {
+      HANDLE wait_events[2];
+      DWORD n_avail;
+
+      wait_events[0] = state->start_select;
+      wait_events[1] = state->stop_select;
+
+      if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE) != WAIT_OBJECT_0)
+	{
+	  CloseHandle (state->stop_select);
+	  return 0;
+	}
+
+    retry:
+      if (!PeekNamedPipe (h, NULL, 0, NULL, &n_avail, NULL))
+	{
+	  SetEvent (state->except_event);
+	  continue;
+	}
+
+      if (n_avail > 0)
+	{
+	  SetEvent (state->read_event);
+	  continue;
+	}
+
+      if (WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0)
+	{
+	  CloseHandle (state->stop_select);
+	  return 0;
+	}
+
+      Sleep (10);
+      goto retry;
+    }
+}
+
+static void
+ser_console_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
+{
+  struct ser_console_state *state = scb->state;
+
+  if (state == NULL)
+    {
+      DWORD threadId;
+      int is_tty;
+
+      is_tty = isatty (scb->fd);
+      if (!is_tty && !fd_is_pipe (scb->fd))
+	{
+	  *read = NULL;
+	  *except = NULL;
+	  return;
+	}
+
+      state = xmalloc (sizeof (struct ser_console_state));
+      memset (state, 0, sizeof (struct ser_console_state));
+      scb->state = state;
+
+      /* Create auto reset events to wake and terminate the select thread.  */
+      state->start_select = CreateEvent (0, FALSE, FALSE, 0);
+      state->stop_select = CreateEvent (0, FALSE, FALSE, 0);
+
+      /* Create our own events to report read and exceptions separately.
+	 The exception event is currently never used.  */
+      state->read_event = CreateEvent (0, FALSE, FALSE, 0);
+      state->except_event = CreateEvent (0, FALSE, FALSE, 0);
+
+      /* And finally start the select thread.  */
+      if (is_tty)
+	CreateThread (NULL, 0, console_select_thread, scb, 0, &threadId);
+      else
+	CreateThread (NULL, 0, pipe_select_thread, scb, 0, &threadId);
+    }
+
+  ResetEvent (state->read_event);
+  ResetEvent (state->except_event);
+
+  SetEvent (state->start_select);
+
+  *read = state->read_event;
+  *except = state->except_event;
+}
+
+static void
+ser_console_close (struct serial *scb)
+{
+  struct ser_console_state *state = scb->state;
+
+  if (scb->state)
+    {
+      SetEvent (state->stop_select);
+
+      CloseHandle (state->read_event);
+      CloseHandle (state->except_event);
+
+      xfree (scb->state);
+    }
+}
+
+struct ser_console_ttystate
+{
+  int is_a_tty;
+};
+
+static serial_ttystate
+ser_console_get_tty_state (struct serial *scb)
+{
+  if (isatty (scb->fd))
+    {
+      struct ser_console_ttystate *state;
+      state = (struct ser_console_ttystate *) xmalloc (sizeof *state);
+      state->is_a_tty = 1;
+      return state;
+    }
+  else
+    return NULL;
+}
+
+struct net_windows_state
+{
+  HANDLE read_event;
+  HANDLE except_event;
+
+  HANDLE start_select;
+  HANDLE stop_select;
+  HANDLE sock_event;
+};
+
+static DWORD WINAPI
+net_windows_select_thread (void *arg)
+{
+  struct serial *scb = arg;
+  struct net_windows_state *state, state_copy;
+  int event_index, fd;
+
+  /* Copy useful information out of the control block, to make sure
+     that we do not race with freeing it.  */
+  state_copy = *(struct net_windows_state *) scb->state;
+  state = &state_copy;
+  fd = scb->fd;
+
+  while (1)
+    {
+      HANDLE wait_events[2];
+      WSANETWORKEVENTS events;
+
+      wait_events[0] = state->start_select;
+      wait_events[1] = state->stop_select;
+
+      if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE) != WAIT_OBJECT_0)
+	{
+	  CloseHandle (state->stop_select);
+	  return 0;
+	}
+
+      wait_events[0] = state->stop_select;
+      wait_events[1] = state->sock_event;
+
+      event_index = WaitForMultipleObjects (2, wait_events, FALSE, INFINITE);
+
+      if (event_index == WAIT_OBJECT_0
+	  || WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0)
+	{
+	  CloseHandle (state->stop_select);
+	  return 0;
+	}
+
+      if (event_index != WAIT_OBJECT_0 + 1)
+	{
+	  /* Some error has occured.  Assume that this is an error
+	     condition.  */
+	  SetEvent (state->except_event);
+	  continue;
+	}
+
+      /* Enumerate the internal network events, and reset the object that
+	 signalled us to catch the next event.  */
+      WSAEnumNetworkEvents (fd, state->sock_event, &events);
+
+      if (events.lNetworkEvents & FD_READ)
+	SetEvent (state->read_event);
+
+      if (events.lNetworkEvents & FD_CLOSE)
+	SetEvent (state->except_event);
+    }
+}
+
+static void
+net_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
+{
+  struct net_windows_state *state = scb->state;
+
+  ResetEvent (state->read_event);
+  ResetEvent (state->except_event);
+
+  SetEvent (state->start_select);
+
+  *read = state->read_event;
+  *except = state->except_event;
+}
+
+static int
+net_windows_open (struct serial *scb, const char *name)
+{
+  struct net_windows_state *state;
+  int ret;
+  DWORD threadId;
+
+  ret = net_open (scb, name);
+  if (ret != 0)
+    return ret;
+
+  state = xmalloc (sizeof (struct net_windows_state));
+  memset (state, 0, sizeof (struct net_windows_state));
+  scb->state = state;
+
+  /* Create auto reset events to wake and terminate the select thread.  */
+  state->start_select = CreateEvent (0, FALSE, FALSE, 0);
+  state->stop_select = CreateEvent (0, FALSE, FALSE, 0);
+
+  /* Associate an event with the socket.  */
+  state->sock_event = CreateEvent (0, TRUE, FALSE, 0);
+  WSAEventSelect (scb->fd, state->sock_event, FD_READ | FD_CLOSE);
+
+  /* Create our own events to report read and close separately.  */
+  state->read_event = CreateEvent (0, FALSE, FALSE, 0);
+  state->except_event = CreateEvent (0, FALSE, FALSE, 0);
+
+  /* And finally start the select thread.  */
+  CreateThread (NULL, 0, net_windows_select_thread, scb, 0, &threadId);
+
+  return 0;
+}
+
+
+static void
+net_windows_close (struct serial *scb)
+{
+  struct net_windows_state *state = scb->state;
+
+  SetEvent (state->stop_select);
+
+  CloseHandle (state->read_event);
+  CloseHandle (state->except_event);
+  CloseHandle (state->start_select);
+  CloseHandle (state->sock_event);
+
+  xfree (scb->state);
+
+  net_close (scb);
+}
+
+void
+_initialize_ser_windows (void)
+{
+  WSADATA wsa_data;
+  struct serial_ops *ops;
+
+  /* First register the serial port driver.  */
+
+  ops = XMALLOC (struct serial_ops);
+  memset (ops, 0, sizeof (struct serial_ops));
+  ops->name = "hardwire";
+  ops->next = 0;
+  ops->open = ser_windows_open;
+  ops->close = ser_windows_close;
+
+  ops->flush_output = ser_windows_flush_output;
+  ops->flush_input = ser_windows_flush_input;
+  ops->send_break = ser_windows_send_break;
+
+  /* These are only used for stdin; we do not need them for serial
+     ports, so supply the standard dummies.  */
+  ops->get_tty_state = ser_base_get_tty_state;
+  ops->set_tty_state = ser_base_set_tty_state;
+  ops->print_tty_state = ser_base_print_tty_state;
+  ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
+
+  ops->go_raw = ser_windows_raw;
+  ops->setbaudrate = ser_windows_setbaudrate;
+  ops->setstopbits = ser_windows_setstopbits;
+  ops->drain_output = ser_windows_drain_output;
+  ops->readchar = ser_base_readchar;
+  ops->write = ser_base_write;
+  ops->async = ser_base_async;
+  ops->read_prim = ser_windows_read_prim;
+  ops->write_prim = ser_windows_write_prim;
+  ops->wait_handle = ser_windows_wait_handle;
+
+  serial_add_interface (ops);
+
+  /* Next create the dummy serial driver used for terminals.  We only
+     provide the TTY-related methods.  */
+
+  ops = XMALLOC (struct serial_ops);
+  memset (ops, 0, sizeof (struct serial_ops));
+
+  ops->name = "terminal";
+  ops->next = 0;
+
+  ops->close = ser_console_close;
+  ops->get_tty_state = ser_console_get_tty_state;
+  ops->set_tty_state = ser_base_set_tty_state;
+  ops->print_tty_state = ser_base_print_tty_state;
+  ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
+  ops->drain_output = ser_base_drain_output;
+  ops->wait_handle = ser_console_wait_handle;
+
+  serial_add_interface (ops);
+
+  /* If WinSock works, register the TCP/UDP socket driver.  */
+
+  if (WSAStartup (MAKEWORD (1, 0), &wsa_data) != 0)
+    /* WinSock is unavailable.  */
+    return;
+
+  ops = XMALLOC (struct serial_ops);
+  memset (ops, 0, sizeof (struct serial_ops));
+  ops->name = "tcp";
+  ops->next = 0;
+  ops->open = net_windows_open;
+  ops->close = net_windows_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;
+  ops->get_tty_state = ser_base_get_tty_state;
+  ops->set_tty_state = ser_base_set_tty_state;
+  ops->print_tty_state = ser_base_print_tty_state;
+  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;
+  ops->write_prim = net_write_prim;
+  ops->wait_handle = net_windows_wait_handle;
+  serial_add_interface (ops);
+}
Index: src/gdb/config/i386/xm-mingw.h
===================================================================
--- src.orig/gdb/config/i386/xm-mingw.h	2006-02-06 15:23:13.000000000 -0500
+++ src/gdb/config/i386/xm-mingw.h	2006-02-06 15:45:37.000000000 -0500
@@ -28,3 +28,4 @@ char *mingw_strerror (int);
 # define strerror mingw_strerror
 #endif
 
+int mingw_select (int, void *, void *, void *, void *);
Index: src/gdb/mingw-hdep.c
===================================================================
--- src.orig/gdb/mingw-hdep.c	2006-02-06 15:22:52.000000000 -0500
+++ src/gdb/mingw-hdep.c	2006-02-06 15:50:58.000000000 -0500
@@ -25,7 +25,10 @@
 #define IN_MINGW_HDEP
 
 #include "defs.h"
+#include "serial.h"
 
+#include "gdb_assert.h"
+#include "gdb_select.h"
 #include "gdb_string.h"
 
 #include <windows.h>
@@ -65,3 +68,120 @@ mingw_strerror (int errnum)
 
   return buffer;
 }
+
+/* Wrapper for select.  On Windows systems, where the select interface
+   only works for sockets, this uses the GDB serial abstraction to
+   handle sockets, consoles, pipes, and serial ports.
+
+   The arguments to this function are the same as the traditional
+   arguments to select; the void * usage is necessary to avoid
+   including <windows.h> in order to prototype this function.  */
+
+int
+mingw_select (int n, void *readfds_, void *writefds_, void *exceptfds_,
+	      void *timeout_)
+{
+  static HANDLE never_handle;
+  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+  HANDLE h;
+  DWORD event;
+  DWORD num_handles;
+  int fd;
+  int num_ready;
+  int indx;
+  struct timeval *timeout = timeout_;
+  fd_set *readfds = readfds_, *writefds = writefds_, *exceptfds = exceptfds_;
+
+  num_ready = 0;
+  num_handles = 0;
+  for (fd = 0; fd < n; ++fd)
+    {
+      HANDLE read = NULL, except = NULL;
+      struct serial *scb;
+
+      /* There is no support yet for WRITEFDS.  At present, this isn't
+	 used by GDB -- but we do not want to silently ignore WRITEFDS
+	 if something starts using it.  */
+      gdb_assert (!writefds || !FD_ISSET (fd, writefds));
+
+      if (!FD_ISSET (fd, readfds)
+	  && !FD_ISSET (fd, exceptfds))
+	continue;
+      h = (HANDLE) _get_osfhandle (fd);
+
+      scb = serial_for_fd (fd);
+      if (scb)
+	serial_wait_handle (scb, &read, &except);
+
+      if (read == NULL)
+	read = h;
+      if (except == NULL)
+	{
+	  if (!never_handle)
+	    never_handle = CreateEvent (0, FALSE, FALSE, 0);
+
+	  except = never_handle;
+	}
+
+      if (FD_ISSET (fd, readfds))
+	{
+	  gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
+	  handles[num_handles++] = read;
+	}
+
+      if (FD_ISSET (fd, exceptfds))
+	{
+	  gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
+	  handles[num_handles++] = except;
+	}
+    }
+  /* If we don't need to wait for any handles, we are done.  */
+  if (!num_handles)
+    return 0;
+  event = WaitForMultipleObjects (num_handles,
+				  handles,
+				  FALSE,
+				  timeout
+				  ? (timeout->tv_sec * 1000 + timeout->tv_usec)
+				  : INFINITE);
+  /* EVENT can only be a value in the WAIT_ABANDONED_0 range if the
+     HANDLES included an abandoned mutex.  Since GDB doesn't use
+     mutexes, that should never occur.  */
+  gdb_assert (!(WAIT_ABANDONED_0 <= event
+		&& event < WAIT_ABANDONED_0 + num_handles));
+  if (event == WAIT_FAILED)
+    return -1;
+  if (event == WAIT_TIMEOUT)
+    return 0;
+  /* Run through the READFDS, clearing bits corresponding to descriptors
+     for which input is unavailable.  */
+  h = handles[event - WAIT_OBJECT_0];
+  for (fd = 0, indx = 0; fd < n; ++fd)
+    {
+      HANDLE fd_h;
+
+      if (FD_ISSET (fd, readfds))
+	{
+	  fd_h = handles[indx++];
+	  /* This handle might be ready, even though it wasn't the handle
+	     returned by WaitForMultipleObjects.  */
+	  if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
+	    FD_CLR (fd, readfds);
+	  else
+	    num_ready++;
+	}
+
+      if (FD_ISSET (fd, exceptfds))
+	{
+	  fd_h = handles[indx++];
+	  /* This handle might be ready, even though it wasn't the handle
+	     returned by WaitForMultipleObjects.  */
+	  if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
+	    FD_CLR (fd, exceptfds);
+	  else
+	    num_ready++;
+	}
+    }
+
+  return num_ready;
+}


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