160 lines
4 KiB
C
160 lines
4 KiB
C
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
s_poll.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the STREAMS api, poll()
|
|
|
|
Author:
|
|
|
|
Eric Chin (ericc) July 26, 1991
|
|
|
|
Revision History:
|
|
|
|
Sam Patton (sampa) August 13, 1991
|
|
changed errno to {get|set}lasterror
|
|
|
|
--*/
|
|
#include "common.h"
|
|
|
|
|
|
/*
|
|
* BUGBUG
|
|
* Confirm that the following is a sane number.
|
|
*/
|
|
#define MAX_FDS NPOLLFILE /* max handles to poll */
|
|
|
|
|
|
|
|
|
|
int
|
|
poll(
|
|
IN OUT struct pollfd *fds OPTIONAL,
|
|
IN unsigned int nfds,
|
|
IN int timeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure is called to poll a set of stream descriptors.
|
|
|
|
Arguments:
|
|
|
|
fds - pointer to a array of poll structures
|
|
nfds - number of poll structures pointed to by fds
|
|
timeout - 0, INFTIM (-1), or timeout in milliseconds.
|
|
|
|
Return Value:
|
|
|
|
no of stream descriptors selected, or -1 if failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
char *chunk;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
int chunksz, selected;
|
|
struct pollfd *overlay;
|
|
HANDLE hijack = INVALID_HANDLE_VALUE;
|
|
|
|
if (!fds || (nfds <= 0) || (nfds > MAX_FDS)) {
|
|
SetLastError(EINVAL);
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* hijack a handle to the Stream Head driver.
|
|
*
|
|
* BUGBUG:
|
|
* In Unix, the user can set pollfd.fd to less than 0 to indicate that
|
|
* the entry should be ignored. On NT, that isn't possible:
|
|
* INVALID_HANDLE_VALUE must be used.
|
|
*/
|
|
for (overlay = fds; overlay < &fds[nfds]; overlay++) {
|
|
if (overlay->fd != INVALID_HANDLE_VALUE) {
|
|
hijack = overlay->fd;
|
|
break;
|
|
}
|
|
}
|
|
if (hijack == INVALID_HANDLE_VALUE) {
|
|
SetLastError(EINVAL);
|
|
return(-1);
|
|
}
|
|
|
|
chunksz = sizeof(nfds) + nfds * sizeof(*fds) + sizeof(timeout);
|
|
|
|
if (!(chunk = (char *) LocalAlloc(LMEM_FIXED, chunksz))) {
|
|
SetLastError(EAGAIN);
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* marshall the arguments into one contiguous chunk, laid out as:
|
|
*
|
|
* nfds (required)
|
|
* timeout (required)
|
|
* struct fds[nfds] (required)
|
|
*/
|
|
* ((size_t *) chunk) = nfds;
|
|
* (int *) (chunk + sizeof(nfds)) = timeout;
|
|
overlay = (struct pollfd *) (chunk +
|
|
sizeof(nfds) + sizeof(timeout));
|
|
|
|
memcpy(overlay, fds, nfds * sizeof(*fds));
|
|
|
|
status = NtDeviceIoControlFile(
|
|
hijack,
|
|
NULL, // Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&iosb, // IoStatusBlock
|
|
IOCTL_STREAMS_POLL, // IoControlCode
|
|
(PVOID) chunk, // InputBuffer
|
|
chunksz, // InputBufferSize
|
|
(PVOID) chunk, // OutputBuffer
|
|
chunksz); // OutputBufferSize
|
|
|
|
if (status == STATUS_PENDING) {
|
|
status =
|
|
NtWaitForSingleObject(
|
|
hijack,
|
|
TRUE,
|
|
NULL);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
SetLastError(MapNtToPosixStatus(status));
|
|
LocalFree((HANDLE) chunk);
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* the Stream Head Driver marshalled the return parameters into one
|
|
* contiguous chunk, laid out as:
|
|
*
|
|
* return value (required)
|
|
* errno (required)
|
|
* struct fds[nfds] (required)
|
|
*/
|
|
if ((selected = * (int *) chunk) == -1) {
|
|
SetLastError(* (int *) (chunk + sizeof(nfds)));
|
|
LocalFree((HANDLE) chunk);
|
|
return(selected);
|
|
}
|
|
overlay = (struct pollfd *) (chunk + sizeof(nfds) + sizeof(timeout));
|
|
|
|
while (nfds--) {
|
|
fds[nfds].revents = overlay[nfds].revents;
|
|
}
|
|
LocalFree((HANDLE) chunk);
|
|
return(selected);
|
|
}
|