* 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.
This commit is contained in:
parent
121ce6e53d
commit
0ea3f30e21
20 changed files with 1181 additions and 138 deletions
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
6
gdb/NEWS
6
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.
|
||||
|
|
2
gdb/configure
vendored
2
gdb/configure
vendored
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
37
gdb/gdb_select.h
Normal file
37
gdb/gdb_select.h
Normal file
|
@ -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) */
|
21
gdb/inflow.c
21
gdb/inflow.c
|
@ -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)
|
||||
{
|
||||
|
|
124
gdb/mingw-hdep.c
124
gdb/mingw-hdep.c
|
@ -21,7 +21,10 @@
|
|||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "serial.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_select.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
@ -69,3 +72,124 @@ safe_strerror (int errnum)
|
|||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Wrapper for select. On Windows systems, where the select interface
|
||||
only works for sockets, this uses the GDB serial abstraction to
|
||||
handle sockets, consoles, pipes, and serial ports.
|
||||
|
||||
The arguments to this function are the same as the traditional
|
||||
arguments to select on POSIX platforms. */
|
||||
|
||||
int
|
||||
gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout)
|
||||
{
|
||||
static HANDLE never_handle;
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||
HANDLE h;
|
||||
DWORD event;
|
||||
DWORD num_handles;
|
||||
int fd;
|
||||
int num_ready;
|
||||
int indx;
|
||||
|
||||
num_ready = 0;
|
||||
num_handles = 0;
|
||||
for (fd = 0; fd < n; ++fd)
|
||||
{
|
||||
HANDLE read = NULL, except = NULL;
|
||||
struct serial *scb;
|
||||
|
||||
/* There is no support yet for WRITEFDS. At present, this isn't
|
||||
used by GDB -- but we do not want to silently ignore WRITEFDS
|
||||
if something starts using it. */
|
||||
gdb_assert (!writefds || !FD_ISSET (fd, writefds));
|
||||
|
||||
if (!FD_ISSET (fd, readfds)
|
||||
&& !FD_ISSET (fd, exceptfds))
|
||||
continue;
|
||||
h = (HANDLE) _get_osfhandle (fd);
|
||||
|
||||
scb = serial_for_fd (fd);
|
||||
if (scb)
|
||||
serial_wait_handle (scb, &read, &except);
|
||||
|
||||
if (read == NULL)
|
||||
read = h;
|
||||
if (except == NULL)
|
||||
{
|
||||
if (!never_handle)
|
||||
never_handle = CreateEvent (0, FALSE, FALSE, 0);
|
||||
|
||||
except = never_handle;
|
||||
}
|
||||
|
||||
if (FD_ISSET (fd, readfds))
|
||||
{
|
||||
gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
|
||||
handles[num_handles++] = read;
|
||||
}
|
||||
|
||||
if (FD_ISSET (fd, exceptfds))
|
||||
{
|
||||
gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
|
||||
handles[num_handles++] = except;
|
||||
}
|
||||
}
|
||||
/* If we don't need to wait for any handles, we are done. */
|
||||
if (!num_handles)
|
||||
{
|
||||
if (timeout)
|
||||
Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
event = WaitForMultipleObjects (num_handles,
|
||||
handles,
|
||||
FALSE,
|
||||
timeout
|
||||
? (timeout->tv_sec * 1000
|
||||
+ timeout->tv_usec / 1000)
|
||||
: INFINITE);
|
||||
/* EVENT can only be a value in the WAIT_ABANDONED_0 range if the
|
||||
HANDLES included an abandoned mutex. Since GDB doesn't use
|
||||
mutexes, that should never occur. */
|
||||
gdb_assert (!(WAIT_ABANDONED_0 <= event
|
||||
&& event < WAIT_ABANDONED_0 + num_handles));
|
||||
if (event == WAIT_FAILED)
|
||||
return -1;
|
||||
if (event == WAIT_TIMEOUT)
|
||||
return 0;
|
||||
/* Run through the READFDS, clearing bits corresponding to descriptors
|
||||
for which input is unavailable. */
|
||||
h = handles[event - WAIT_OBJECT_0];
|
||||
for (fd = 0, indx = 0; fd < n; ++fd)
|
||||
{
|
||||
HANDLE fd_h;
|
||||
|
||||
if (FD_ISSET (fd, readfds))
|
||||
{
|
||||
fd_h = handles[indx++];
|
||||
/* This handle might be ready, even though it wasn't the handle
|
||||
returned by WaitForMultipleObjects. */
|
||||
if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
|
||||
FD_CLR (fd, readfds);
|
||||
else
|
||||
num_ready++;
|
||||
}
|
||||
|
||||
if (FD_ISSET (fd, exceptfds))
|
||||
{
|
||||
fd_h = handles[indx++];
|
||||
/* This handle might be ready, even though it wasn't the handle
|
||||
returned by WaitForMultipleObjects. */
|
||||
if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
|
||||
FD_CLR (fd, exceptfds);
|
||||
else
|
||||
num_ready++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_ready;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
796
gdb/ser-mingw.c
Normal file
796
gdb/ser-mingw.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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 */
|
||||
}
|
||||
|
|
32
gdb/ser-tcp.h
Normal file
32
gdb/ser-tcp.h
Normal file
|
@ -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
|
|
@ -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)
|
||||
|
|
37
gdb/serial.c
37
gdb/serial.c
|
@ -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
|
||||
|
|
26
gdb/serial.h
26
gdb/serial.h
|
@ -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 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 */
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue