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

Daniel Jacobowitz
2006-02-03T22:05:40Z

This patch is a log bigger than I wanted it to be, unfortunately - it
fixes several related issues, that all touch the same code.

Fixes, all for a mingw32-hosted GDB:

- Windows serial support. This definitely deserves a NEWS entry,
included.

- Mark's Windows-aware select wrapper is substantially improved.
It's still a far cry from as thorough as Cygwin's, but it works
for reads and errors on serial ports, network sockets, pipes, and
consoles.

- Connecting to a closed TCP socket no longer times out; instead it
reports an error.

The primary ugly bit of this patch is the select wrapper. Windows has
interfaces for all these things which map to Unix file descriptors, but
while the Unix interfaces are actually compatible, the Windows interfaces
are just designed along similar principles. So you can handle a serial port
in roughly the same way you handle a console window.... but only roughly.
In fact you need to know what sort of device is behind each "file
descriptor", in order to handle it appropriately.

The one I'm least proud of is pipes - there does not appear to be a way to
sleep and have the OS wake you when data is available on a pipe. So I poll
every 10ms in a thread. Yuck! The other three all have subtly different
wait mechanisms.

I've tested it. I'm not sure what else to say about it. Is it OK? Are
there things blatantly wrong with it that I've missed? Are there particular
bits that you think are just too ugly, and if so, do you have any
suggestions on how to make them less ugly?

--
Daniel Jacobowitz
CodeSourcery

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

* Makefile.in (gdb_select_h, ser_tcp_h): New.
(ALLDEPFILES): Add ser-windows.c.
(event-loop.o, ser-base.o, ser-tcp.o): Update.
(ser-windows.o): New rule.
* configure: Regenerated.
* configure.in: Add ser-windows.o for mingw32.
* ser-windows.c: New file.
* event-loop.c: Include "serial.h" and "gdb_select.h".
(gdb_select): Make global. Update comments. Use
serial_wait_handle. Handle generic exception conditions.
* 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): Pass an exception set to select also. Whitespace fix.
(_initialize_ser_tcp) [USE_WIN32API]: Do not register TCP support here.
* ser-tcp.h: New file.
* inflow.c (gdb_has_a_terminal): Don't initialize stdin_serial here.
(initialize_stdin_serial): New function.
* terminal.h (initialize_stdin_serial): New prototype.
* top.c (gdb_init): Call initialize_stdin_serial.

Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2006-02-03 15:17:30.000000000 -0500
+++ src/gdb/Makefile.in 2006-02-03 16:27:35.000000000 -0500
@@ -692,6 +692,7 @@ gdb_obstack_h = gdb_obstack.h $(obstack_
gdb_proc_service_h = gdb_proc_service.h $(gregset_h)
gdb_ptrace_h = gdb_ptrace.h
gdb_regex_h = gdb_regex.h $(xregex_h)
+gdb_select_h = gdb_select.h
gdb_stabs_h = gdb-stabs.h
gdb_stat_h = gdb_stat.h
gdb_string_h = gdb_string.h
@@ -764,6 +765,7 @@ scm_tags_h = scm-tags.h
sentinel_frame_h = sentinel-frame.h
serial_h = serial.h
ser_base_h = ser-base.h
+ser_tcp_h = ser-tcp.h
ser_unix_h = ser-unix.h
shnbsd_tdep_h = shnbsd-tdep.h
sh_tdep_h = sh-tdep.h
@@ -1440,7 +1442,7 @@ ALLDEPFILES = \
remote-st.c remote-utils.c dcache.c \
rs6000-nat.c rs6000-tdep.c \
s390-tdep.c s390-nat.c \
- ser-go32.c ser-pipe.c ser-tcp.c \
+ ser-go32.c ser-pipe.c ser-tcp.c ser-windows.c \
sh-tdep.c sh64-tdep.c shnbsd-tdep.c shnbsd-nat.c \
sol2-tdep.c \
solib-irix.c solib-svr4.c solib-sunos.c \
@@ -1920,7 +1922,8 @@ 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) $(serial_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)
@@ -2511,13 +2514,15 @@ ser-e7kpc.o: ser-e7kpc.c $(defs_h) $(ser
ser-go32.o: ser-go32.c $(defs_h) $(gdbcmd_h) $(serial_h) $(gdb_string_h)
serial.o: serial.c $(defs_h) $(serial_h) $(gdb_string_h) $(gdbcmd_h)
ser-base.o: ser-base.c $(defs_h) $(serial_h) $(ser_base_h) $(event_loop_h) \
- $(gdb_string_h)
+ $(gdb_select_h) $(gdb_string_h)
ser-pipe.o: ser-pipe.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \
$(gdb_vfork_h) $(gdb_string_h)
-ser-tcp.o: ser-tcp.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \
+ser-tcp.o: ser-tcp.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_tcp_h) \
$(gdb_string_h)
ser-unix.o: ser-unix.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \
$(terminal_h) $(gdb_string_h)
+ser-windows.o: ser-windows.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.ac
===================================================================
--- src.orig/gdb/configure.ac 2006-02-03 15:17:30.000000000 -0500
+++ src/gdb/configure.ac 2006-02-03 15:24:16.000000000 -0500
@@ -1,5 +1,6 @@
dnl Autoconf configure script for GDB, the GNU debugger.
-dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+dnl 2005, 2006
dnl Free Software Foundation, Inc.
dnl
dnl This file is part of GDB.
@@ -1198,7 +1199,7 @@ SER_HARDWIRE="ser-base.o ser-unix.o ser-
case ${host} in
*go32* ) SER_HARDWIRE=ser-go32.o ;;
*djgpp* ) SER_HARDWIRE=ser-go32.o ;;
- *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o" ;;
+ *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o ser-windows.o" ;;
esac
AC_SUBST(SER_HARDWIRE)

