* NEWS: Mention native Windows support.
authorDaniel Jacobowitz <drow@false.org>
Fri, 10 Feb 2006 22:01:43 +0000 (22:01 +0000)
committerDaniel Jacobowitz <drow@false.org>
Fri, 10 Feb 2006 22:01:43 +0000 (22:01 +0000)
* 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.

20 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/NEWS
gdb/configure
gdb/configure.ac
gdb/event-loop.c
gdb/gdb_select.h [new file with mode: 0644]
gdb/inflow.c
gdb/mingw-hdep.c
gdb/posix-hdep.c
gdb/remote-st.c
gdb/ser-base.c
gdb/ser-mingw.c [new file with mode: 0644]
gdb/ser-tcp.c
gdb/ser-tcp.h [new file with mode: 0644]
gdb/ser-unix.c
gdb/serial.c
gdb/serial.h
gdb/terminal.h
gdb/top.c

index c73df203a130d4ab3d7f45c53209d76f4674537f..400104d68760eb42a03e324dd937490d8d87242a 100644 (file)
@@ -1,3 +1,45 @@
+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.
+
 2006-02-10  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * Makefile.in (mingw-hdep.o, posix-hdep.o): New dependencies.
index 9c0f30bbe4ec15b0d781ee0b292bf412dab87c4a..779c9d0766811334d6d63f1b1ac5b2d5b8abbea8 100644 (file)
@@ -694,6 +694,7 @@ gdb_obstack_h = gdb_obstack.h $(obstack_h)
 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
@@ -767,6 +768,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
@@ -1445,7 +1447,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) $(symtab_h) $(gdbtypes_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) $(inferior_h) $(target_h) $(event_loop_h) \
        $(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_h) $(gdbcmd_h) $(memattr_h) \
        $(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_h) $(expression_h) $(value_h) \
 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) \
@@ -2517,13 +2520,15 @@ ser-e7kpc.o: ser-e7kpc.c $(defs_h) $(serial_h) $(gdb_string_h)
 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 900442da1e797645cfb25f2d856c5836424e179a..c42313cde2c906de3887f9595c5a4aecac48f9bd 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -41,6 +41,12 @@ detach-fork <n>                      Delete a fork from the list of forks
 
 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 d9ea4232270aa026ae147223c1bad502d4ee3746..cf547b72d4a6ce670c74b92bc792ccddd373b44d 100755 (executable)
@@ -20097,7 +20097,7 @@ SER_HARDWIRE="ser-base.o ser-unix.o ser-pipe.o ser-tcp.o"
 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 55dc2be75b3869333849b0cb83040f95244daafd..1861275a2dac5b66fcd91a0974ed2240c50158d7 100644 (file)
@@ -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-pipe.o ser-tcp.o"
 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 4f859b115c6ce8b195ea9f147db75c8e3791e10a..671528f25b4ea8edd0254c0d730ee49e47cd31a8 100644 (file)
@@ -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. 
diff --git a/gdb/gdb_select.h b/gdb/gdb_select.h
new file mode 100644 (file)
index 0000000..1054d6e
--- /dev/null
@@ -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 adfec1b326b4738140a35af0fbd7f60f44a3d99d..83a0c9d828155cce4704383ebbcc18275d606fab 100644 (file)
@@ -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 1318cfdd38e69878f91c96c6138b74b7735d7b21..79b23dc2556b65669676678069298d81cb0a69c0 100644 (file)
    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 ca405f985f585a4966a092b4c2e869b2e487663a..3ad6f922e82dc713d2bfe8100c9f42ad7d3ed362 100644 (file)
@@ -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 6d7ea19f51eff8463a49a3d717e2b915cc0622f3..c7c39a1450d5dac91c7b497490696ff09d7dc4c5 100644 (file)
@@ -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 a43f08bb1814769e1464ba5061d3832344e58520..8b449cd0f9ddc0bdf38e3ce859c78a7c9a01c7fc 100644 (file)
@@ -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, int timeout)
       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)
        {
diff --git a/gdb/ser-mingw.c b/gdb/ser-mingw.c
new file mode 100644 (file)
index 0000000..7a6f232
--- /dev/null
@@ -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 aed91c27654dcb792ba130e11a6196c4db05ef75..bd104aa8f1e25d5c499807c6a48949f7a3f9fa11 100644 (file)
@@ -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 *name)
     {
       /* 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 *name)
          
          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 *name)
   {
     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 *name)
   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, const void *buf, size_t count)
 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 */
 }
diff --git a/gdb/ser-tcp.h b/gdb/ser-tcp.h
new file mode 100644 (file)
index 0000000..accaac7
--- /dev/null
@@ -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 4a40c36662736e9d2fb5bb0bb7cc3e017e634b2f..7c10815a4e0f7d1ea73a9d8f918fde2820fcfddf 100644 (file)
@@ -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 timeout)
       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 e5cf1b9d50320941ef3789bc832c9407f9dd7e1c..9ee2fa0ee3d2804c96ff68e3a2455d5f439b49e8 100644 (file)
@@ -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 a948ae1facd52efe39bfaa307644cf1f668b3acf..d9a395b3fc4d1a8f75b2cd0990b4044a4be1b080 100644 (file)
@@ -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.
 #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 serial_ops * optable);
 
 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 1b88542d554eb494e7991a2963957a30c7aefb97..19b297a65b11ede7b4b824a25fb8a3213c592363 100644 (file)
@@ -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 a5ee333f42f04bb8a3c06cd0b932027c8c656d40..61968afb63c4d2d8d6060ab7da7a54b32c67c601 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -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