newlib-cygwin/winsup/cygwin/select.cc

1508 lines
35 KiB
C++
Raw Normal View History

2000-02-18 03:38:33 +08:00
/* select.cc
2002-03-05 10:23:39 +08:00
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
2000-02-18 03:38:33 +08:00
Written by Christopher Faylor of Cygnus Solutions
cgf@cygnus.com
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
/*
* The following line means that the BSD socket
* definitions for fd_set, FD_ISSET etc. are used in this
* file.
*/
#define __INSIDE_CYGWIN_NET__
#include "winsup.h"
2000-02-18 03:38:33 +08:00
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/time.h>
#include <wingdi.h>
#include <winuser.h>
2000-02-18 03:38:33 +08:00
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#define USE_SYS_TYPES_FD_SET
2000-02-18 03:38:33 +08:00
#include <winsock.h>
#include "select.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
Add "path.h" include throughout, where needed. Use new path_conv methods and operators to simplify testing for directory and attributes, throughout. * path.h (path_conv::exists): New method. (path_conv::has_attribute): Ditto. (path_conv::isdir): Ditto. (path_conv::DWORD &): New operator. (path_conv::int &): Ditto. * dir.cc (rmdir): Eliminate a goto. * dtable.cc (dtable::build_fhandler): Accept opt and suffix info for path_conv.check. Return fh == NULL on path_conv error. Pass unit to set_name as appropriate. (dtable::reset_unix_path_name): New method. * dtable.h (dtable): Declare new method. Reflect arg changes to build_fhandler. * fhandler.cc (fhandler_disk_dummy_name): Eliminate. (fhandler_base::set_name): Expect paths to be NULL. Build unix_path_name from win32_path_name when it is a device. (fhandler_base::reset_unix_path_name): New method. (fhandler_base::raw_read): Report EISDIR when ERROR_INVALID_FUNCTION or ERROR_INVALID_PARAMETER and reading a directory. (fhandler_disk_file::fstat): Don't call stat_dev since we should now never be calling fhandler_disk_file methods with devices. (fhandler_base::fhandler_base): Clear {unix,win32}_path_name. (fhandler_base::~fhandler_base): Always free {unix,win32}_path_name. (fhandler_disk_file::fhandler_disk_file): Remove set_no_free_names kludge. (fhandler_disk_file::open): Ditto. * fhandler.h (fhandler_base::no_free_names): Eliminate. (fhandler_base::set_no_free_names): Ditto. * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Don't set unix_path_name here. * path.cc (fchdir): Lock fd table throughout. Use new dtable::reset_unix_path_name method to reset path. * syscalls.cc (stat_worker): Reorganize to always call fstat method. Pass path_conv method to fhandler_*::open. (chroot): Elminate a goto.
2001-10-01 12:10:07 +08:00
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
#include "perthread.h"
#include "tty.h"
#include "cygthread.h"
2000-02-18 03:38:33 +08:00
/*
* All these defines below should be in sys/types.h
* but because of the includes above, they may not have
* been included. We create special UNIX_xxxx versions here.
*/
#ifndef NBBY
#define NBBY 8 /* number of bits in a byte */
#endif /* NBBY */
/*
* Select uses bit masks of file descriptors in longs.
* These macros manipulate such bit fields (the filesystem macros use chars).
* FD_SETSIZE may be defined by the user, but the default here
* should be >= NOFILE (param.h).
*/
typedef long fd_mask;
#define UNIX_NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */
#ifndef unix_howmany
#define unix_howmany(x,y) (((x)+((y)-1))/(y))
#endif
#define unix_fd_set fd_set
#define NULL_fd_set ((fd_set *) NULL)
2000-02-18 03:38:33 +08:00
#define sizeof_fd_set(n) \
((unsigned) (NULL_fd_set->fds_bits + unix_howmany ((n), UNIX_NFDBITS)))
2000-02-18 03:38:33 +08:00
#define UNIX_FD_SET(n, p) \
((p)->fds_bits[(n)/UNIX_NFDBITS] |= (1L << ((n) % UNIX_NFDBITS)))
#define UNIX_FD_CLR(n, p) \
((p)->fds_bits[(n)/UNIX_NFDBITS] &= ~(1L << ((n) % UNIX_NFDBITS)))
#define UNIX_FD_ISSET(n, p) \
((p)->fds_bits[(n)/UNIX_NFDBITS] & (1L << ((n) % UNIX_NFDBITS)))
#define UNIX_FD_ZERO(p, n) \
bzero ((caddr_t)(p), sizeof_fd_set ((n)))
#define allocfd_set(n) ((fd_set *) memset (alloca (sizeof_fd_set (n)), 0, sizeof_fd_set (n)))
2000-02-18 03:38:33 +08:00
#define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n));
#define set_handle_or_return_if_not_open(h, s) \
h = (s)->fh->get_handle (); \
if (cygheap->fdtab.not_open ((s)->fd)) \
2000-02-18 03:38:33 +08:00
{ \
(s)->saw_error = true; \
set_sig_errno (EBADF); \
2000-02-18 03:38:33 +08:00
return -1; \
} \
/* The main select code.
*/
extern "C" int
cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *to)
2000-02-18 03:38:33 +08:00
{
select_stuff sel;
fd_set *dummy_readfds = allocfd_set (maxfds);
fd_set *dummy_writefds = allocfd_set (maxfds);
fd_set *dummy_exceptfds = allocfd_set (maxfds);
sigframe thisframe (mainthread);
2000-02-18 03:38:33 +08:00
select_printf ("%d, %p, %p, %p, %p", maxfds, readfds, writefds, exceptfds, to);
2000-02-18 03:38:33 +08:00
if (!readfds)
readfds = dummy_readfds;
2000-02-18 03:38:33 +08:00
if (!writefds)
writefds = dummy_writefds;
2000-02-18 03:38:33 +08:00
if (!exceptfds)
exceptfds = dummy_exceptfds;
2000-02-18 03:38:33 +08:00
for (int i = 0; i < maxfds; i++)
2000-02-18 03:38:33 +08:00
if (!sel.test_and_set (i, readfds, writefds, exceptfds))
{
select_printf ("aborting due to test_and_set error");
return -1; /* Invalid fd, maybe? */
}
/* Convert to milliseconds or INFINITE if to == NULL */
DWORD ms = to ? (to->tv_sec * 1000) + (to->tv_usec / 1000) : INFINITE;
if (ms == 0 && to->tv_usec)
ms = 1; /* At least 1 ms granularity */
if (to)
select_printf ("to->tv_sec %d, to->tv_usec %d, ms %d", to->tv_sec, to->tv_usec, ms);
else
select_printf ("to NULL, ms %x", ms);
select_printf ("sel.always_ready %d", sel.always_ready);
2000-02-18 03:38:33 +08:00
int timeout = 0;
/* 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);
2000-02-18 03:38:33 +08:00
/* Degenerate case. No fds to wait for. Just wait. */
if (sel.start.next == NULL)
2000-02-18 03:38:33 +08:00
{
2001-08-29 04:39:22 +08:00
if (WaitForSingleObject (signal_arrived, ms) == WAIT_OBJECT_0)
2000-02-18 03:38:33 +08:00
{
select_printf ("signal received");
set_sig_errno (EINTR);
return -1;
}
timeout = 1;
2000-02-18 03:38:33 +08:00
}
else if (sel.always_ready || ms == 0)
/* Don't bother waiting. */;
else if ((timeout = sel.wait (r, w, e, ms) < 0))
return -1; /* some kind of error */
sel.cleanup ();
copyfd_set (readfds, r, maxfds);
copyfd_set (writefds, w, maxfds);
copyfd_set (exceptfds, e, maxfds);
return timeout ? 0 : sel.poll (readfds, writefds, exceptfds);
2000-02-18 03:38:33 +08:00
}
/* Call cleanup functions for all inspected fds. Gets rid of any
executing threads. */
void
select_stuff::cleanup ()
2000-02-18 03:38:33 +08:00
{
select_record *s = &start;
select_printf ("calling cleanup routines");
while ((s = s->next))
if (s->cleanup)
{
s->cleanup (s, this);
s->cleanup = NULL;
}
}
2000-02-18 03:38:33 +08:00
/* Destroy all storage associated with select stuff. */
select_stuff::~select_stuff ()
{
cleanup ();
select_record *s = &start;
2000-02-18 03:38:33 +08:00
select_record *snext = start.next;
select_printf ("deleting select records");
while ((s = snext))
{
snext = s->next;
delete s;
}
}
/* Add a record to the select chain */
int
select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds)
{
select_record *s = NULL;
if (UNIX_FD_ISSET (i, readfds) && (s = cygheap->fdtab.select_read (i, s)) == NULL)
2000-02-18 03:38:33 +08:00
return 0; /* error */
if (UNIX_FD_ISSET (i, writefds) && (s = cygheap->fdtab.select_write (i, s)) == NULL)
2000-02-18 03:38:33 +08:00
return 0; /* error */
if (UNIX_FD_ISSET (i, exceptfds) && (s = cygheap->fdtab.select_except (i, s)) == NULL)
2000-02-18 03:38:33 +08:00
return 0; /* error */
if (s == NULL)
return 1; /* nothing to do */
if (s->read_ready || s->write_ready || s->except_ready)
always_ready = true;
2000-02-18 03:38:33 +08:00
if (s->windows_handle || s->windows_handle || s->windows_handle)
windows_used = true;
2000-02-18 03:38:33 +08:00
s->next = start.next;
start.next = s;
return 1;
}
/* The heart of select. Waits for an fd to do something interesting. */
int
select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
DWORD ms)
{
int wait_ret;
HANDLE w4[MAXIMUM_WAIT_OBJECTS];
2000-02-18 03:38:33 +08:00
select_record *s = &start;
int m = 0;
int res = 0;
2000-02-18 03:38:33 +08:00
w4[m++] = signal_arrived; /* Always wait for the arrival of a signal. */
/* Loop through the select chain, starting up anything appropriate and
counting the number of active fds. */
while ((s = s->next))
{
if (m > MAXIMUM_WAIT_OBJECTS)
{
set_sig_errno (EINVAL);
return -1;
}
2000-02-18 03:38:33 +08:00
if (!s->startup (s, this))
{
__seterrno ();
return -1;
}
if (s->h == NULL)
continue;
for (int i = 1; i < m; i++)
if (w4[i] == s->h)
goto next_while;
w4[m++] = s->h;
next_while:
continue;
}
DWORD start_time = GetTickCount (); /* Record the current time for later use. */
debug_printf ("m %d, ms %u", m, ms);
2000-02-18 03:38:33 +08:00
for (;;)
{
if (!windows_used)
wait_ret = WaitForMultipleObjects (m, w4, FALSE, ms);
else
wait_ret = MsgWaitForMultipleObjects (m, w4, FALSE, ms, QS_ALLINPUT);
switch (wait_ret)
{
case WAIT_OBJECT_0:
select_printf ("signal received");
set_sig_errno (EINTR);
return -1;
case WAIT_FAILED:
select_printf ("WaitForMultipleObjects failed");
__seterrno ();
return -1;
case WAIT_TIMEOUT:
select_printf ("timed out");
res = 1;
2000-02-18 03:38:33 +08:00
goto out;
}
select_printf ("woke up. wait_ret %d. verifying", wait_ret);
s = &start;
int gotone = FALSE;
/* Some types of object (e.g., consoles) wake up on "inappropriate" events
2001-11-05 14:09:15 +08:00
like mouse movements. The verify function will detect these situations.
If it returns false, then this wakeup was a false alarm and we should go
back to waiting. */
2000-02-18 03:38:33 +08:00
while ((s = s->next))
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, readfds, writefds, exceptfds))
gotone = true;
2000-02-18 03:38:33 +08:00
select_printf ("gotone %d", gotone);
if (gotone)
goto out;
if (ms == INFINITE)
{
select_printf ("looping");
continue;
}
select_printf ("recalculating ms");
DWORD now = GetTickCount ();
if (now > (start_time + ms))
{
select_printf ("timed out after verification");
goto out;
}
ms -= (now - start_time);
start_time = now;
select_printf ("ms now %u", ms);
}
out:
select_printf ("returning %d", res);
return res;
2000-02-18 03:38:33 +08:00
}
static int
set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds)
2000-02-18 03:38:33 +08:00
{
int ready = 0;
select_printf ("me %p, testing fd %d (%s)", me, me->fd, me->fh->get_name ());
if (me->read_selected && me->read_ready)
{
UNIX_FD_SET (me->fd, readfds);
ready++;
}
if (me->write_selected && me->write_ready)
{
UNIX_FD_SET (me->fd, writefds);
if (me->except_on_write && me->fh->get_device () == FH_SOCKET)
2002-09-30 23:17:44 +08:00
((fhandler_socket *) me->fh)->set_connect_state (CONNECTED);
2000-02-18 03:38:33 +08:00
ready++;
}
if ((me->except_selected || me->except_on_write) && me->except_ready)
2000-02-18 03:38:33 +08:00
{
if (me->except_on_write) /* Only on sockets */
2002-09-30 23:17:44 +08:00
{
UNIX_FD_SET (me->fd, writefds);
if (me->fh->get_device () == FH_SOCKET)
((fhandler_socket *) me->fh)->set_connect_state (CONNECTED);
2002-09-30 23:17:44 +08:00
}
if (me->except_selected)
UNIX_FD_SET (me->fd, exceptfds);
2000-02-18 03:38:33 +08:00
ready++;
}
select_printf ("ready %d", ready);
return ready;
}
/* Poll every fd in the select chain. Set appropriate fd in mask. */
int
select_stuff::poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
{
int n = 0;
select_record *s = &start;
while ((s = s->next))
n += (!s->peek || s->peek (s, true)) ?
set_bits (s, readfds, writefds, exceptfds) : 0;
select_printf ("returning %d", n);
return n;
}
2000-02-18 03:38:33 +08:00
static int
verify_true (select_record *, fd_set *, fd_set *, fd_set *)
2000-02-18 03:38:33 +08:00
{
return 1;
}
static int
verify_ok (select_record *me, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds)
{
return set_bits (me, readfds, writefds, exceptfds);
}
static int
no_startup (select_record *, select_stuff *)
2000-02-18 03:38:33 +08:00
{
return 1;
}
static int
no_verify (select_record *, fd_set *, fd_set *, fd_set *)
{
return 0;
}
static int
peek_pipe (select_record *s, bool from_select)
2000-02-18 03:38:33 +08:00
{
int n = 0;
int gotone = 0;
fhandler_base *fh = s->fh;
HANDLE h;
set_handle_or_return_if_not_open (h, s);
/* pipes require a guard mutex to guard against the situation where multiple
readers are attempting to read from the same pipe. In this scenario, it
is possible for PeekNamedPipe to report available data to two readers but
only one will actually get the data. This will result in the other reader
entering fhandler_base::raw_read and blocking indefinitely in an interruptible
state. This causes things like "make -j2" to hang. So, for the non-select case
we use the pipe mutex, if it is available. */
HANDLE guard_mutex = from_select ? NULL : fh->get_guard ();
2000-02-18 03:38:33 +08:00
/* Don't perform complicated tests if we don't need to. */
if (!s->read_selected && !s->except_selected)
goto out;
if (s->read_selected)
2000-02-18 03:38:33 +08:00
{
if (s->read_ready)
{
select_printf ("already ready");
gotone = 1;
goto out;
}
2000-02-18 03:38:33 +08:00
switch (fh->get_device ())
{
case FH_PTYM:
case FH_TTYM:
if (((fhandler_pty_master *) fh)->need_nl)
{
gotone = s->read_ready = true;
goto out;
}
break;
default:
if (fh->get_readahead_valid ())
{
select_printf ("readahead");
gotone = s->read_ready = true;
goto out;
}
}
if (fh->bg_check (SIGTTIN) <= bg_eof)
{
gotone = s->read_ready = true;
goto out;
}
2000-02-18 03:38:33 +08:00
}
if (fh->get_device () == FH_PIPEW)
/* nothing */;
else if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
{
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
n = -1;
}
else if (!n || !guard_mutex)
/* no guard mutex or nothing to read from the pipe. */;
else if (WaitForSingleObject (guard_mutex, 0) != WAIT_OBJECT_0)
{
select_printf ("%s, couldn't get mutex %p, %E", fh->get_name (),
guard_mutex);
n = 0;
}
else
{
/* Now that we have the mutex, make sure that no one else has snuck
in and grabbed the data that we originally saw. */
if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
{
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
n = -1;
}
if (n <= 0)
ReleaseMutex (guard_mutex); /* Oops. We lost the race. */
}
2000-02-18 03:38:33 +08:00
if (n < 0)
{
fh->set_eof (); /* Flag that other end of pipe is gone */
2000-02-18 03:38:33 +08:00
select_printf ("%s, n %d", fh->get_name (), n);
if (s->except_selected)
gotone += s->except_ready = true;
2000-02-18 03:38:33 +08:00
if (s->read_selected)
gotone += s->read_ready = true;
2000-02-18 03:38:33 +08:00
}
if (n > 0 && s->read_selected)
{
select_printf ("%s, ready for read", fh->get_name ());
gotone += s->read_ready = true;
2000-02-18 03:38:33 +08:00
}
if (!gotone && s->fh->hit_eof ())
{
select_printf ("%s, saw EOF", fh->get_name ());
if (s->except_selected)
gotone = s->except_ready = true;
2000-02-18 03:38:33 +08:00
if (s->read_selected)
gotone += s->read_ready = true;
2000-04-12 05:22:53 +08:00
select_printf ("saw eof on '%s'", fh->get_name ());
2000-02-18 03:38:33 +08:00
}
out:
return gotone || s->write_ready;
}
static int start_thread_pipe (select_record *me, select_stuff *stuff);
struct pipeinf
{
cygthread *thread;
2000-02-18 03:38:33 +08:00
BOOL stop_thread_pipe;
select_record *start;
};
static DWORD WINAPI
thread_pipe (void *arg)
{
pipeinf *pi = (pipeinf *) arg;
2000-02-18 03:38:33 +08:00
BOOL gotone = FALSE;
for (;;)
{
select_record *s = pi->start;
while ((s = s->next))
if (s->startup == start_thread_pipe)
{
if (peek_pipe (s, true))
gotone = true;
2000-02-18 03:38:33 +08:00
if (pi->stop_thread_pipe)
{
select_printf ("stopping");
goto out;
}
}
/* Paranoid check */
if (pi->stop_thread_pipe)
{
select_printf ("stopping from outer loop");
break;
}
2000-02-18 03:38:33 +08:00
if (gotone)
break;
Sleep (10);
}
out:
return 0;
}
static int
start_thread_pipe (select_record *me, select_stuff *stuff)
{
if (stuff->device_specific[FHDEVN (FH_PIPE)])
2000-02-18 03:38:33 +08:00
{
me->h = *((pipeinf *) stuff->device_specific[FHDEVN (FH_PIPE)])->thread;
2000-02-18 03:38:33 +08:00
return 1;
}
pipeinf *pi = new pipeinf;
pi->start = &stuff->start;
pi->stop_thread_pipe = FALSE;
pi->thread = new cygthread (thread_pipe, (LPVOID) pi, "select_pipe");
me->h = *pi->thread;
2000-02-18 03:38:33 +08:00
if (!me->h)
return 0;
stuff->device_specific[FHDEVN (FH_PIPE)] = (void *) pi;
2000-02-18 03:38:33 +08:00
return 1;
}
static void
pipe_cleanup (select_record *, select_stuff *stuff)
2000-02-18 03:38:33 +08:00
{
pipeinf *pi = (pipeinf *) stuff->device_specific[FHDEVN (FH_PIPE)];
2000-02-18 03:38:33 +08:00
if (pi && pi->thread)
{
pi->stop_thread_pipe = true;
pi->thread->detach ();
2000-02-18 03:38:33 +08:00
delete pi;
stuff->device_specific[FHDEVN (FH_PIPE)] = NULL;
2000-02-18 03:38:33 +08:00
}
}
int
fhandler_pipe::ready_for_read (int fd, DWORD howlong)
{
int res;
if (howlong)
res = true;
else
res = fhandler_base::ready_for_read (fd, howlong);
if (res)
get_guard ();
return res;
}
2000-02-18 03:38:33 +08:00
select_record *
fhandler_pipe::select_read (select_record *s)
{
if (!s)
s = new select_record;
s->startup = start_thread_pipe;
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
s->peek = peek_pipe;
2000-02-18 03:38:33 +08:00
s->verify = verify_ok;
s->read_selected = true;
s->read_ready = false;
2000-02-18 03:38:33 +08:00
s->cleanup = pipe_cleanup;
return s;
}
select_record *
fhandler_pipe::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = no_verify;
}
s->peek = peek_pipe;
s->write_selected = true;
s->write_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_pipe::select_except (select_record *s)
{
if (!s)
s = new select_record;
s->startup = start_thread_pipe;
s->peek = peek_pipe;
2000-02-18 03:38:33 +08:00
s->verify = verify_ok;
s->cleanup = pipe_cleanup;
s->except_selected = true;
s->except_ready = false;
2000-02-18 03:38:33 +08:00
return s;
}
static int
peek_console (select_record *me, bool)
2000-02-18 03:38:33 +08:00
{
extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *);
fhandler_console *fh = (fhandler_console *) me->fh;
2000-02-18 03:38:33 +08:00
if (!me->read_selected)
return me->write_ready;
if (fh->get_readahead_valid ())
2000-02-18 03:38:33 +08:00
{
select_printf ("readahead");
return me->read_ready = true;
2000-02-18 03:38:33 +08:00
}
if (me->read_ready)
{
select_printf ("already ready");
return 1;
}
2000-02-18 03:38:33 +08:00
INPUT_RECORD irec;
DWORD events_read;
HANDLE h;
char tmpbuf[17];
2000-02-18 03:38:33 +08:00
set_handle_or_return_if_not_open (h, me);
for (;;)
if (fh->bg_check (SIGTTIN) <= bg_eof)
return me->read_ready = true;
2000-02-18 03:38:33 +08:00
else if (!PeekConsoleInput (h, &irec, 1, &events_read) || !events_read)
break;
else
{
if (irec.EventType == KEY_EVENT)
{
if (irec.Event.KeyEvent.bKeyDown
&& (irec.Event.KeyEvent.uChar.AsciiChar
|| get_nonascii_key (irec, tmpbuf)))
return me->read_ready = true;
}
else
{
fh->send_winch_maybe ();
if (irec.EventType == MOUSE_EVENT
&& fh->mouse_aware ()
&& (irec.Event.MouseEvent.dwEventFlags == 0
|| irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
return me->read_ready = true;
}
2000-02-18 03:38:33 +08:00
/* Read and discard the event */
ReadConsoleInput (h, &irec, 1, &events_read);
}
return me->write_ready;
}
2001-11-05 14:09:15 +08:00
static int
verify_console (select_record *me, fd_set *rfds, fd_set *wfds,
fd_set *efds)
{
return peek_console (me, true);
}
2000-02-18 03:38:33 +08:00
select_record *
fhandler_console::select_read (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_console;
set_cursor_maybe ();
2000-02-18 03:38:33 +08:00
}
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
s->peek = peek_console;
2000-02-18 03:38:33 +08:00
s->h = get_handle ();
s->read_selected = true;
s->read_ready = false;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_console::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = no_verify;
set_cursor_maybe ();
2000-02-18 03:38:33 +08:00
}
s->peek = peek_console;
s->write_selected = true;
s->write_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_console::select_except (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = no_verify;
set_cursor_maybe ();
2000-02-18 03:38:33 +08:00
}
s->peek = peek_console;
s->except_selected = true;
s->except_ready = false;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_tty_common::select_read (select_record *s)
{
return ((fhandler_pipe *) this)->fhandler_pipe::select_read (s);
2000-02-18 03:38:33 +08:00
}
select_record *
fhandler_tty_common::select_write (select_record *s)
{
return ((fhandler_pipe *) this)->fhandler_pipe::select_write (s);
2000-02-18 03:38:33 +08:00
}
select_record *
fhandler_tty_common::select_except (select_record *s)
{
return ((fhandler_pipe *) this)->fhandler_pipe::select_except (s);
2000-02-18 03:38:33 +08:00
}
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 = true;
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;
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
s->peek = peek_pipe;
s->verify = verify_tty_slave;
s->read_selected = true;
s->read_ready = false;
s->cleanup = NULL;
return s;
}
2000-02-18 03:38:33 +08:00
select_record *
fhandler_dev_null::select_read (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = no_verify;
}
s->h = get_handle ();
s->read_selected = true;
s->read_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_dev_null::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = no_verify;
}
s->h = get_handle ();
s->write_selected = true;
s->write_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_dev_null::select_except (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = no_verify;
}
s->h = get_handle ();
s->except_selected = true;
s->except_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
static int start_thread_serial (select_record *me, select_stuff *stuff);
struct serialinf
{
cygthread *thread;
2000-02-18 03:38:33 +08:00
BOOL stop_thread_serial;
select_record *start;
};
static int
peek_serial (select_record *s, bool)
2000-02-18 03:38:33 +08:00
{
COMSTAT st;
fhandler_serial *fh = (fhandler_serial *) s->fh;
2000-02-18 03:38:33 +08:00
if (fh->get_readahead_valid () || fh->overlapped_armed < 0)
return s->read_ready = true;
2000-02-18 03:38:33 +08:00
select_printf ("fh->overlapped_armed %d", fh->overlapped_armed);
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;
}
2000-02-18 03:38:33 +08:00
(void) SetCommMask (h, EV_RXCHAR);
if (!fh->overlapped_armed)
{
COMSTAT st;
ResetEvent (fh->io_status.hEvent);
if (!ClearCommError (h, &fh->ev, &st))
2000-02-18 03:38:33 +08:00
{
debug_printf ("ClearCommError");
goto err;
}
else if (st.cbInQue)
return s->read_ready = true;
else if (WaitCommEvent (h, &fh->ev, &fh->io_status))
return s->read_ready = true;
2000-02-18 03:38:33 +08:00
else if (GetLastError () == ERROR_IO_PENDING)
fh->overlapped_armed = 1;
else
{
debug_printf ("WaitCommEvent");
goto err;
}
}
HANDLE w4[2];
DWORD to;
w4[0] = fh->io_status.hEvent;
w4[1] = signal_arrived;
to = 10;
switch (WaitForMultipleObjects (2, w4, FALSE, to))
{
case WAIT_OBJECT_0:
if (!ClearCommError (h, &fh->ev, &st))
* Makefile.in: Add cygheap.o. * child_info.h: Add specific exec class. * cygheap.h: New file. Contains declarations for cygwin heap. * cygheap.cc: New file. Implements cygwin heap functions. * dcrt0.cc (quoted): Simplify due to new method for passing arguments between cygwin programs. (alloc_stack_hard_way): Attempt to handle overlapped stack. (dll_crt0_1): Move child_info processing here. Accomodate new method for passing arguments between cygwin programs. Initialize cygwin heap. Establish __argc and __argv variables. (_dll_crt0): Move most of child_info processing to dll_crt0_1. (cygwin_dll_init): Remove duplication. * dtable.cc (dtable::extend): Allocate dtable using cygwin heap. (dtable::build_fhandler): Ditto for fhandler type being constructed. (dtable::dup_worker): Free new fhandler from cygwin heap on error. (dtable::select_*): Don't assume that this == fdtab. (dtable::linearize_fd_array): Delete. (dtable::delinearize_fd_array): Delete. (dtable::fixup_after_exec): New file. (dtable::vfork_child_dup): Use cygwin heap. (dtable::vfork_parent_restore): Ditto. * dtable.h: Remove obsolete methods. Add new method. * environ.cc (posify): Eliminate already_posix parameter and logic. (envsize): New function. (_addenv): Use envsize. (environ_init): Accept an argument pointing to an existing environment list. If supplied, allocate space for this in the the program's heap. * fhandler.cc (fhandler_base::operator =): Move here from fhandler.h. Use cygwin heap to allocate filenames. (fhandler_base::set_name): Allocate/free names from cygwin heap. (fhandler_base::linearize): Delete. (fhandler_base::de_linearize): Delete. (fhandler_base::operator delete): Free from cygwin heap. (fhandler_base::~fhandler_base): Ditto. * fhandler.h: Accomodate elimination of *linearize and other changes above. * fhandler_console.cc (fhandler_console::fixup_after_exec): Rename from de_linearize. * heap.h: New file. * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Use cygwin heap for name. fhandler_tty::fixup_after_exec): Rename from de_linearize. * fork.cc (fork): Call cygheap_fixup_in_child. * heap.cc: Use declarations in heap.h. * malloc.cc: Sprinkle assertions throughout to catch attempts to free/realloc something from the cygwin heap. * path.cc: Throughout, eliminate use of per-thread cache for cwd. Use cwd_* functions rather than cwd_* variables to access cwd_win32 and cwd_posix. (cwd_win32): New function. (cwd_posix): New function. (cwd_hash): New function. (cwd_fixup_after_exec): New function. * path.h: Accomodate path.cc changes. * pinfo.cc (pinfo_init): Accept a pointer to an environment table. Pass this to environ_init. Eliminate old 'title' tests. * pinfo.h: Accomodate above change in argument. * spawn.cc (struct av): New method for building argv list. (av::unshift): New method. (spawn_guts): Allocate everything that the child process needs in the cygwin heap and pass a pointer to this to the child. Build argv list using new method. Eliminate delinearize stuff. * thread.h: Eliminate _cwd_win32 and _cwd_posix buffers. * winsup.h: Eliminate obsolete functions. Add envsize() declaration.
2000-09-03 12:16:35 +08:00
{
debug_printf ("ClearCommError");
goto err;
}
2000-02-18 03:38:33 +08:00
else if (!st.cbInQue)
Sleep (to);
else
{
return s->read_ready = true;
2000-02-18 03:38:33 +08:00
select_printf ("got something");
}
break;
case WAIT_OBJECT_0 + 1:
select_printf ("interrupt");
set_sig_errno (EINTR);
ready = -1;
break;
case WAIT_TIMEOUT:
break;
default:
debug_printf ("WaitForMultipleObjects");
goto err;
}
out:
2000-02-18 03:38:33 +08:00
return ready;
err:
if (GetLastError () == ERROR_OPERATION_ABORTED)
{
select_printf ("operation aborted");
return ready;
}
__seterrno ();
s->saw_error = true;
2000-02-18 03:38:33 +08:00
select_printf ("error %E");
return -1;
}
static DWORD WINAPI
thread_serial (void *arg)
{
serialinf *si = (serialinf *) arg;
2000-02-18 03:38:33 +08:00
BOOL gotone= FALSE;
for (;;)
{
select_record *s = si->start;
while ((s = s->next))
if (s->startup == start_thread_serial)
{
if (peek_serial (s, true))
gotone = true;
2000-02-18 03:38:33 +08:00
}
if (si->stop_thread_serial)
{
select_printf ("stopping");
break;
}
if (gotone)
break;
}
select_printf ("exiting");
return 0;
}
static int
start_thread_serial (select_record *me, select_stuff *stuff)
{
if (stuff->device_specific[FHDEVN (FH_SERIAL)])
2000-02-18 03:38:33 +08:00
{
me->h = *((serialinf *) stuff->device_specific[FHDEVN (FH_SERIAL)])->thread;
2000-02-18 03:38:33 +08:00
return 1;
}
serialinf *si = new serialinf;
si->start = &stuff->start;
si->stop_thread_serial = FALSE;
si->thread = new cygthread (thread_serial, (LPVOID) si, "select_serial");
me->h = *si->thread;
stuff->device_specific[FHDEVN (FH_SERIAL)] = (void *) si;
2000-02-18 03:38:33 +08:00
return 1;
}
static void
serial_cleanup (select_record *, select_stuff *stuff)
2000-02-18 03:38:33 +08:00
{
serialinf *si = (serialinf *) stuff->device_specific[FHDEVN (FH_SERIAL)];
2000-02-18 03:38:33 +08:00
if (si && si->thread)
{
si->stop_thread_serial = true;
si->thread->detach ();
2000-02-18 03:38:33 +08:00
delete si;
stuff->device_specific[FHDEVN (FH_SERIAL)] = NULL;
2000-02-18 03:38:33 +08:00
}
}
select_record *
fhandler_serial::select_read (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = start_thread_serial;
s->verify = verify_ok;
s->cleanup = serial_cleanup;
}
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
s->peek = peek_serial;
s->read_selected = true;
s->read_ready = false;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_serial::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_ok;
}
s->peek = peek_serial;
2000-02-18 03:38:33 +08:00
s->h = get_handle ();
s->write_selected = true;
s->write_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_serial::select_except (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_ok;
}
s->h = NULL;
s->peek = peek_serial;
s->except_selected = false; // Can't do this
s->except_ready = false;
2000-02-18 03:38:33 +08:00
return s;
}
int
fhandler_base::ready_for_read (int fd, DWORD howlong)
2000-02-18 03:38:33 +08:00
{
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
int avail = 0;
select_record me (this);
me.fd = fd;
while (!avail)
{
(void) select_read (&me);
avail = me.read_ready ?: me.peek (&me, false);
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
if (fd >= 0 && cygheap->fdtab.not_open (fd))
{
set_sig_errno (EBADF);
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
avail = 0;
break;
}
if (howlong != INFINITE)
{
if (!avail)
set_sig_errno (EAGAIN);
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
break;
}
if (WaitForSingleObject (signal_arrived, avail ? 0 : 10) == WAIT_OBJECT_0)
{
set_sig_errno (EINTR);
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
avail = 0;
break;
}
}
if (get_guard () && !avail && me.read_ready)
ReleaseMutex (get_guard ());
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
select_printf ("read_ready %d, avail %d", me.read_ready, avail);
return avail;
2000-02-18 03:38:33 +08:00
}
select_record *
fhandler_base::select_read (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_ok;
}
s->h = get_handle ();
s->read_selected = true;
s->read_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_base::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_ok;
}
s->h = get_handle ();
s->write_selected = true;
s->write_ready = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_base::select_except (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_ok;
}
s->h = NULL;
s->except_selected = true;
s->except_ready = false;
2000-02-18 03:38:33 +08:00
return s;
}
struct socketinf
{
cygthread *thread;
2000-02-18 03:38:33 +08:00
winsock_fd_set readfds, writefds, exceptfds;
SOCKET exitsock;
struct sockaddr_in sin;
select_record *start;
};
static int
peek_socket (select_record *me, bool)
2000-02-18 03:38:33 +08:00
{
winsock_fd_set ws_readfds, ws_writefds, ws_exceptfds;
struct timeval tv = {0, 0};
2000-02-18 03:38:33 +08:00
WINSOCK_FD_ZERO (&ws_readfds);
WINSOCK_FD_ZERO (&ws_writefds);
WINSOCK_FD_ZERO (&ws_exceptfds);
HANDLE h;
set_handle_or_return_if_not_open (h, me);
select_printf ("considering handle %p", h);
if (me->read_selected && !me->read_ready)
2000-02-18 03:38:33 +08:00
{
select_printf ("adding read fd_set %s, fd %d", me->fh->get_name (),
me->fd);
WINSOCK_FD_SET (h, &ws_readfds);
}
if (me->write_selected && !me->write_ready)
2000-02-18 03:38:33 +08:00
{
select_printf ("adding write fd_set %s, fd %d", me->fh->get_name (),
me->fd);
WINSOCK_FD_SET (h, &ws_writefds);
}
if ((me->except_selected || me->except_on_write) && !me->except_ready)
2000-02-18 03:38:33 +08:00
{
select_printf ("adding except fd_set %s, fd %d", me->fh->get_name (),
me->fd);
WINSOCK_FD_SET (h, &ws_exceptfds);
}
int r;
if ((me->read_selected && !me->read_ready)
|| (me->write_selected && !me->write_ready)
|| ((me->except_selected || me->except_on_write) && !me->except_ready))
2000-02-18 03:38:33 +08:00
{
r = WINSOCK_SELECT (0, &ws_readfds, &ws_writefds, &ws_exceptfds, &tv);
select_printf ("WINSOCK_SELECT returned %d", r);
if (r == -1)
{
select_printf ("error %d", WSAGetLastError ());
set_winsock_errno ();
return 0;
}
if (WINSOCK_FD_ISSET (h, &ws_readfds) || (me->read_selected && me->read_ready))
me->read_ready = true;
if (WINSOCK_FD_ISSET (h, &ws_writefds) || (me->write_selected && me->write_ready))
me->write_ready = true;
if (WINSOCK_FD_ISSET (h, &ws_exceptfds) || ((me->except_selected || me->except_on_write) && me->except_ready))
me->except_ready = true;
2000-02-18 03:38:33 +08:00
}
return me->read_ready || me->write_ready || me->except_ready;
2000-02-18 03:38:33 +08:00
}
static int start_thread_socket (select_record *, select_stuff *);
static DWORD WINAPI
thread_socket (void *arg)
{
socketinf *si = (socketinf *) arg;
2000-02-18 03:38:33 +08:00
select_printf ("stuff_start %p", &si->start);
int r = WINSOCK_SELECT (0, &si->readfds, &si->writefds, &si->exceptfds, NULL);
select_printf ("Win32 select returned %d", r);
if (r == -1)
select_printf ("error %d", WSAGetLastError ());
select_record *s = si->start;
while ((s = s->next))
if (s->startup == start_thread_socket)
{
HANDLE h = s->fh->get_handle ();
select_printf ("s %p, testing fd %d (%s)", s, s->fd, s->fh->get_name ());
if (WINSOCK_FD_ISSET (h, &si->readfds))
{
select_printf ("read_ready");
s->read_ready = true;
2000-02-18 03:38:33 +08:00
}
if (WINSOCK_FD_ISSET (h, &si->writefds))
{
select_printf ("write_ready");
s->write_ready = true;
2000-02-18 03:38:33 +08:00
}
if (WINSOCK_FD_ISSET (h, &si->exceptfds))
{
select_printf ("except_ready");
s->except_ready = true;
2000-02-18 03:38:33 +08:00
}
}
if (WINSOCK_FD_ISSET (si->exitsock, &si->readfds))
select_printf ("saw exitsock read");
return 0;
}
extern "C" unsigned long htonl (unsigned long);
static int
start_thread_socket (select_record *me, select_stuff *stuff)
{
socketinf *si;
if ((si = (socketinf *) stuff->device_specific[FHDEVN (FH_SOCKET)]))
2000-02-18 03:38:33 +08:00
{
me->h = *si->thread;
2000-02-18 03:38:33 +08:00
return 1;
}
si = new socketinf;
WINSOCK_FD_ZERO (&si->readfds);
WINSOCK_FD_ZERO (&si->writefds);
WINSOCK_FD_ZERO (&si->exceptfds);
select_record *s = &stuff->start;
while ((s = s->next))
if (s->startup == start_thread_socket)
{
HANDLE h = s->fh->get_handle ();
select_printf ("Handle %p", h);
if (s->read_selected && !s->read_ready)
2000-02-18 03:38:33 +08:00
{
WINSOCK_FD_SET (h, &si->readfds);
select_printf ("Added to readfds");
}
if (s->write_selected && !s->write_ready)
2000-02-18 03:38:33 +08:00
{
WINSOCK_FD_SET (h, &si->writefds);
select_printf ("Added to writefds");
}
if ((s->except_selected || s->except_on_write) && !s->except_ready)
2000-02-18 03:38:33 +08:00
{
WINSOCK_FD_SET (h, &si->exceptfds);
select_printf ("Added to exceptfds");
}
}
if ((si->exitsock = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
set_winsock_errno ();
select_printf ("cannot create socket, %E");
return -1;
}
/* Allow rapid reuse of the port. */
int tmp = 1;
(void) setsockopt (si->exitsock, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
int sin_len = sizeof (si->sin);
2000-02-18 03:38:33 +08:00
memset (&si->sin, 0, sizeof (si->sin));
si->sin.sin_family = AF_INET;
si->sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
if (bind (si->exitsock, (struct sockaddr *) &si->sin, sizeof (si->sin)) < 0)
{
select_printf ("cannot bind socket, %E");
goto err;
}
if (getsockname (si->exitsock, (struct sockaddr *) &si->sin, &sin_len) < 0)
{
select_printf ("getsockname error");
goto err;
}
if (listen (si->exitsock, 1))
{
select_printf ("listen failed, %E");
goto err;
}
select_printf ("exitsock %p", si->exitsock);
WINSOCK_FD_SET ((HANDLE) si->exitsock, &si->readfds);
WINSOCK_FD_SET ((HANDLE) si->exitsock, &si->exceptfds);
stuff->device_specific[FHDEVN (FH_SOCKET)] = (void *) si;
2000-02-18 03:38:33 +08:00
si->start = &stuff->start;
select_printf ("stuff_start %p", &stuff->start);
si->thread = new cygthread (thread_socket, (LPVOID) si, "select_socket");
me->h = *si->thread;
return 1;
2000-02-18 03:38:33 +08:00
err:
set_winsock_errno ();
closesocket (si->exitsock);
return -1;
}
void
socket_cleanup (select_record *, select_stuff *stuff)
2000-02-18 03:38:33 +08:00
{
socketinf *si = (socketinf *) stuff->device_specific[FHDEVN (FH_SOCKET)];
2000-02-18 03:38:33 +08:00
select_printf ("si %p si->thread %p", si, si ? si->thread : NULL);
if (si && si->thread)
{
select_printf ("connection to si->exitsock %p", si->exitsock);
SOCKET s = socket (AF_INET, SOCK_STREAM, 0);
/* Set LINGER with 0 timeout for hard close */
struct linger tmp = {1, 0}; /* On, 0 delay */
(void) setsockopt (s, SOL_SOCKET, SO_LINGER, (char *)&tmp, sizeof (tmp));
(void) setsockopt (si->exitsock, SOL_SOCKET, SO_LINGER, (char *)&tmp, sizeof (tmp));
2000-02-18 03:38:33 +08:00
/* Connecting to si->exitsock will cause any executing select to wake
up. When this happens then the exitsock condition will cause the
thread to terminate. */
if (connect (s, (struct sockaddr *) &si->sin, sizeof (si->sin)) < 0)
{
set_winsock_errno ();
select_printf ("connect failed");
/* FIXME: now what? */
}
shutdown (s, SD_BOTH);
2000-02-18 03:38:33 +08:00
closesocket (s);
/* Wait for thread to go away */
si->thread->detach ();
shutdown (si->exitsock, SD_BOTH);
2000-02-18 03:38:33 +08:00
closesocket (si->exitsock);
stuff->device_specific[FHDEVN (FH_SOCKET)] = NULL;
2000-02-18 03:38:33 +08:00
delete si;
}
select_printf ("returning");
}
select_record *
fhandler_socket::select_read (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = start_thread_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
s->peek = peek_socket;
s->read_ready = saw_shutdown_read ();
s->read_selected = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_socket::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = start_thread_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
s->peek = peek_socket;
s->write_ready = saw_shutdown_write () || is_unconnected ();
s->write_selected = true;
if (is_connect_pending ())
{
s->except_ready = saw_shutdown_write () || saw_shutdown_read ();
s->except_on_write = true;
}
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_socket::select_except (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = start_thread_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
s->peek = peek_socket;
/* FIXME: Is this right? Should these be used as criteria for except? */
s->except_ready = saw_shutdown_write () || saw_shutdown_read ();
s->except_selected = true;
2000-02-18 03:38:33 +08:00
return s;
}
static int
peek_windows (select_record *me, bool)
2000-02-18 03:38:33 +08:00
{
MSG m;
HANDLE h;
set_handle_or_return_if_not_open (h, me);
if (me->read_selected && me->read_ready)
return 1;
2000-02-18 03:38:33 +08:00
if (PeekMessage (&m, (HWND) h, 0, 0, PM_NOREMOVE))
{
me->read_ready = true;
2000-02-18 03:38:33 +08:00
select_printf ("window %d(%p) ready", me->fd, me->fh->get_handle ());
return 1;
}
select_printf ("window %d(%p) not ready", me->fd, me->fh->get_handle ());
return me->write_ready;
}
static int
verify_windows (select_record *me, fd_set *rfds, fd_set *wfds,
fd_set *efds)
{
return peek_windows (me, true);
}
2000-02-18 03:38:33 +08:00
select_record *
fhandler_windows::select_read (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
}
s->verify = verify_windows;
* dtable.cc (dtable::build_fhandler): Issue internal error on unknown device. * fhandler.cc (fhandler_base::close): Show both name and handle in debugging output. * fhandler.h (fhandler_base::get_guard): New virtual method. (fhandler_pipe::get_guard): New method. (fhandler_socket::ready_for_read): Delete declaration. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (struct select_record::peek): Declare new method. * select.cc (MAKEready): Delete. (peek_pipe): Use get_guard method to retrieve potential guard mutex handle. (fhandler_base::ready_for_read): Rewrite as generic ready-for-read handler. Should only be called for "slow" devices. (fhandler_socket::ready_for_read): Delete definition. (fhandler_pipe::ready_for_read): Ditto. (fhandler_serial::ready_for_read): Ditto. (fhandler_console::ready_for_read): Ditto. (fhandler_tty_common::ready_for_read): Ditto. (fhandler_windows::ready_for_read): Ditto. (fhandler_pipe::select_read): Fill in new peek record in select_record structure. (fhandler_console::select_read): Ditto. (fhandler_tty_common::select_read): Ditto. (fhandler_serial::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_socket::select_read): Ditto. (fhandler_tty_slave::ready_for_read): Check for tty not open. Set errnos appropriately. * syscalls.cc (_read): Allow ready_for_read to set errno. * pinfo.cc (pinfo::init): Return spawn/NO_WAIT process as valid if it is initializing. * sigproc.cc (getsem): Adjust wait for process to initialize downward to avoid huge waits.
2001-11-02 05:15:53 +08:00
s->peek = peek_windows;
s->read_selected = true;
s->read_ready = false;
2000-02-18 03:38:33 +08:00
s->h = get_handle ();
s->windows_handle = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_windows::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_ok;
}
s->peek = peek_windows;
2000-02-18 03:38:33 +08:00
s->h = get_handle ();
s->write_selected = true;
s->write_ready = true;
s->windows_handle = true;
2000-02-18 03:38:33 +08:00
return s;
}
select_record *
fhandler_windows::select_except (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = verify_ok;
}
s->peek = peek_windows;
2000-02-18 03:38:33 +08:00
s->h = get_handle ();
s->except_selected = true;
s->except_ready = true;
s->windows_handle = true;
2000-02-18 03:38:33 +08:00
return s;
}