Index: src/gdb/ser-windows.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/ser-windows.c 2006-02-03 16:23:42.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/event-loop.c
===================================================================
--- src.orig/gdb/event-loop.c 2006-02-03 15:17:30.000000000 -0500
+++ src/gdb/event-loop.c 2006-02-03 16:25:46.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.
@@ -22,6 +23,7 @@
#include "defs.h"
#include "event-loop.h"
#include "event-top.h"
+#include "serial.h"

#ifdef HAVE_POLL
#if defined (HAVE_POLL_H)
@@ -37,6 +39,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,13 +734,11 @@ handle_file_event (int event_file_desc)
}
}

-/* Wrapper for select. This function is not yet exported from this
- file because it is not sufficiently general. For example,
- ser-base.c uses select to check for socket activity, and this
- function does not support sockets under Windows, so we do not want
- to use gdb_select in ser-base.c. */
+/* Wrapper for select. 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. */

-static int
+int
gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
{
@@ -748,40 +749,55 @@ gdb_select (int n, fd_set *readfds, fd_s
DWORD num_handles;
int fd;
int num_ready;
+ int indx;
+ static HANDLE never_handle;

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 (!FD_ISSET (fd, writefds));
+ gdb_assert (!writefds || !FD_ISSET (fd, writefds));
+
if (!FD_ISSET (fd, readfds)
&& !FD_ISSET (fd, exceptfds))
continue;
h = (HANDLE) _get_osfhandle (fd);
- if (h == INVALID_HANDLE_VALUE)
+
+ scb = serial_for_fd (fd);
+ if (scb)
+ serial_wait_handle (scb, &read, &except);
+
+ if (read == NULL)
+ read = h;
+ if (except == NULL)
{
- /* 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 (!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++] = h;
- }
+ {
+ gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
+ handles[num_handles++] = read;
+ }
+
+ if (FD_ISSET (fd, exceptfds))
+ {
+ gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
+ handles[num_handles++] = except;
+ }
}
/* If we don't need to wait for any handles, we are done. */
if (!num_handles)
- return num_ready;
+ return 0;
event = WaitForMultipleObjects (num_handles,
handles,
FALSE,
@@ -796,23 +812,34 @@ gdb_select (int n, fd_set *readfds, fd_s
if (event == WAIT_FAILED)
return -1;
if (event == WAIT_TIMEOUT)
- return num_ready;
+ return 0;
/* 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)
+ for (fd = 0, indx = 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)
+
+ if (FD_ISSET (fd, readfds))
{
- FD_CLR (fd, readfds);
- --num_ready;
+ 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++;
}
}

Index: src/gdb/ser-base.c
===================================================================
--- src.orig/gdb/ser-base.c 2006-02-03 15:17:30.000000000 -0500
+++ src/gdb/ser-base.c 2006-02-03 16:26:09.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-03 15:17:30.000000000 -0500
+++ src/gdb/serial.c 2006-02-03 16:26:43.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-03 15:17:30.000000000 -0500
+++ src/gdb/serial.h 2006-02-03 16:27:11.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-03 15:19:42.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 <windows.h>
+#endif
+
+extern int gdb_select (int n, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout);
+
+#endif /* !defined(GDB_STRING_H) */
Index: src/gdb/ser-tcp.c
===================================================================
--- src.orig/gdb/ser-tcp.c 2006-02-03 15:17:30.000000000 -0500
+++ src/gdb/ser-tcp.c 2006-02-03 16:27:18.000000000 -0500
@@ -1,6 +1,6 @@
/* Serial interface for raw TCP connections on Un*x like systems.

- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001, 2005
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001, 2005, 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -23,7 +23,7 @@
#include "defs.h"
#include "serial.h"
#include "ser-base.h"
-#include "ser-unix.h"
+#include "ser-tcp.h"

#include <sys/types.h>

@@ -56,8 +56,6 @@
typedef int socklen_t;
#endif

-static int net_open (struct serial *scb, const char *name);
-static void net_close (struct serial *scb);
void _initialize_ser_tcp (void);

/* seconds to wait for connect */
@@ -67,7 +65,7 @@ void _initialize_ser_tcp (void);

/* Open a tcp socket */

-static int
+int
net_open (struct serial *scb, const char *name)
{
char *port_str, hostname[100];
@@ -153,7 +151,7 @@ net_open (struct serial *scb, const char
{
/* looks like we need to wait for the connect */
struct timeval t;
- fd_set rset, wset;
+ fd_set rset, wset, eset;
int polls = 0;
FD_ZERO (&rset);

@@ -174,10 +172,13 @@ net_open (struct serial *scb, const char

FD_SET (scb->fd, &rset);
wset = rset;
+ eset = rset;
t.tv_sec = 0;
t.tv_usec = 1000000 / POLL_INTERVAL;

- n = select (scb->fd + 1, &rset, &wset, NULL, &t);
+ /* Windows returns connection failure in eset rather than wset.
+ How perverse. */
+ n = select (scb->fd + 1, &rset, &wset, &eset, &t);
polls++;
}
while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL);
@@ -194,7 +195,7 @@ net_open (struct serial *scb, const char
{
int res, err;
socklen_t len;
- len = sizeof(err);
+ len = sizeof (err);
/* On Windows, the fourth parameter to getsockopt is a "char *";
on UNIX systems it is generally "void *". The cast to "void *"
is OK everywhere, since in C "void *" can be implicitly
@@ -230,7 +231,7 @@ net_open (struct serial *scb, const char
return 0;
}

-static void
+void
net_close (struct serial *scb)
{
if (scb->fd < 0)
@@ -240,13 +241,13 @@ net_close (struct serial *scb)
scb->fd = -1;
}

-static int
+int
net_read_prim (struct serial *scb, size_t count)
{
return recv (scb->fd, scb->buf, count, 0);
}

-static int
+int
net_write_prim (struct serial *scb, const void *buf, size_t count)
{
return send (scb->fd, buf, count, 0);
@@ -255,13 +256,12 @@ net_write_prim (struct serial *scb, cons
void
_initialize_ser_tcp (void)
{
- struct serial_ops *ops;
#ifdef USE_WIN32API
- WSADATA wsa_data;
- if (WSAStartup (MAKEWORD (1, 0), &wsa_data) != 0)
- /* WinSock is unavailable. */
- return;
-#endif
+ /* Do nothing; the TCP serial operations will be initialized in
+ ser-windows.c. */
+ return;
+#else
+ struct serial_ops *ops;
ops = XMALLOC (struct serial_ops);
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "tcp";
@@ -285,4 +285,5 @@ _initialize_ser_tcp (void)
ops->read_prim = net_read_prim;
ops->write_prim = net_write_prim;
serial_add_interface (ops);
+#endif /* USE_WIN32API */
}
Index: src/gdb/ser-tcp.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/ser-tcp.h 2006-02-03 16:34:52.000000000 -0500
@@ -0,0 +1,32 @@
+/* Serial interface for raw TCP connections on Un*x like systems.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef SER_TCP_H
+#define SER_TCP_H
+
+struct serial;
+
+extern int net_open (struct serial *scb, const char *name);
+extern void net_close (struct serial *scb);
+extern int net_read_prim (struct serial *scb, size_t count);
+extern int net_write_prim (struct serial *scb, const void *buf, size_t count);
+
+#endif
Index: src/gdb/inflow.c
===================================================================
--- src.orig/gdb/inflow.c 2006-02-03 15:17:30.000000000 -0500
+++ src/gdb/inflow.c 2006-02-03 16:28:04.000000000 -0500
@@ -1,6 +1,6 @@
/* Low level interface to ptrace, for GDB when running under Unix.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -129,7 +129,6 @@ gdb_has_a_terminal (void)
#endif

gdb_has_a_terminal_flag = no;
- stdin_serial = serial_fdopen (0);
if (stdin_serial != NULL)
{
our_ttystate = serial_get_tty_state (stdin_serial);
@@ -730,6 +729,18 @@ gdb_setpgid (void)
return retval;
}

+/* Get all the current tty settings (including whether we have a
+ tty at all!). We can't do this in _initialize_inflow because
+ serial_fdopen() won't work until the serial_ops_list is
+ initialized, but we don't want to do it lazily either, so
+ that we can guarantee stdin_serial is opened if there is
+ a terminal. */
+void
+initialize_stdin_serial (void)
+{
+ stdin_serial = serial_fdopen (0);
+}
+
void
_initialize_inflow (void)
{
Index: src/gdb/terminal.h
===================================================================
--- src.orig/gdb/terminal.h 2006-02-03 15:17:30.000000000 -0500
+++ src/gdb/terminal.h 2006-02-03 16:28:30.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-03 15:17:30.000000000 -0500
+++ src/gdb/top.c 2006-02-03 15:19:42.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