/*++ 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); }