/* Serial interface for local (hardwired) serial ports on Windows systems
- Copyright (C) 2006
- Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
This file is part of GDB.
return 0;
}
+static int
+fd_is_file (int fd)
+{
+ if (GetFileType ((HANDLE) _get_osfhandle (fd)) == FILE_TYPE_DISK)
+ return 1;
+ else
+ return 0;
+}
+
static DWORD WINAPI
pipe_select_thread (void *arg)
{
}
}
+static DWORD WINAPI
+file_select_thread (void *arg)
+{
+ struct serial *scb = arg;
+ struct ser_console_state *state;
+ int event_index;
+ HANDLE h;
+
+ state = scb->state;
+ h = (HANDLE) _get_osfhandle (scb->fd);
+
+ while (1)
+ {
+ HANDLE wait_events[2];
+ DWORD n_avail;
+
+ SetEvent (state->have_stopped);
+
+ wait_events[0] = state->start_select;
+ wait_events[1] = state->exit_select;
+
+ if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE) != WAIT_OBJECT_0)
+ return 0;
+
+ ResetEvent (state->have_stopped);
+
+ if (SetFilePointer (h, 0, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
+ {
+ SetEvent (state->except_event);
+ continue;
+ }
+
+ SetEvent (state->read_event);
+ }
+}
+
static void
ser_console_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
{
int is_tty;
is_tty = isatty (scb->fd);
- if (!is_tty && !fd_is_pipe (scb->fd))
+ if (!is_tty && !fd_is_file (scb->fd) && !fd_is_pipe (scb->fd))
{
*read = NULL;
*except = NULL;
if (is_tty)
state->thread = CreateThread (NULL, 0, console_select_thread, scb, 0,
&threadId);
- else
+ else if (fd_is_pipe (scb->fd))
state->thread = CreateThread (NULL, 0, pipe_select_thread, scb, 0,
&threadId);
+ else
+ state->thread = CreateThread (NULL, 0, file_select_thread, scb, 0,
+ &threadId);
}
*read = state->read_event;
int saved_errno = errno;
if (ps->wait.read_event != INVALID_HANDLE_VALUE)
- CloseHandle (ps->wait.read_event);
- if (ps->wait.except_event != INVALID_HANDLE_VALUE)
- CloseHandle (ps->wait.except_event);
- if (ps->wait.start_select != INVALID_HANDLE_VALUE)
- CloseHandle (ps->wait.start_select);
+ {
+ SetEvent (ps->wait.exit_select);
+
+ WaitForSingleObject (ps->wait.thread, INFINITE);
+
+ CloseHandle (ps->wait.start_select);
+ CloseHandle (ps->wait.stop_select);
+ CloseHandle (ps->wait.exit_select);
+ CloseHandle (ps->wait.have_stopped);
- /* If we have a select thread running, let the select thread free
- the stop event. */
- if (ps->wait.stop_select != INVALID_HANDLE_VALUE)
- SetEvent (ps->wait.stop_select);
+ CloseHandle (ps->wait.read_event);
+ CloseHandle (ps->wait.except_event);
+ }
/* Close the pipe to the child. We must close the pipe before
calling pex_free because pex_free will wait for the child to exit
static int
pipe_windows_open (struct serial *scb, const char *name)
{
+ struct pipe_state *ps;
+ FILE *pex_stderr;
+
char **argv = buildargv (name);
struct cleanup *back_to = make_cleanup_freeargv (argv);
if (! argv[0] || argv[0][0] == '\0')
error ("missing child command");
- struct pipe_state *ps = make_pipe_state ();
+
+ ps = make_pipe_state ();
make_cleanup (cleanup_pipe_state, ps);
ps->pex = pex_init (PEX_USE_PIPES, "target remote pipe", NULL);
{
int err;
const char *err_msg
- = pex_run (ps->pex, PEX_SEARCH | PEX_BINARY_INPUT | PEX_BINARY_OUTPUT,
+ = pex_run (ps->pex, PEX_SEARCH | PEX_BINARY_INPUT | PEX_BINARY_OUTPUT
+ | PEX_STDERR_TO_PIPE,
argv[0], argv, NULL, NULL,
&err);
ps->output = pex_read_output (ps->pex, 1);
if (! ps->output)
goto fail;
-
scb->fd = fileno (ps->output);
+
+ pex_stderr = pex_read_err (ps->pex, 1);
+ if (! pex_stderr)
+ goto fail;
+ scb->error_fd = fileno (pex_stderr);
+
scb->state = (void *) ps;
discard_cleanups (back_to);
pipe_windows_read (struct serial *scb, size_t count)
{
HANDLE pipeline_out = (HANDLE) _get_osfhandle (scb->fd);
+ DWORD available;
+ DWORD bytes_read;
+
if (pipeline_out == INVALID_HANDLE_VALUE)
return -1;
- DWORD available;
if (! PeekNamedPipe (pipeline_out, NULL, 0, NULL, &available, NULL))
return -1;
if (count > available)
count = available;
- DWORD bytes_read;
if (! ReadFile (pipeline_out, scb->buf, count, &bytes_read, NULL))
return -1;
pipe_windows_write (struct serial *scb, const void *buf, size_t count)
{
struct pipe_state *ps = scb->state;
+ HANDLE pipeline_in;
+ DWORD written;
+
int pipeline_in_fd = fileno (ps->input);
if (pipeline_in_fd < 0)
return -1;
- HANDLE pipeline_in = (HANDLE) _get_osfhandle (pipeline_in_fd);
+ pipeline_in = (HANDLE) _get_osfhandle (pipeline_in_fd);
if (pipeline_in == INVALID_HANDLE_VALUE)
return -1;
- DWORD written;
if (! WriteFile (pipeline_in, buf, count, &written, NULL))
return -1;
{
DWORD threadId;
- /* Create auto reset events to wake and terminate the select thread. */
+ /* Create auto reset events to wake, stop, and exit the select
+ thread. */
ps->wait.start_select = CreateEvent (0, FALSE, FALSE, 0);
ps->wait.stop_select = CreateEvent (0, FALSE, FALSE, 0);
+ ps->wait.exit_select = CreateEvent (0, FALSE, FALSE, 0);
+
+ /* Create a manual reset event to signal whether the thread is
+ stopped. This must be manual reset, because we may wait on
+ it multiple times without ever starting the thread. */
+ ps->wait.have_stopped = CreateEvent (0, TRUE, FALSE, 0);
/* Create our own events to report read and exceptions separately.
The exception event is currently never used. */
CreateThread (NULL, 0, pipe_select_thread, scb, 0, &threadId);
}
+ *read = ps->wait.read_event;
+ *except = ps->wait.except_event;
+
+ /* Start from a blank state. */
ResetEvent (ps->wait.read_event);
ResetEvent (ps->wait.except_event);
+ ResetEvent (ps->wait.stop_select);
+ /* Start the select thread. */
SetEvent (ps->wait.start_select);
+}
- *read = ps->wait.read_event;
- *except = ps->wait.except_event;
+static void
+pipe_done_wait_handle (struct serial *scb)
+{
+ struct pipe_state *ps = scb->state;
+
+ /* Have we allocated our events yet? */
+ if (ps->wait.read_event == INVALID_HANDLE_VALUE)
+ return;
+
+ SetEvent (ps->wait.stop_select);
+ WaitForSingleObject (ps->wait.have_stopped, INFINITE);
}
+static int
+pipe_avail (struct serial *scb, int fd)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ DWORD numBytes;
+ BOOL r = PeekNamedPipe (h, NULL, 0, NULL, &numBytes, NULL);
+ if (r == FALSE)
+ numBytes = 0;
+ return numBytes;
+}
struct net_windows_state
{
ops->read_prim = pipe_windows_read;
ops->write_prim = pipe_windows_write;
ops->wait_handle = pipe_wait_handle;
+ ops->done_wait_handle = pipe_done_wait_handle;
+ ops->avail = pipe_avail;
serial_add_interface (ops);