/* select.cc
- Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
Written by Christopher Faylor of Cygnus Solutions
cgf@cygnus.com
#define __INSIDE_CYGWIN_NET__
#define Win32_Winsock
+#include "winsup.h"
#include <errno.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/time.h>
-#include "winsup.h"
+#include <wingdi.h>
+#include <winuser.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <winsock.h>
#include "select.h"
+#include "cygerrno.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "sync.h"
+#include "sigproc.h"
+#include "perthread.h"
+#include "tty.h"
/*
* All these defines below should be in sys/types.h
#define UNIX_FD_ZERO(p, n) \
bzero ((caddr_t)(p), sizeof_fd_set ((n)))
-#define allocfd_set(n) ((fd_set *) alloca (sizeof_fd_set (n)))
+#define allocfd_set(n) ((fd_set *) memset (alloca (sizeof_fd_set (n)), 0, sizeof_fd_set (n)))
#define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n));
/* Make a fhandler_foo::ready_for_ready method.
me.fd = fd; \
(void) select_read (&me); \
while (!peek_##what (&me, ignra) && howlong == INFINITE) \
- if (fd >= 0 && dtable.not_open (fd)) \
+ if (fd >= 0 && fdtab.not_open (fd)) \
break; \
else if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0) \
break; \
#define set_handle_or_return_if_not_open(h, s) \
h = (s)->fh->get_handle (); \
- if (dtable.not_open ((s)->fd)) \
+ if (fdtab.not_open ((s)->fd)) \
{ \
(s)->saw_error = TRUE; \
set_errno (EBADF); \
*/
extern "C"
int
-cygwin_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
- struct timeval *to)
+cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *to)
{
select_stuff sel;
- fd_set *dummy_readfds = allocfd_set (n);
- fd_set *dummy_writefds = allocfd_set (n);
- fd_set *dummy_exceptfds = allocfd_set (n);
+ fd_set *dummy_readfds = allocfd_set (maxfds);
+ fd_set *dummy_writefds = allocfd_set (maxfds);
+ fd_set *dummy_exceptfds = allocfd_set (maxfds);
+ sigframe thisframe (mainthread);
#if 0
if (n > FD_SETSIZE)
}
#endif
- select_printf ("%d, %p, %p, %p, %p", n, readfds, writefds, exceptfds, to);
+ select_printf ("%d, %p, %p, %p, %p", maxfds, readfds, writefds, exceptfds, to);
- memset (&sel, 0, sizeof (sel));
if (!readfds)
- {
- UNIX_FD_ZERO (dummy_readfds, n);
- readfds = dummy_readfds;
- }
+ readfds = dummy_readfds;
if (!writefds)
- {
- UNIX_FD_ZERO (dummy_writefds, n);
- writefds = dummy_writefds;
- }
+ writefds = dummy_writefds;
if (!exceptfds)
- {
- UNIX_FD_ZERO (dummy_exceptfds, n);
- exceptfds = dummy_exceptfds;
- }
+ exceptfds = dummy_exceptfds;
- for (int i = 0; i < n; i++)
+ for (int i = 0; i < maxfds; i++)
if (!sel.test_and_set (i, readfds, writefds, exceptfds))
{
select_printf ("aborting due to test_and_set error");
else
select_printf ("to NULL, ms %x", ms);
- select_printf ("sel.total %d, sel.always_ready %d", sel.total, sel.always_ready);
+ select_printf ("sel.always_ready %d", sel.always_ready);
/* Degenerate case. No fds to wait for. Just wait. */
- if (sel.total == 0)
+ if (sel.start.next == NULL)
{
if (WaitForSingleObject (signal_arrived, ms) == WAIT_OBJECT_0)
{
return 0;
}
- /* If one of the selected fds is "always ready" just poll everything and return
- the result. There is no need to wait. */
- if (sel.always_ready || ms == 0)
- {
- UNIX_FD_ZERO (readfds, n);
- UNIX_FD_ZERO (writefds, n);
- UNIX_FD_ZERO (exceptfds, n);
- return sel.poll (readfds, writefds, exceptfds);
- }
+ /* Allocate some fd_set structures using the number of fds as a guide. */
+ fd_set *r = allocfd_set (maxfds);
+ fd_set *w = allocfd_set (maxfds);
+ fd_set *e = allocfd_set (maxfds);
- /* Wait for an fd to come alive */
- return sel.wait (readfds, writefds, exceptfds, ms);
+ if (sel.always_ready || ms == 0)
+ /* Don't bother waiting. */;
+ else if (sel.wait (r, w, e, ms))
+ return -1; /* some kind of error */
+
+ copyfd_set (readfds, r, maxfds);
+ copyfd_set (writefds, w, maxfds);
+ copyfd_set (exceptfds, e, maxfds);
+ return sel.poll (readfds, writefds, exceptfds);
}
/* Cleanup */
fd_set *exceptfds)
{
select_record *s = NULL;
- if (UNIX_FD_ISSET (i, readfds) && (s = dtable.select_read (i, s)) == NULL)
+ if (UNIX_FD_ISSET (i, readfds) && (s = fdtab.select_read (i, s)) == NULL)
return 0; /* error */
- if (UNIX_FD_ISSET (i, writefds) && (s = dtable.select_write (i, s)) == NULL)
+ if (UNIX_FD_ISSET (i, writefds) && (s = fdtab.select_write (i, s)) == NULL)
return 0; /* error */
- if (UNIX_FD_ISSET (i, exceptfds) && (s = dtable.select_except (i, s)) == NULL)
+ if (UNIX_FD_ISSET (i, exceptfds) && (s = fdtab.select_except (i, s)) == NULL)
return 0; /* error */
if (s == NULL)
return 1; /* nothing to do */
s->next = start.next;
start.next = s;
- total++;
return 1;
}
DWORD ms)
{
int wait_ret;
- HANDLE w4[total + 1];
+ HANDLE w4[MAXIMUM_WAIT_OBJECTS];
select_record *s = &start;
int m = 0;
counting the number of active fds. */
while ((s = s->next))
{
+ if (m > MAXIMUM_WAIT_OBJECTS)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
if (!s->startup (s, this))
{
__seterrno ();
continue;
}
- int n = m - 1;
DWORD start_time = GetTickCount (); /* Record the current time for later use. */
- /* Allocate some fd_set structures using the number of fds as a guide. */
- fd_set *r = allocfd_set (n);
- fd_set *w = allocfd_set (n);
- fd_set *e = allocfd_set (n);
- UNIX_FD_ZERO (r, n);
- UNIX_FD_ZERO (w, n);
- UNIX_FD_ZERO (e, n);
- debug_printf ("n %d, ms %u", n, ms);
+ debug_printf ("m %d, ms %u", m, ms);
for (;;)
{
if (!windows_used)
if (s->saw_error)
return -1; /* Somebody detected an error */
else if ((((wait_ret >= m && s->windows_handle) || s->h == w4[wait_ret])) &&
- s->verify (s, r, w, e))
+ s->verify (s, readfds, writefds, exceptfds))
gotone = TRUE;
select_printf ("gotone %d", gotone);
}
out:
- copyfd_set (readfds, r, n);
- copyfd_set (writefds, w, n);
- copyfd_set (exceptfds, e, n);
-
- return poll (readfds, writefds, exceptfds);
+ select_printf ("returning 0");
+ return 0;
}
static int
if (!s->read_selected && !s->except_selected)
goto out;
- if (s->read_selected && fh->bg_check (SIGTTIN) <= 0)
+ if (s->read_selected)
{
- gotone = s->read_ready = 1;
- goto out;
- }
+ if (s->read_ready)
+ {
+ select_printf ("already ready");
+ gotone = 1;
+ goto out;
+ }
+ if (fh->bg_check (SIGTTIN) <= bg_eof)
+ {
+ gotone = s->read_ready = 1;
+ goto out;
+ }
- if (!ignra && fh->get_readahead_valid ())
- {
- select_printf ("readahead");
- gotone = s->read_ready = 1;
- goto out;
+ switch (fh->get_device ())
+ {
+ case FH_PTYM:
+ case FH_TTYM:
+ if (((fhandler_pty_master *)fh)->need_nl)
+ {
+ gotone = s->read_ready = 1;
+ goto out;
+ }
+ break;
+ default:
+ if (!ignra && fh->get_readahead_valid ())
+ {
+ select_printf ("readahead");
+ gotone = s->read_ready = 1;
+ goto out;
+ }
+ }
}
- else if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
+ if (fh->get_device() != FH_PIPEW &&
+ !PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
{
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
n = -1;
gotone = s->except_ready = TRUE;
if (s->read_selected)
gotone += s->read_ready = TRUE;
+ select_printf ("saw eof on '%s'", fh->get_name ());
}
out:
goto out;
}
}
+ /* Paranoid check */
+ if (pi->stop_thread_pipe)
+ {
+ select_printf ("stopping from outer loop");
+ break;
+ }
if (gotone)
break;
Sleep (10);
static int
peek_console (select_record *me, int ignra)
{
- extern const char * get_nonascii_key (INPUT_RECORD& input_rec);
+ extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *);
fhandler_console *fh = (fhandler_console *)me->fh;
if (!me->read_selected)
return me->read_ready = 1;
}
+ if (me->read_ready)
+ {
+ select_printf ("already ready");
+ return 1;
+ }
+
INPUT_RECORD irec;
DWORD events_read;
HANDLE h;
+ char tmpbuf[17];
set_handle_or_return_if_not_open (h, me);
for (;;)
- if (fh->bg_check (SIGTTIN) <= 0)
+ if (fh->bg_check (SIGTTIN) <= bg_eof)
return me->read_ready = 1;
else if (!PeekConsoleInput (h, &irec, 1, &events_read) || !events_read)
break;
{
if (irec.EventType == WINDOW_BUFFER_SIZE_EVENT)
kill_pgrp (fh->tc->getpgid (), SIGWINCH);
+ else if (irec.EventType == MOUSE_EVENT &&
+ (irec.Event.MouseEvent.dwEventFlags == 0 ||
+ irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
+ {
+ if (fh->mouse_aware ())
+ return me->read_ready = 1;
+ }
else if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown == TRUE &&
- (irec.Event.KeyEvent.uChar.AsciiChar || get_nonascii_key (irec)))
+ (irec.Event.KeyEvent.uChar.AsciiChar || get_nonascii_key (irec, tmpbuf)))
return me->read_ready = 1;
/* Read and discard the event */
s->startup = no_startup;
s->poll = poll_console;
s->verify = poll_console;
+ set_cursor_maybe ();
}
s->h = get_handle ();
s->startup = no_startup;
s->poll = poll_console;
s->verify = no_verify;
+ set_cursor_maybe ();
}
s->write_selected = TRUE;
s->startup = no_startup;
s->poll = poll_console;
s->verify = no_verify;
+ set_cursor_maybe ();
}
s->except_selected = TRUE;
return ((fhandler_pipe *)this)->fhandler_pipe::select_except (s);
}
+static int
+verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds)
+{
+ if (WaitForSingleObject (me->h, 0) == WAIT_OBJECT_0)
+ me->read_ready = 1;
+ return set_bits (me, readfds, writefds, exceptfds);
+}
+
+select_record *
+fhandler_tty_slave::select_read (select_record *s)
+{
+ if (!s)
+ s = new select_record;
+ s->h = input_available_event;
+ s->startup = no_startup;
+ s->poll = poll_pipe;
+ s->verify = verify_tty_slave;
+ s->read_selected = TRUE;
+ s->cleanup = NULL;
+ return s;
+}
+
+int
+fhandler_tty_slave::ready_for_read (int fd, DWORD howlong, int ignra)
+{
+ HANDLE w4[2];
+ if (!ignra && get_readahead_valid ())
+ {
+ select_printf ("readahead");
+ return 1;
+ }
+ w4[0] = signal_arrived;
+ w4[1] = input_available_event;
+ switch (WaitForMultipleObjects (2, w4, FALSE, howlong))
+ {
+ case WAIT_OBJECT_0 + 1:
+ return 1;
+ case WAIT_FAILED:
+ select_printf ( "wait failed %E" );
+ case WAIT_OBJECT_0:
+ case WAIT_TIMEOUT:
+ default:
+ return 0;
+ }
+}
+
select_record *
fhandler_dev_null::select_read (select_record *s)
{
HANDLE h;
set_handle_or_return_if_not_open (h, s);
int ready = 0;
+
+ if (s->read_selected && s->read_ready || (s->write_selected && s->write_ready))
+ {
+ select_printf ("already ready");
+ ready = 1;
+ goto out;
+ }
+
(void) SetCommMask (h, EV_RXCHAR);
if (!fh->overlapped_armed)
{
case WAIT_OBJECT_0:
if (!ClearCommError (h, &ev, &st))
- {
- debug_printf ("ClearCommError");
- goto err;
- }
+ {
+ debug_printf ("ClearCommError");
+ goto err;
+ }
else if (!st.cbInQue)
Sleep (to);
else
goto err;
}
+out:
return ready;
err:
peek_socket (select_record *me, int)
{
winsock_fd_set ws_readfds, ws_writefds, ws_exceptfds;
- struct timeval tv = {0};
+ struct timeval tv = {0, 0};
WINSOCK_FD_ZERO (&ws_readfds);
WINSOCK_FD_ZERO (&ws_writefds);
WINSOCK_FD_ZERO (&ws_exceptfds);
return 0;
}
- if (WINSOCK_FD_ISSET (h, &ws_readfds))
+ if (WINSOCK_FD_ISSET (h, &ws_readfds) || (me->read_selected && me->read_ready))
gotone = me->read_ready = TRUE;
- if (WINSOCK_FD_ISSET (h, &ws_writefds))
+ if (WINSOCK_FD_ISSET (h, &ws_writefds) || (me->write_selected && me->write_ready))
gotone = me->write_ready = TRUE;
- if (WINSOCK_FD_ISSET (h, &ws_exceptfds))
+ if (WINSOCK_FD_ISSET (h, &ws_exceptfds) || (me->except_selected && me->except_ready))
gotone = me->except_ready = TRUE;
return gotone;
}
select_printf ("connect failed");
/* FIXME: now what? */
}
+ shutdown (s, 2);
closesocket (s);
/* Wait for thread to go away */
WaitForSingleObject (si->thread, INFINITE);
+ shutdown (si->exitsock, 2);
closesocket (si->exitsock);
CloseHandle (si->thread);
stuff->device_specific[FHDEVN(FH_SOCKET)] = NULL;
MSG m;
HANDLE h;
set_handle_or_return_if_not_open (h, me);
+
+ if (me->read_selected && me->read_ready)
+ return 1;
+
if (PeekMessage (&m, (HWND) h, 0, 0, PM_NOREMOVE))
{
me->read_ready = TRUE;