|
Packit |
33f14e |
/* Emulation for select(2)
|
|
Packit |
33f14e |
Contributed by Paolo Bonzini.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
Copyright 2008-2017 Free Software Foundation, Inc.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
This file is part of gnulib.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
33f14e |
it under the terms of the GNU General Public License as published by
|
|
Packit |
33f14e |
the Free Software Foundation; either version 3, or (at your option)
|
|
Packit |
33f14e |
any later version.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
This program is distributed in the hope that it will be useful,
|
|
Packit |
33f14e |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
33f14e |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
33f14e |
GNU General Public License for more details.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
You should have received a copy of the GNU General Public License along
|
|
Packit |
33f14e |
with this program; if not, see <http://www.gnu.org/licenses/>. */
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#include <config.h>
|
|
Packit |
33f14e |
#include <alloca.h>
|
|
Packit |
33f14e |
#include <assert.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
|
|
Packit |
33f14e |
/* Native Windows. */
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#include <sys/types.h>
|
|
Packit |
33f14e |
#include <errno.h>
|
|
Packit |
33f14e |
#include <limits.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#include <winsock2.h>
|
|
Packit |
33f14e |
#include <windows.h>
|
|
Packit |
33f14e |
#include <io.h>
|
|
Packit |
33f14e |
#include <stdio.h>
|
|
Packit |
33f14e |
#include <conio.h>
|
|
Packit |
33f14e |
#include <time.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Get the overridden 'struct timeval'. */
|
|
Packit |
33f14e |
#include <sys/time.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#if GNULIB_MSVC_NOTHROW
|
|
Packit |
33f14e |
# include "msvc-nothrow.h"
|
|
Packit |
33f14e |
#else
|
|
Packit |
33f14e |
# include <io.h>
|
|
Packit |
33f14e |
#endif
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#undef select
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
struct bitset {
|
|
Packit |
33f14e |
unsigned char in[FD_SETSIZE / CHAR_BIT];
|
|
Packit |
33f14e |
unsigned char out[FD_SETSIZE / CHAR_BIT];
|
|
Packit |
33f14e |
};
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Declare data structures for ntdll functions. */
|
|
Packit |
33f14e |
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
|
|
Packit |
33f14e |
ULONG NamedPipeType;
|
|
Packit |
33f14e |
ULONG NamedPipeConfiguration;
|
|
Packit |
33f14e |
ULONG MaximumInstances;
|
|
Packit |
33f14e |
ULONG CurrentInstances;
|
|
Packit |
33f14e |
ULONG InboundQuota;
|
|
Packit |
33f14e |
ULONG ReadDataAvailable;
|
|
Packit |
33f14e |
ULONG OutboundQuota;
|
|
Packit |
33f14e |
ULONG WriteQuotaAvailable;
|
|
Packit |
33f14e |
ULONG NamedPipeState;
|
|
Packit |
33f14e |
ULONG NamedPipeEnd;
|
|
Packit |
33f14e |
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
typedef struct _IO_STATUS_BLOCK
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
union {
|
|
Packit |
33f14e |
DWORD Status;
|
|
Packit |
33f14e |
PVOID Pointer;
|
|
Packit |
33f14e |
} u;
|
|
Packit |
33f14e |
ULONG_PTR Information;
|
|
Packit |
33f14e |
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
typedef enum _FILE_INFORMATION_CLASS {
|
|
Packit |
33f14e |
FilePipeLocalInformation = 24
|
|
Packit |
33f14e |
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
typedef DWORD (WINAPI *PNtQueryInformationFile)
|
|
Packit |
33f14e |
(HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#ifndef PIPE_BUF
|
|
Packit |
33f14e |
#define PIPE_BUF 512
|
|
Packit |
33f14e |
#endif
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
static BOOL IsConsoleHandle (HANDLE h)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
DWORD mode;
|
|
Packit |
33f14e |
return GetConsoleMode (h, &mode) != 0;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
static BOOL
|
|
Packit |
33f14e |
IsSocketHandle (HANDLE h)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
WSANETWORKEVENTS ev;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (IsConsoleHandle (h))
|
|
Packit |
33f14e |
return FALSE;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Under Wine, it seems that getsockopt returns 0 for pipes too.
|
|
Packit |
33f14e |
WSAEnumNetworkEvents instead distinguishes the two correctly. */
|
|
Packit |
33f14e |
ev.lNetworkEvents = 0xDEADBEEF;
|
|
Packit |
33f14e |
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev;;
|
|
Packit |
33f14e |
return ev.lNetworkEvents != 0xDEADBEEF;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Compute output fd_sets for libc descriptor FD (whose Windows handle is
|
|
Packit |
33f14e |
H). */
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
static int
|
|
Packit |
33f14e |
windows_poll_handle (HANDLE h, int fd,
|
|
Packit |
33f14e |
struct bitset *rbits,
|
|
Packit |
33f14e |
struct bitset *wbits,
|
|
Packit |
33f14e |
struct bitset *xbits)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
BOOL read, write, except;
|
|
Packit |
33f14e |
int i, ret;
|
|
Packit |
33f14e |
INPUT_RECORD *irbuffer;
|
|
Packit |
33f14e |
DWORD avail, nbuffer;
|
|
Packit |
33f14e |
BOOL bRet;
|
|
Packit |
33f14e |
IO_STATUS_BLOCK iosb;
|
|
Packit |
33f14e |
FILE_PIPE_LOCAL_INFORMATION fpli;
|
|
Packit |
33f14e |
static PNtQueryInformationFile NtQueryInformationFile;
|
|
Packit |
33f14e |
static BOOL once_only;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
read = write = except = FALSE;
|
|
Packit |
33f14e |
switch (GetFileType (h))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
case FILE_TYPE_DISK:
|
|
Packit |
33f14e |
read = TRUE;
|
|
Packit |
33f14e |
write = TRUE;
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
case FILE_TYPE_PIPE:
|
|
Packit |
33f14e |
if (!once_only)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
NtQueryInformationFile = (PNtQueryInformationFile)
|
|
Packit |
33f14e |
GetProcAddress (GetModuleHandle ("ntdll.dll"),
|
|
Packit |
33f14e |
"NtQueryInformationFile");
|
|
Packit |
33f14e |
once_only = TRUE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
if (avail)
|
|
Packit |
33f14e |
read = TRUE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else if (GetLastError () == ERROR_BROKEN_PIPE)
|
|
Packit |
33f14e |
;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* It was the write-end of the pipe. Check if it is writable.
|
|
Packit |
33f14e |
If NtQueryInformationFile fails, optimistically assume the pipe is
|
|
Packit |
33f14e |
writable. This could happen on Windows 9x, where
|
|
Packit |
33f14e |
NtQueryInformationFile is not available, or if we inherit a pipe
|
|
Packit |
33f14e |
that doesn't permit FILE_READ_ATTRIBUTES access on the write end
|
|
Packit |
33f14e |
(I think this should not happen since Windows XP SP2; WINE seems
|
|
Packit |
33f14e |
fine too). Otherwise, ensure that enough space is available for
|
|
Packit |
33f14e |
atomic writes. */
|
|
Packit |
33f14e |
memset (&iosb, 0, sizeof (iosb));
|
|
Packit |
33f14e |
memset (&fpli, 0, sizeof (fpli));
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (!NtQueryInformationFile
|
|
Packit |
33f14e |
|| NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
|
|
Packit |
33f14e |
FilePipeLocalInformation)
|
|
Packit |
33f14e |
|| fpli.WriteQuotaAvailable >= PIPE_BUF
|
|
Packit |
33f14e |
|| (fpli.OutboundQuota < PIPE_BUF &&
|
|
Packit |
33f14e |
fpli.WriteQuotaAvailable == fpli.OutboundQuota))
|
|
Packit |
33f14e |
write = TRUE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
case FILE_TYPE_CHAR:
|
|
Packit |
33f14e |
write = TRUE;
|
|
Packit |
33f14e |
if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
ret = WaitForSingleObject (h, 0);
|
|
Packit |
33f14e |
if (ret == WAIT_OBJECT_0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
if (!IsConsoleHandle (h))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
read = TRUE;
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
nbuffer = avail = 0;
|
|
Packit |
33f14e |
bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Screen buffers handles are filtered earlier. */
|
|
Packit |
33f14e |
assert (bRet);
|
|
Packit |
33f14e |
if (nbuffer == 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
except = TRUE;
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
|
|
Packit |
33f14e |
bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
|
|
Packit |
33f14e |
if (!bRet || avail == 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
except = TRUE;
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
for (i = 0; i < avail; i++)
|
|
Packit |
33f14e |
if (irbuffer[i].EventType == KEY_EVENT)
|
|
Packit |
33f14e |
read = TRUE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
default:
|
|
Packit |
33f14e |
ret = WaitForSingleObject (h, 0);
|
|
Packit |
33f14e |
write = TRUE;
|
|
Packit |
33f14e |
if (ret == WAIT_OBJECT_0)
|
|
Packit |
33f14e |
read = TRUE;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
ret = 0;
|
|
Packit |
33f14e |
if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
|
|
Packit |
33f14e |
ret++;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
|
|
Packit |
33f14e |
ret++;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
|
|
Packit |
33f14e |
ret++;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
return ret;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
int
|
|
Packit |
33f14e |
rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
|
|
Packit |
33f14e |
struct timeval *timeout)
|
|
Packit |
33f14e |
#undef timeval
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
static struct timeval tv0;
|
|
Packit |
33f14e |
static HANDLE hEvent;
|
|
Packit |
33f14e |
HANDLE h, handle_array[FD_SETSIZE + 2];
|
|
Packit |
33f14e |
fd_set handle_rfds, handle_wfds, handle_xfds;
|
|
Packit |
33f14e |
struct bitset rbits, wbits, xbits;
|
|
Packit |
33f14e |
unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
|
|
Packit |
33f14e |
DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
|
|
Packit |
33f14e |
MSG msg;
|
|
Packit |
33f14e |
int i, fd, rc;
|
|
Packit |
33f14e |
clock_t tend;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (nfds > FD_SETSIZE)
|
|
Packit |
33f14e |
nfds = FD_SETSIZE;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (!timeout)
|
|
Packit |
33f14e |
wait_timeout = INFINITE;
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* select is also used as a portable usleep. */
|
|
Packit |
33f14e |
if (!rfds && !wfds && !xfds)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
Sleep (wait_timeout);
|
|
Packit |
33f14e |
return 0;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (!hEvent)
|
|
Packit |
33f14e |
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
handle_array[0] = hEvent;
|
|
Packit |
33f14e |
nhandles = 1;
|
|
Packit |
33f14e |
nsock = 0;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Copy descriptors to bitsets. At the same time, eliminate
|
|
Packit |
33f14e |
bits in the "wrong" direction for console input buffers
|
|
Packit |
33f14e |
and screen buffers, because screen buffers are waitable
|
|
Packit |
33f14e |
and they will block until a character is available. */
|
|
Packit |
33f14e |
memset (&rbits, 0, sizeof (rbits));
|
|
Packit |
33f14e |
memset (&wbits, 0, sizeof (wbits));
|
|
Packit |
33f14e |
memset (&xbits, 0, sizeof (xbits));
|
|
Packit |
33f14e |
memset (anyfds_in, 0, sizeof (anyfds_in));
|
|
Packit |
33f14e |
if (rfds)
|
|
Packit |
33f14e |
for (i = 0; i < rfds->fd_count; i++)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
fd = rfds->fd_array[i];
|
|
Packit |
33f14e |
h = (HANDLE) _get_osfhandle (fd);
|
|
Packit |
33f14e |
if (IsConsoleHandle (h)
|
|
Packit |
33f14e |
&& !GetNumberOfConsoleInputEvents (h, &nbuffer))
|
|
Packit |
33f14e |
continue;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
|
|
Packit |
33f14e |
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
rfds = (fd_set *) alloca (sizeof (fd_set));
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (wfds)
|
|
Packit |
33f14e |
for (i = 0; i < wfds->fd_count; i++)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
fd = wfds->fd_array[i];
|
|
Packit |
33f14e |
h = (HANDLE) _get_osfhandle (fd);
|
|
Packit |
33f14e |
if (IsConsoleHandle (h)
|
|
Packit |
33f14e |
&& GetNumberOfConsoleInputEvents (h, &nbuffer))
|
|
Packit |
33f14e |
continue;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
|
|
Packit |
33f14e |
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
wfds = (fd_set *) alloca (sizeof (fd_set));
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (xfds)
|
|
Packit |
33f14e |
for (i = 0; i < xfds->fd_count; i++)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
fd = xfds->fd_array[i];
|
|
Packit |
33f14e |
xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
|
|
Packit |
33f14e |
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
xfds = (fd_set *) alloca (sizeof (fd_set));
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Zero all the fd_sets, including the application's. */
|
|
Packit |
33f14e |
FD_ZERO (rfds);
|
|
Packit |
33f14e |
FD_ZERO (wfds);
|
|
Packit |
33f14e |
FD_ZERO (xfds);
|
|
Packit |
33f14e |
FD_ZERO (&handle_rfds);
|
|
Packit |
33f14e |
FD_ZERO (&handle_wfds);
|
|
Packit |
33f14e |
FD_ZERO (&handle_xfds);
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Classify handles. Create fd sets for sockets, poll the others. */
|
|
Packit |
33f14e |
for (i = 0; i < nfds; i++)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
|
|
Packit |
33f14e |
continue;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
h = (HANDLE) _get_osfhandle (i);
|
|
Packit |
33f14e |
if (!h)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
errno = EBADF;
|
|
Packit |
33f14e |
return -1;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (IsSocketHandle (h))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
int requested = FD_CLOSE;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* See above; socket handles are mapped onto select, but we
|
|
Packit |
33f14e |
need to map descriptors to handles. */
|
|
Packit |
33f14e |
if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
requested |= FD_READ | FD_ACCEPT;
|
|
Packit |
33f14e |
FD_SET ((SOCKET) h, rfds);
|
|
Packit |
33f14e |
FD_SET ((SOCKET) h, &handle_rfds);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
requested |= FD_WRITE | FD_CONNECT;
|
|
Packit |
33f14e |
FD_SET ((SOCKET) h, wfds);
|
|
Packit |
33f14e |
FD_SET ((SOCKET) h, &handle_wfds);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
requested |= FD_OOB;
|
|
Packit |
33f14e |
FD_SET ((SOCKET) h, xfds);
|
|
Packit |
33f14e |
FD_SET ((SOCKET) h, &handle_xfds);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
WSAEventSelect ((SOCKET) h, hEvent, requested);
|
|
Packit |
33f14e |
nsock++;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
handle_array[nhandles++] = h;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Poll now. If we get an event, do not wait below. */
|
|
Packit |
33f14e |
if (wait_timeout != 0
|
|
Packit |
33f14e |
&& windows_poll_handle (h, i, &rbits, &wbits, &xbits))
|
|
Packit |
33f14e |
wait_timeout = 0;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Place a sentinel at the end of the array. */
|
|
Packit |
33f14e |
handle_array[nhandles] = NULL;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* When will the waiting period expire? */
|
|
Packit |
33f14e |
if (wait_timeout != INFINITE)
|
|
Packit |
33f14e |
tend = clock () + wait_timeout;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
restart:
|
|
Packit |
33f14e |
if (wait_timeout == 0 || nsock == 0)
|
|
Packit |
33f14e |
rc = 0;
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* See if we need to wait in the loop below. If any select is ready,
|
|
Packit |
33f14e |
do MsgWaitForMultipleObjects anyway to dispatch messages, but
|
|
Packit |
33f14e |
no need to call select again. */
|
|
Packit |
33f14e |
rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
|
|
Packit |
33f14e |
if (rc == 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Restore the fd_sets for the other select we do below. */
|
|
Packit |
33f14e |
memcpy (&handle_rfds, rfds, sizeof (fd_set));
|
|
Packit |
33f14e |
memcpy (&handle_wfds, wfds, sizeof (fd_set));
|
|
Packit |
33f14e |
memcpy (&handle_xfds, xfds, sizeof (fd_set));
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
wait_timeout = 0;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* How much is left to wait? */
|
|
Packit |
33f14e |
if (wait_timeout != INFINITE)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
clock_t tnow = clock ();
|
|
Packit |
33f14e |
if (tend >= tnow)
|
|
Packit |
33f14e |
wait_timeout = tend - tnow;
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
wait_timeout = 0;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
for (;;)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
|
|
Packit |
33f14e |
wait_timeout, QS_ALLINPUT);
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (ret == WAIT_OBJECT_0 + nhandles)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* new input of some other kind */
|
|
Packit |
33f14e |
BOOL bRet;
|
|
Packit |
33f14e |
while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
TranslateMessage (&msg;;
|
|
Packit |
33f14e |
DispatchMessage (&msg;;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* If we haven't done it yet, check the status of the sockets. */
|
|
Packit |
33f14e |
if (rc == 0 && nsock > 0)
|
|
Packit |
33f14e |
rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (nhandles > 1)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Count results that are not counted in the return value of select. */
|
|
Packit |
33f14e |
nhandles = 1;
|
|
Packit |
33f14e |
for (i = 0; i < nfds; i++)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
|
|
Packit |
33f14e |
continue;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
h = (HANDLE) _get_osfhandle (i);
|
|
Packit |
33f14e |
if (h == handle_array[nhandles])
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Not a socket. */
|
|
Packit |
33f14e |
nhandles++;
|
|
Packit |
33f14e |
windows_poll_handle (h, i, &rbits, &wbits, &xbits);
|
|
Packit |
33f14e |
if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
|
|
Packit |
33f14e |
|| wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
|
|
Packit |
33f14e |
|| xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
|
|
Packit |
33f14e |
rc++;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (rc == 0
|
|
Packit |
33f14e |
&& (wait_timeout == INFINITE
|
|
Packit |
33f14e |
/* If NHANDLES > 1, but no bits are set, it means we've
|
|
Packit |
33f14e |
been told incorrectly that some handle was signaled.
|
|
Packit |
33f14e |
This happens with anonymous pipes, which always cause
|
|
Packit |
33f14e |
MsgWaitForMultipleObjects to exit immediately, but no
|
|
Packit |
33f14e |
data is found ready to be read by windows_poll_handle.
|
|
Packit |
33f14e |
To avoid a total failure (whereby we return zero and
|
|
Packit |
33f14e |
don't wait at all), let's poll in a more busy loop. */
|
|
Packit |
33f14e |
|| (wait_timeout != 0 && nhandles > 1)))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Sleep 1 millisecond to avoid busy wait and retry with the
|
|
Packit |
33f14e |
original fd_sets. */
|
|
Packit |
33f14e |
memcpy (&handle_rfds, rfds, sizeof (fd_set));
|
|
Packit |
33f14e |
memcpy (&handle_wfds, wfds, sizeof (fd_set));
|
|
Packit |
33f14e |
memcpy (&handle_xfds, xfds, sizeof (fd_set));
|
|
Packit |
33f14e |
SleepEx (1, TRUE);
|
|
Packit |
33f14e |
goto restart;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
if (timeout && wait_timeout == 0 && rc == 0)
|
|
Packit |
33f14e |
timeout->tv_sec = timeout->tv_usec = 0;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Now fill in the results. */
|
|
Packit |
33f14e |
FD_ZERO (rfds);
|
|
Packit |
33f14e |
FD_ZERO (wfds);
|
|
Packit |
33f14e |
FD_ZERO (xfds);
|
|
Packit |
33f14e |
nhandles = 1;
|
|
Packit |
33f14e |
for (i = 0; i < nfds; i++)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
|
|
Packit |
33f14e |
continue;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
h = (HANDLE) _get_osfhandle (i);
|
|
Packit |
33f14e |
if (h != handle_array[nhandles])
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Perform handle->descriptor mapping. */
|
|
Packit |
33f14e |
WSAEventSelect ((SOCKET) h, NULL, 0);
|
|
Packit |
33f14e |
if (FD_ISSET (h, &handle_rfds))
|
|
Packit |
33f14e |
FD_SET (i, rfds);
|
|
Packit |
33f14e |
if (FD_ISSET (h, &handle_wfds))
|
|
Packit |
33f14e |
FD_SET (i, wfds);
|
|
Packit |
33f14e |
if (FD_ISSET (h, &handle_xfds))
|
|
Packit |
33f14e |
FD_SET (i, xfds);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Not a socket. */
|
|
Packit |
33f14e |
nhandles++;
|
|
Packit |
33f14e |
if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
|
|
Packit |
33f14e |
FD_SET (i, rfds);
|
|
Packit |
33f14e |
if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
|
|
Packit |
33f14e |
FD_SET (i, wfds);
|
|
Packit |
33f14e |
if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
|
|
Packit |
33f14e |
FD_SET (i, xfds);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
return rc;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#else /* ! Native Windows. */
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#include <sys/select.h>
|
|
Packit |
33f14e |
#include <stddef.h> /* NULL */
|
|
Packit |
33f14e |
#include <errno.h>
|
|
Packit |
33f14e |
#include <unistd.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#undef select
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
int
|
|
Packit |
33f14e |
rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
|
|
Packit |
33f14e |
struct timeval *timeout)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
int i;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* FreeBSD 8.2 has a bug: it does not always detect invalid fds. */
|
|
Packit |
33f14e |
if (nfds < 0 || nfds > FD_SETSIZE)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
errno = EINVAL;
|
|
Packit |
33f14e |
return -1;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
for (i = 0; i < nfds; i++)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
if (((rfds && FD_ISSET (i, rfds))
|
|
Packit |
33f14e |
|| (wfds && FD_ISSET (i, wfds))
|
|
Packit |
33f14e |
|| (xfds && FD_ISSET (i, xfds)))
|
|
Packit |
33f14e |
&& dup2 (i, i) != i)
|
|
Packit |
33f14e |
return -1;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Interix 3.5 has a bug: it does not support nfds == 0. */
|
|
Packit |
33f14e |
if (nfds == 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
nfds = 1;
|
|
Packit |
33f14e |
rfds = NULL;
|
|
Packit |
33f14e |
wfds = NULL;
|
|
Packit |
33f14e |
xfds = NULL;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
return select (nfds, rfds, wfds, xfds, timeout);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#endif
|