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


Here's a version that puts gdb_select off in its own file, and uses it
everywhere that it can be used (which does not include ser-tcp.c,
sorry).

-- 
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, inflow.o, mingw-hdep.o, posix-hdep.o, ser-base.o)
	(ser-tcp.o, ser-unix.o): Update.
	(ser-mingw.o): New rule.
	* configure: Regenerated.
	* configure.ac: Add ser-mingw.o for mingw32.
	* ser-mingw.c: New file.
	* event-loop.c: Include "gdb_select.h".
	(gdb_select): Remove, moved to mingw-hdep.c and posix-hdep.c.
	* 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.
	Document why we can not use gdb_select.
	(_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.
	(handle_sigio): Use gdb_select.
	(initialize_stdin_serial): New function.
	* terminal.h (initialize_stdin_serial): New prototype.
	* top.c (gdb_init): Call initialize_stdin_serial.
	* mingw-hdep.c (gdb_select): New function, moved from gdb_select in
	event-loop.c.  Add exception condition support.  Use serial_for_fd
	and serial_wait_handle.  Fix timeout handling.
	* posix-hdep.c: Include "gdb_select.h".
	(gdb_select): New function.
	* remote-st.c (connect_command): Use gdb_select.
	* ser-unix.c: Include "gdb_select.h".
	(hardwire_send_break, wait_for): Use gdb_select.

Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2006-02-09 17:26:52.000000000 -0500
+++ src/gdb/Makefile.in	2006-02-09 17:32:27.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
@@ -1442,7 +1444,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 \
@@ -1922,7 +1924,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)
@@ -2129,7 +2131,7 @@ inf-loop.o: inf-loop.c $(defs_h) $(infer
 	$(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h)
 inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
 	$(serial_h) $(terminal_h) $(target_h) $(gdbthread_h) $(gdb_string_h) \
-	$(inflow_h)
+	$(inflow_h) $(gdb_select_h)
 inf-ptrace.o: inf-ptrace.c $(defs_h) $(command_h) $(inferior_h) $(inflow_h) \
 	$(gdbcore_h) $(regcache_h) $(gdb_assert_h) \
 	$(gdb_string_h) $(gdb_ptrace_h) $(gdb_wait_h) $(inf_child_h)
@@ -2282,7 +2284,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) \
@@ -2378,7 +2381,7 @@ p-exp.o: p-exp.c $(defs_h) $(gdb_string_
 p-lang.o: p-lang.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
 	$(expression_h) $(parser_defs_h) $(language_h) $(p_lang_h) \
 	$(valprint_h) $(value_h)
-posix-hdep.o: posix-hdep.c $(defs_h)
+posix-hdep.o: posix-hdep.c $(defs_h) $(gdb_select_h)
 ppc-bdm.o: ppc-bdm.c $(defs_h) $(gdbcore_h) $(gdb_string_h) $(frame_h) \
 	$(inferior_h) $(bfd_h) $(symfile_h) $(target_h) $(gdbcmd_h) \
 	$(objfiles_h) $(gdb_stabs_h) $(serial_h) $(ocd_h) $(ppc_tdep_h) \
@@ -2515,13 +2518,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)
+	$(terminal_h) $(gdb_select_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-09 17:26:52.000000000 -0500
+++ src/gdb/configure	2006-02-09 17:26:52.000000000 -0500
@@ -20097,7 +20097,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-09 17:26:52.000000000 -0500
+++ src/gdb/configure.ac	2006-02-09 17:26:52.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.
@@ -1202,7 +1203,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-09 17:25:51.000000000 -0500
+++ src/gdb/event-loop.c	2006-02-09 17:26:52.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,97 +733,6 @@ 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.  */
-
-static 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;
-#else
-  return select (n, readfds, writefds, exceptfds, timeout);
-#endif
-}
-
 /* Called by gdb_do_one_event to wait for new events on the 
    monitored file descriptors. Queue file events as they are 
    detected by the poll. 
Index: src/gdb/ser-base.c
===================================================================
--- src.orig/gdb/ser-base.c	2006-02-09 17:25:51.000000000 -0500
+++ src/gdb/ser-base.c	2006-02-09 17:26:52.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-09 17:25:51.000000000 -0500
+++ src/gdb/serial.c	2006-02-09 17:26:52.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-09 17:25:51.000000000 -0500
+++ src/gdb/serial.h	2006-02-09 17:26:52.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-09 17:27:11.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_SELECT_H) */
Index: src/gdb/ser-tcp.c
===================================================================
--- src.orig/gdb/ser-tcp.c	2006-02-09 17:25:51.000000000 -0500
+++ src/gdb/ser-tcp.c	2006-02-09 17:26:52.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,19 @@ 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);
+	  /* POSIX systems return connection success or failure by signalling
+	     wset.  Windows systems return success in wset and failure in
+	     eset.
+
+	     We must call select here, rather than gdb_select, because
+	     the serial structure has not yet been initialized - the
+	     MinGW select wrapper will not know that this FD refers
+	     to a socket.  */
+	  n = select (scb->fd + 1, &rset, &wset, &eset, &t);
 	  polls++;
 	} 
       while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL);
@@ -194,7 +201,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 +237,7 @@ net_open (struct serial *scb, const char
   return 0;
 }
 
