aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2007-10-02 16:09:53 +0000
committerDaniel Jacobowitz <drow@false.org>2007-10-02 16:09:53 +0000
commit4577549b8f2c2839976293166e7475401d9e21f2 (patch)
tree61f014025f2d20732677c9fe60d15ba2b70fd15b /gdb
parentb0b951d937a64163513e46d65b529c6a5ac87139 (diff)
downloadfsf-binutils-gdb-4577549b8f2c2839976293166e7475401d9e21f2.zip
fsf-binutils-gdb-4577549b8f2c2839976293166e7475401d9e21f2.tar.gz
fsf-binutils-gdb-4577549b8f2c2839976293166e7475401d9e21f2.tar.bz2
2007-10-02 Mark Mitchell <mark@codesourcery.com>
* mingw-hdep.c (gdb_select): Stop helper threads before returning. * ser-mingw.c (enum select_thread_state): New type. (struct ser_console_state): Add have_started and thread_state. (select_thread_wait): New function. (thread_fn_type): New type. (create_select_thread): New function. (destroy_select_thread): Likewise. (start_select_thread): Likewise. (stop_select_thread): Likewise. (console_select_thread): Use new functions. (pipe_select_thread): Likewise. (file_select_thread): Likewise. (ser_console_wait_handle): Likewise. (ser_console_done_wait_handle): Likewise. (ser_console_close): Likewise. (free_pipe_state): Likewise. (pipe_wait_handle): Likewise. (pipe_done_wait_handle): Likewise. (struct net_windows_state): Derive from ser_console_state. (net_windows_select_thread): Use new functions. (net_windows_wait_handle): Likewise. (net_windows_done_wait_handle): Likewise. (net_windows_close): Likewise.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog26
-rw-r--r--gdb/mingw-hdep.c26
-rw-r--r--gdb/ser-mingw.c529
3 files changed, 313 insertions, 268 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9d0c86b..b20f517 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,29 @@
+2007-10-02 Mark Mitchell <mark@codesourcery.com>
+
+ * mingw-hdep.c (gdb_select): Stop helper threads before returning.
+ * ser-mingw.c (enum select_thread_state): New type.
+ (struct ser_console_state): Add have_started and thread_state.
+ (select_thread_wait): New function.
+ (thread_fn_type): New type.
+ (create_select_thread): New function.
+ (destroy_select_thread): Likewise.
+ (start_select_thread): Likewise.
+ (stop_select_thread): Likewise.
+ (console_select_thread): Use new functions.
+ (pipe_select_thread): Likewise.
+ (file_select_thread): Likewise.
+ (ser_console_wait_handle): Likewise.
+ (ser_console_done_wait_handle): Likewise.
+ (ser_console_close): Likewise.
+ (free_pipe_state): Likewise.
+ (pipe_wait_handle): Likewise.
+ (pipe_done_wait_handle): Likewise.
+ (struct net_windows_state): Derive from ser_console_state.
+ (net_windows_select_thread): Use new functions.
+ (net_windows_wait_handle): Likewise.
+ (net_windows_done_wait_handle): Likewise.
+ (net_windows_close): Likewise.
+
2007-10-02 Daniel Jacobowitz <dan@codesourcery.com>
* inflow.c (terminal_ours_1): Remove useless line.
diff --git a/gdb/mingw-hdep.c b/gdb/mingw-hdep.c
index 355b2fc..f57e3ce 100644
--- a/gdb/mingw-hdep.c
+++ b/gdb/mingw-hdep.c
@@ -86,12 +86,18 @@ gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
HANDLE h;
DWORD event;
DWORD num_handles;
+ /* SCBS contains serial control objects corresponding to file
+ descriptors in READFDS and WRITEFDS. */
+ struct serial *scbs[MAXIMUM_WAIT_OBJECTS];
+ /* The number of valid entries in SCBS. */
+ size_t num_scbs;
int fd;
int num_ready;
- int indx;
+ size_t indx;
num_ready = 0;
num_handles = 0;
+ num_scbs = 0;
for (fd = 0; fd < n; ++fd)
{
HANDLE read = NULL, except = NULL;
@@ -105,14 +111,16 @@ gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
if ((!readfds || !FD_ISSET (fd, readfds))
&& (!exceptfds || !FD_ISSET (fd, exceptfds)))
continue;
- h = (HANDLE) _get_osfhandle (fd);
scb = serial_for_fd (fd);
if (scb)
- serial_wait_handle (scb, &read, &except);
+ {
+ serial_wait_handle (scb, &read, &except);
+ scbs[num_scbs++] = scb;
+ }
if (read == NULL)
- read = h;
+ read = (HANDLE) _get_osfhandle (fd);
if (except == NULL)
{
if (!never_handle)
@@ -154,6 +162,9 @@ gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
mutexes, that should never occur. */
gdb_assert (!(WAIT_ABANDONED_0 <= event
&& event < WAIT_ABANDONED_0 + num_handles));
+ /* We no longer need the helper threads to check for activity. */
+ for (indx = 0; indx < num_scbs; ++indx)
+ serial_done_wait_handle (scbs[indx]);
if (event == WAIT_FAILED)
return -1;
if (event == WAIT_TIMEOUT)
@@ -164,7 +175,6 @@ gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
for (fd = 0, indx = 0; fd < n; ++fd)
{
HANDLE fd_h;
- struct serial *scb;
if ((!readfds || !FD_ISSET (fd, readfds))
&& (!exceptfds || !FD_ISSET (fd, exceptfds)))
@@ -191,12 +201,6 @@ gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
else
num_ready++;
}
-
- /* We created at least one event handle for this fd. Let the
- device know we are finished with it. */
- scb = serial_for_fd (fd);
- if (scb)
- serial_done_wait_handle (scb);
}
return num_ready;
diff --git a/gdb/ser-mingw.c b/gdb/ser-mingw.c
index 9c63c03..d57ea7f 100644
--- a/gdb/ser-mingw.c
+++ b/gdb/ser-mingw.c
@@ -341,19 +341,162 @@ ser_windows_write_prim (struct serial *scb, const void *buf, size_t len)
return bytes_written;
}
+/* On Windows, gdb_select is implemented using WaitForMulpleObjects.
+ A "select thread" is created for each file descriptor. These
+ threads looks for activity on the corresponding descriptor, using
+ whatever techniques are appropriate for the descriptor type. When
+ that activity occurs, the thread signals an appropriate event,
+ which wakes up WaitForMultipleObjects.
+
+ Each select thread is in one of two states: stopped or started.
+ Select threads begin in the stopped state. When gdb_select is
+ called, threads corresponding to the descriptors of interest are
+ started by calling a wait_handle function. Each thread that
+ notices activity signals the appropriate event and then reenters
+ the stopped state. Before gdb_select returns it calls the
+ wait_handle_done functions, which return the threads to the stopped
+ state. */
+
+enum select_thread_state {
+ STS_STARTED,
+ STS_STOPPED
+};
+
struct ser_console_state
{
+ /* Signaled by the select thread to indicate that data is available
+ on the file descriptor. */
HANDLE read_event;
+ /* Signaled by the select thread to indicate that an exception has
+ occurred on the file descriptor. */
HANDLE except_event;
+ /* Signaled by the select thread to indicate that it has entered the
+ started state. HAVE_STARTED and HAVE_STOPPED are never signaled
+ simultaneously. */
+ HANDLE have_started;
+ /* Signaled by the select thread to indicate that it has stopped,
+ either because data is available (and READ_EVENT is signaled),
+ because an exception has occurred (and EXCEPT_EVENT is signaled),
+ or because STOP_SELECT was signaled. */
+ HANDLE have_stopped;
+ /* Signaled by the main program to tell the select thread to enter
+ the started state. */
HANDLE start_select;
+ /* Signaled by the main program to tell the select thread to enter
+ the stopped state. */
HANDLE stop_select;
+ /* Signaled by the main program to tell the select thread to
+ exit. */
HANDLE exit_select;
- HANDLE have_stopped;
+ /* The handle for the select thread. */
HANDLE thread;
+ /* The state of the select thread. This field is only accessed in
+ the main program, never by the select thread itself. */
+ enum select_thread_state thread_state;
};
+/* Called by a select thread to enter the stopped state. This
+ function does not return until the thread has re-entered the
+ started state. */
+static void
+select_thread_wait (struct ser_console_state *state)
+{
+ HANDLE wait_events[2];
+
+ /* There are two things that can wake us up: a request that we enter
+ the started state, or that we exit this thread. */
+ wait_events[0] = state->start_select;
+ wait_events[1] = state->exit_select;
+ if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE)
+ != WAIT_OBJECT_0)
+ /* Either the EXIT_SELECT event was signaled (requesting that the
+ thread exit) or an error has occurred. In either case, we exit
+ the thread. */
+ ExitThread (0);
+
+ /* We are now in the started state. */
+ SetEvent (state->have_started);
+}
+
+typedef DWORD WINAPI (*thread_fn_type)(void *);
+
+/* Create a new select thread for SCB executing THREAD_FN. The STATE
+ will be filled in by this function before return. */
+void
+create_select_thread (thread_fn_type thread_fn,
+ struct serial *scb,
+ struct ser_console_state *state)
+{
+ DWORD threadId;
+
+ /* Create all of the events. These are all auto-reset events. */
+ state->read_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ state->except_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ state->have_started = CreateEvent (NULL, FALSE, FALSE, NULL);
+ state->have_stopped = CreateEvent (NULL, FALSE, FALSE, NULL);
+ state->start_select = CreateEvent (NULL, FALSE, FALSE, NULL);
+ state->stop_select = CreateEvent (NULL, FALSE, FALSE, NULL);
+ state->exit_select = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+ state->thread = CreateThread (NULL, 0, thread_fn, scb, 0, &threadId);
+ /* The thread begins in the stopped state. */
+ state->thread_state = STS_STOPPED;
+}
+
+/* Destroy the select thread indicated by STATE. */
+static void
+destroy_select_thread (struct ser_console_state *state)
+{
+ /* Ask the thread to exit. */
+ SetEvent (state->exit_select);
+ /* Wait until it does. */
+ WaitForSingleObject (state->thread, INFINITE);
+
+ /* Destroy the events. */
+ CloseHandle (state->read_event);
+ CloseHandle (state->except_event);
+ CloseHandle (state->have_started);
+ CloseHandle (state->have_stopped);
+ CloseHandle (state->start_select);
+ CloseHandle (state->stop_select);
+ CloseHandle (state->exit_select);
+}
+
+/* Called by gdb_select to start the select thread indicated by STATE.
+ This function does not return until the thread has started. */
+static void
+start_select_thread (struct ser_console_state *state)
+{
+ /* Ask the thread to start. */
+ SetEvent (state->start_select);
+ /* Wait until it does. */
+ WaitForSingleObject (state->have_started, INFINITE);
+ /* The thread is now started. */
+ state->thread_state = STS_STARTED;
+}
+
+/* Called by gdb_select to stop the select thread indicated by STATE.
+ This function does not return until the thread has stopped. */
+static void
+stop_select_thread (struct ser_console_state *state)
+{
+ /* If the thread is already in the stopped state, we have nothing to
+ do. Some of the wait_handle functions avoid calling
+ start_select_thread if they notice activity on the relevant file
+ descriptors. The wait_handle_done functions still call
+ stop_select_thread -- but it is already stopped. */
+ if (state->thread_state != STS_STARTED)
+ return;
+ /* Ask the thread to stop. */
+ SetEvent (state->stop_select);
+ /* Wait until it does. */
+ WaitForSingleObject (state->have_stopped, INFINITE);
+ /* The thread is now stopped. */
+ state->thread_state = STS_STOPPED;
+}
+
static DWORD WINAPI
console_select_thread (void *arg)
{
@@ -371,74 +514,69 @@ console_select_thread (void *arg)
INPUT_RECORD record;
DWORD n_records;
- 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);
+ select_thread_wait (state);
- retry:
- wait_events[0] = state->stop_select;
- wait_events[1] = h;
+ while (1)
+ {
+ wait_events[0] = state->stop_select;
+ wait_events[1] = h;
- event_index = WaitForMultipleObjects (2, wait_events, FALSE, INFINITE);
+ event_index = WaitForMultipleObjects (2, wait_events, FALSE, INFINITE);
- if (event_index == WAIT_OBJECT_0
- || WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0)
- continue;
+ if (event_index == WAIT_OBJECT_0
+ || WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0)
+ break;
- 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;
- }
+ 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);
+ break;
+ }
- /* 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;
- }
+ /* 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);
+ break;
+ }
- if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
- {
- WORD keycode = record.Event.KeyEvent.wVirtualKeyCode;
-
- /* Ignore events containing only control keys. We must
- recognize "enhanced" keys which we are interested in
- reading via getch, if they do not map to ASCII. But we
- do not want to report input available for e.g. the
- control key alone. */
-
- if (record.Event.KeyEvent.uChar.AsciiChar != 0
- || keycode == VK_PRIOR
- || keycode == VK_NEXT
- || keycode == VK_END
- || keycode == VK_HOME
- || keycode == VK_LEFT
- || keycode == VK_UP
- || keycode == VK_RIGHT
- || keycode == VK_DOWN
- || keycode == VK_INSERT
- || keycode == VK_DELETE)
+ if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
{
- /* This is really a keypress. */
- SetEvent (state->read_event);
- continue;
+ WORD keycode = record.Event.KeyEvent.wVirtualKeyCode;
+
+ /* Ignore events containing only control keys. We must
+ recognize "enhanced" keys which we are interested in
+ reading via getch, if they do not map to ASCII. But we
+ do not want to report input available for e.g. the
+ control key alone. */
+
+ if (record.Event.KeyEvent.uChar.AsciiChar != 0
+ || keycode == VK_PRIOR
+ || keycode == VK_NEXT
+ || keycode == VK_END
+ || keycode == VK_HOME
+ || keycode == VK_LEFT
+ || keycode == VK_UP
+ || keycode == VK_RIGHT
+ || keycode == VK_DOWN
+ || keycode == VK_INSERT
+ || keycode == VK_DELETE)
+ {
+ /* This is really a keypress. */
+ SetEvent (state->read_event);
+ break;
+ }
}
+
+ /* Otherwise discard it and wait again. */
+ ReadConsoleInput (h, &record, 1, &n_records);
}
- /* Otherwise discard it and wait again. */
- ReadConsoleInput (h, &record, 1, &n_records);
- goto retry;
+ SetEvent(state->have_stopped);
}
}
@@ -473,38 +611,32 @@ pipe_select_thread (void *arg)
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;
+ select_thread_wait (state);
- ResetEvent (state->have_stopped);
-
- retry:
- if (!PeekNamedPipe (h, NULL, 0, NULL, &n_avail, NULL))
+ /* Wait for something to happen on the pipe. */
+ while (1)
{
- SetEvent (state->except_event);
- continue;
- }
+ if (!PeekNamedPipe (h, NULL, 0, NULL, &n_avail, NULL))
+ {
+ SetEvent (state->except_event);
+ break;
+ }
- if (n_avail > 0)
- {
- SetEvent (state->read_event);
- continue;
- }
+ if (n_avail > 0)
+ {
+ SetEvent (state->read_event);
+ break;
+ }
- /* Delay 10ms before checking again, but allow the stop event
- to wake us. */
- if (WaitForSingleObject (state->stop_select, 10) == WAIT_OBJECT_0)
- continue;
+ /* Delay 10ms before checking again, but allow the stop
+ event to wake us. */
+ if (WaitForSingleObject (state->stop_select, 10) == WAIT_OBJECT_0)
+ break;
+ }
- goto retry;
+ SetEvent (state->have_stopped);
}
}
@@ -521,26 +653,14 @@ file_select_thread (void *arg)
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);
+ select_thread_wait (state);
if (SetFilePointer (h, 0, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
- {
- SetEvent (state->except_event);
- continue;
- }
+ SetEvent (state->except_event);
+ else
+ SetEvent (state->read_event);
- SetEvent (state->read_event);
+ SetEvent (state->have_stopped);
}
}
@@ -551,7 +671,7 @@ ser_console_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
if (state == NULL)
{
- DWORD threadId;
+ thread_fn_type thread_fn;
int is_tty;
is_tty = isatty (scb->fd);
@@ -566,30 +686,14 @@ ser_console_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
memset (state, 0, sizeof (struct ser_console_state));
scb->state = state;
- /* Create auto reset events to wake, stop, and exit the select
- thread. */
- state->start_select = CreateEvent (0, FALSE, FALSE, 0);
- state->stop_select = CreateEvent (0, FALSE, FALSE, 0);
- state->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. */
- state->have_stopped = CreateEvent (0, TRUE, FALSE, 0);
-
- /* Create our own events to report read and exceptions separately. */
- state->read_event = CreateEvent (0, FALSE, FALSE, 0);
- state->except_event = CreateEvent (0, FALSE, FALSE, 0);
-
if (is_tty)
- state->thread = CreateThread (NULL, 0, console_select_thread, scb, 0,
- &threadId);
+ thread_fn = console_select_thread;
else if (fd_is_pipe (scb->fd))
- state->thread = CreateThread (NULL, 0, pipe_select_thread, scb, 0,
- &threadId);
+ thread_fn = pipe_select_thread;
else
- state->thread = CreateThread (NULL, 0, file_select_thread, scb, 0,
- &threadId);
+ thread_fn = file_select_thread;
+
+ create_select_thread (thread_fn, scb, state);
}
*read = state->read_event;
@@ -612,7 +716,7 @@ ser_console_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
}
/* Otherwise, start the select thread. */
- SetEvent (state->start_select);
+ start_select_thread (state);
}
static void
@@ -623,8 +727,7 @@ ser_console_done_wait_handle (struct serial *scb)
if (state == NULL)
return;
- SetEvent (state->stop_select);
- WaitForSingleObject (state->have_stopped, INFINITE);
+ stop_select_thread (state);
}
static void
@@ -634,18 +737,7 @@ ser_console_close (struct serial *scb)
if (scb->state)
{
- SetEvent (state->exit_select);
-
- WaitForSingleObject (state->thread, INFINITE);
-
- CloseHandle (state->start_select);
- CloseHandle (state->stop_select);
- CloseHandle (state->exit_select);
- CloseHandle (state->have_stopped);
-
- CloseHandle (state->read_event);
- CloseHandle (state->except_event);
-
+ destroy_select_thread (state);
xfree (scb->state);
}
}
@@ -703,19 +795,7 @@ free_pipe_state (struct pipe_state *ps)
int saved_errno = errno;
if (ps->wait.read_event != INVALID_HANDLE_VALUE)
- {
- 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);
-
- CloseHandle (ps->wait.read_event);
- CloseHandle (ps->wait.except_event);
- }
+ destroy_select_thread (&ps->wait);
/* 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
@@ -870,28 +950,8 @@ pipe_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
/* Have we allocated our events yet? */
if (ps->wait.read_event == INVALID_HANDLE_VALUE)
- {
- DWORD threadId;
-
- /* 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. */
- ps->wait.read_event = CreateEvent (0, FALSE, FALSE, 0);
- ps->wait.except_event = CreateEvent (0, FALSE, FALSE, 0);
-
- /* Start the select thread. */
- CreateThread (NULL, 0, pipe_select_thread, scb, 0, &threadId);
- }
+ /* Start the thread. */
+ create_select_thread (pipe_select_thread, scb, &ps->wait);
*read = ps->wait.read_event;
*except = ps->wait.except_event;
@@ -901,8 +961,7 @@ pipe_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
ResetEvent (ps->wait.except_event);
ResetEvent (ps->wait.stop_select);
- /* Start the select thread. */
- SetEvent (ps->wait.start_select);
+ start_select_thread (&ps->wait);
}
static void
@@ -914,8 +973,7 @@ pipe_done_wait_handle (struct serial *scb)
if (ps->wait.read_event == INVALID_HANDLE_VALUE)
return;
- SetEvent (ps->wait.stop_select);
- WaitForSingleObject (ps->wait.have_stopped, INFINITE);
+ stop_select_thread (&ps->wait);
}
static int
@@ -931,24 +989,16 @@ pipe_avail (struct serial *scb, int fd)
struct net_windows_state
{
- HANDLE read_event;
- HANDLE except_event;
-
- HANDLE start_select;
- HANDLE stop_select;
- HANDLE exit_select;
- HANDLE have_stopped;
-
+ struct ser_console_state base;
+
HANDLE sock_event;
-
- HANDLE thread;
};
static DWORD WINAPI
net_windows_select_thread (void *arg)
{
struct serial *scb = arg;
- struct net_windows_state *state, state_copy;
+ struct net_windows_state *state;
int event_index;
state = scb->state;
@@ -958,44 +1008,37 @@ net_windows_select_thread (void *arg)
HANDLE wait_events[2];
WSANETWORKEVENTS events;
- SetEvent (state->have_stopped);
+ select_thread_wait (&state->base);
- 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);
-
- wait_events[0] = state->stop_select;
+ wait_events[0] = state->base.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)
- continue;
-
- if (event_index != WAIT_OBJECT_0 + 1)
+ || WaitForSingleObject (state->base.stop_select, 0) == WAIT_OBJECT_0)
+ /* We have been requested to stop. */
+ ;
+ else if (event_index != WAIT_OBJECT_0 + 1)
+ /* Some error has occured. Assume that this is an error
+ condition. */
+ SetEvent (state->base.except_event);
+ else
{
- /* 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 (scb->fd, state->sock_event, &events);
+
+ gdb_assert (events.lNetworkEvents & (FD_READ | FD_CLOSE));
+
+ if (events.lNetworkEvents & FD_READ)
+ SetEvent (state->base.read_event);
+
+ if (events.lNetworkEvents & FD_CLOSE)
+ SetEvent (state->base.except_event);
}
- /* Enumerate the internal network events, and reset the object that
- signalled us to catch the next event. */
- WSAEnumNetworkEvents (scb->fd, state->sock_event, &events);
-
- gdb_assert (events.lNetworkEvents & (FD_READ | FD_CLOSE));
-
- if (events.lNetworkEvents & FD_READ)
- SetEvent (state->read_event);
-
- if (events.lNetworkEvents & FD_CLOSE)
- SetEvent (state->except_event);
+ SetEvent (state->base.have_stopped);
}
}
@@ -1005,12 +1048,12 @@ net_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
struct net_windows_state *state = scb->state;
/* Start from a clean slate. */
- ResetEvent (state->read_event);
- ResetEvent (state->except_event);
- ResetEvent (state->stop_select);
+ ResetEvent (state->base.read_event);
+ ResetEvent (state->base.except_event);
+ ResetEvent (state->base.stop_select);
- *read = state->read_event;
- *except = state->except_event;
+ *read = state->base.read_event;
+ *except = state->base.except_event;
/* Check any pending events. This both avoids starting the thread
unnecessarily, and handles stray FD_READ events (see below). */
@@ -1042,7 +1085,7 @@ net_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
if (ioctlsocket (scb->fd, FIONREAD, &available) == 0
&& available > 0)
{
- SetEvent (state->read_event);
+ SetEvent (state->base.read_event);
any = 1;
}
else
@@ -1056,7 +1099,7 @@ net_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
still valid, and it will not be resignalled. */
if (events.lNetworkEvents & FD_CLOSE)
{
- SetEvent (state->except_event);
+ SetEvent (state->base.except_event);
any = 1;
}
@@ -1065,8 +1108,7 @@ net_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
return;
}
- /* Start the select thread. */
- SetEvent (state->start_select);
+ start_select_thread (&state->base);
}
static void
@@ -1074,8 +1116,7 @@ net_windows_done_wait_handle (struct serial *scb)
{
struct net_windows_state *state = scb->state;
- SetEvent (state->stop_select);
- WaitForSingleObject (state->have_stopped, INFINITE);
+ stop_select_thread (&state->base);
}
static int
@@ -1093,28 +1134,12 @@ net_windows_open (struct serial *scb, const char *name)
memset (state, 0, sizeof (struct net_windows_state));
scb->state = state;
- /* Create auto reset events to wake, stop, and exit the select
- thread. */
- state->start_select = CreateEvent (0, FALSE, FALSE, 0);
- state->stop_select = CreateEvent (0, FALSE, FALSE, 0);
- state->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. */
- state->have_stopped = CreateEvent (0, TRUE, 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. */
- state->thread = CreateThread (NULL, 0, net_windows_select_thread, scb, 0,
- &threadId);
+ /* Start the thread. */
+ create_select_thread (net_windows_select_thread, scb, &state->base);
return 0;
}
@@ -1125,17 +1150,7 @@ net_windows_close (struct serial *scb)
{
struct net_windows_state *state = scb->state;
- SetEvent (state->exit_select);
- WaitForSingleObject (state->thread, INFINITE);
-
- CloseHandle (state->read_event);
- CloseHandle (state->except_event);
-
- CloseHandle (state->start_select);
- CloseHandle (state->stop_select);
- CloseHandle (state->exit_select);
- CloseHandle (state->have_stopped);
-
+ destroy_select_thread (&state->base);
CloseHandle (state->sock_event);
xfree (scb->state);