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

Daniel Jacobowitz
2006-02-10T22:02:23Z

On Fri, Feb 10, 2006 at 09:45:58PM +0100, Mark Kettenis wrote:
> > Date: Thu, 9 Feb 2006 17:38:32 -0500
> > From: Daniel Jacobowitz <drow@false.org>
> >
> > 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).
>
> It's a pity ser-tcp.c can't use it. Can you add a comment explaining
> why? Otherwise, this looks fine to me (and the safe_strerror patch
> looks fine too). Thanks for doing this.

I already had :-)

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. */

Here's what I checked in after testing.

--
Daniel Jacobowitz
CodeSourcery

2006-02-10 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-10 12:41:37.000000000 -0500
+++ src/gdb/Makefile.in 2006-02-10 12:42:13.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) $(gdb_string_h)
+posix-hdep.o: posix-hdep.c $(defs_h) $(gdb_string_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-10 12:41:28.000000000 -0500
+++ src/gdb/configure 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/configure.ac 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/event-loop.c 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/ser-base.c 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/serial.c 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/serial.h 2006-02-10 12:42:02.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-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/ser-tcp.c 2006-02-10 12:42:02.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-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/inflow.c 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/terminal.h 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/top.c 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/NEWS 2006-02-10 12:42:02.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-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/mingw-hdep.c 2006-02-10 12:42:02.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-10 12:41:57.000000000 -0500
+++ src/gdb/posix-hdep.c 2006-02-10 12:42:02.000000000 -0500
@@ -24,6 +24,8 @@

#include "gdb_string.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. */
@@ -43,3 +45,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-10 12:41:28.000000000 -0500
+++ src/gdb/remote-st.c 2006-02-10 12:42:02.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-10 12:41:28.000000000 -0500
+++ src/gdb/ser-unix.c 2006-02-10 12:42:02.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)