-static void
+void
 net_close (struct serial *scb)
 {
   if (scb->fd < 0)
@@ -240,13 +247,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 +262,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 +291,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-09 17:26:52.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-09 17:25:51.000000000 -0500
+++ src/gdb/inflow.c	2006-02-09 17:26:52.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.
@@ -32,9 +32,7 @@
 #include "gdb_string.h"
 #include <signal.h>
 #include <fcntl.h>
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
+#include "gdb_select.h"
 
 #include "inflow.h"
 
@@ -129,7 +127,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);
@@ -643,7 +640,7 @@ handle_sigio (int signo)
 
   FD_ZERO (&readfds);
   FD_SET (target_activity_fd, &readfds);
-  numfds = select (target_activity_fd + 1, &readfds, NULL, NULL, NULL);
+  numfds = gdb_select (target_activity_fd + 1, &readfds, NULL, NULL, NULL);
   if (numfds >= 0 && FD_ISSET (target_activity_fd, &readfds))
     {
 #ifndef _WIN32
@@ -730,6 +727,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-09 17:25:51.000000000 -0500
+++ src/gdb/terminal.h	2006-02-09 17:26:52.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-09 17:25:51.000000000 -0500
+++ src/gdb/top.c	2006-02-09 17:26:52.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-09 17:25:51.000000000 -0500
+++ src/gdb/NEWS	2006-02-09 17:26:52.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-09 17:26:52.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/mingw-hdep.c
===================================================================
--- src.orig/gdb/mingw-hdep.c	2006-02-09 17:26:52.000000000 -0500
+++ src/gdb/mingw-hdep.c	2006-02-09 17:26:52.000000000 -0500
@@ -21,7 +21,10 @@
    Boston, MA 02110-1301, USA.  */
 
 #include "defs.h"
+#include "serial.h"
 
+#include "gdb_assert.h"
+#include "gdb_select.h"
 #include "gdb_string.h"
 
 #include <windows.h>
@@ -69,3 +72,124 @@ safe_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 on POSIX platforms.  */
+
+int
+gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	    struct timeval *timeout)
+{
+  static HANDLE never_handle;
+  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+  HANDLE h;
+  DWORD event;
+  DWORD num_handles;
+  int fd;
+  int num_ready;
+  int indx;
+
+  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)
+    {
+      if (timeout)
+	Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
+
+      return 0;
+    }
+
+  event = WaitForMultipleObjects (num_handles,
+				  handles,
+				  FALSE,
+				  timeout
+				  ? (timeout->tv_sec * 1000
+				     + timeout->tv_usec / 1000)
+				  : 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: src/gdb/posix-hdep.c
===================================================================
--- src.orig/gdb/posix-hdep.c	2006-02-09 17:26:52.000000000 -0500
+++ src/gdb/posix-hdep.c	2006-02-09 17:26:52.000000000 -0500
@@ -22,6 +22,8 @@
 
 #include "defs.h"
 
+#include "gdb_select.h"
+
 /* The strerror() function can return NULL for errno values that are
    out of range.  Provide a "safe" version that always returns a
    printable string. */
@@ -41,3 +43,11 @@ safe_strerror (int errnum)
   return (msg);
 }
 
+/* Wrapper for select.  Nothing special needed on POSIX platforms.  */
+
+int
+gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	    struct timeval *timeout)
+{
+  return select (n, readfds, writefds, exceptfds, timeout);
+}
Index: src/gdb/remote-st.c
===================================================================
--- src.orig/gdb/remote-st.c	2006-02-09 17:25:51.000000000 -0500
+++ src/gdb/remote-st.c	2006-02-09 17:26:52.000000000 -0500
@@ -704,7 +704,7 @@ connect_command (char *args, int fromtty
 	{
 	  FD_SET (0, &readfds);
 	  FD_SET (deprecated_serial_fd (st2000_desc), &readfds);
-	  numfds = select (sizeof (readfds) * 8, &readfds, 0, 0, 0);
+	  numfds = gdb_select (sizeof (readfds) * 8, &readfds, 0, 0, 0);
 	}
       while (numfds == 0);
 
Index: src/gdb/ser-unix.c
===================================================================
--- src.orig/gdb/ser-unix.c	2006-02-09 17:25:51.000000000 -0500
+++ src/gdb/ser-unix.c	2006-02-09 17:26:52.000000000 -0500
@@ -31,6 +31,7 @@
 #include <sys/socket.h>
 #include <sys/time.h>
 
+#include "gdb_select.h"
 #include "gdb_string.h"
 
 #ifdef HAVE_TERMIOS
@@ -365,7 +366,7 @@ hardwire_send_break (struct serial *scb)
        the full length of time.  I think that is OK.  */
     timeout.tv_sec = 0;
     timeout.tv_usec = 250000;
-    select (0, 0, 0, 0, &timeout);
+    gdb_select (0, 0, 0, 0, &timeout);
     status = ioctl (scb->fd, TIOCCBRK, 0);
     return status;
   }
@@ -448,9 +449,9 @@ wait_for (struct serial *scb, int timeou
       FD_SET (scb->fd, &readfds);
 
       if (timeout >= 0)
-	numfds = select (scb->fd + 1, &readfds, 0, 0, &tv);
+	numfds = gdb_select (scb->fd + 1, &readfds, 0, 0, &tv);
       else
-	numfds = select (scb->fd + 1, &readfds, 0, 0, 0);
+	numfds = gdb_select (scb->fd + 1, &readfds, 0, 0, 0);
 
       if (numfds <= 0)
 	if (numfds == 0)


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