in file_io/win32/readwrite.c [32:148]
static apr_status_t read_with_timeout(apr_file_t *file, void *buf, apr_size_t len_in, apr_size_t *nbytes)
{
apr_status_t rv;
DWORD len = (DWORD)len_in;
DWORD bytesread = 0;
/* Handle the zero timeout non-blocking case */
if (file->timeout == 0) {
/* Peek at the pipe. If there is no data available, return APR_EAGAIN.
* If data is available, go ahead and read it.
*/
if (file->ftype == APR_FILETYPE_PIPE) {
DWORD bytes;
if (!PeekNamedPipe(file->filehand, NULL, 0, NULL, &bytes, NULL)) {
rv = apr_get_os_error();
if (rv == APR_FROM_OS_ERROR(ERROR_BROKEN_PIPE)) {
rv = APR_EOF;
}
*nbytes = 0;
return rv;
}
else {
if (bytes == 0) {
*nbytes = 0;
return APR_EAGAIN;
}
if (len > bytes) {
len = bytes;
}
}
}
else {
/* ToDo: Handle zero timeout non-blocking file i/o
* This is not needed until an APR application needs to
* timeout file i/o (which means setting file i/o non-blocking)
*/
}
}
if (file->pOverlapped && file->ftype == APR_FILETYPE_FILE) {
file->pOverlapped->Offset = (DWORD)file->filePtr;
file->pOverlapped->OffsetHigh = (DWORD)(file->filePtr >> 32);
}
if (ReadFile(file->filehand, buf, len,
&bytesread, file->pOverlapped)) {
rv = APR_SUCCESS;
}
else {
rv = apr_get_os_error();
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) {
DWORD res;
/* It seems that ReadFile() return ERROR_IO_PENDING even
* when I/O operation completed syncronously.
* Use fast macro to check that overlapped I/O already
* completed to avoid kernel call.
*/
if (HasOverlappedIoCompleted(file->pOverlapped)) {
res = WAIT_OBJECT_0;
}
else {
/* Wait for the pending i/o, timeout converted from us to ms
* Note that we loop if someone gives up the event.
*
* NOTE: We do not handle WAIT_ABANDONED here because they
* can be returned only when waiting for mutex.
*/
res = apr_wait_for_single_object(file->pOverlapped->hEvent,
file->timeout);
}
/* There is one case that represents entirely
* successful operations, otherwise we will cancel
* the operation in progress.
*/
if (res != WAIT_OBJECT_0) {
CancelIoEx(file->filehand, file->pOverlapped);
}
/* Ignore any failures above. Attempt to complete
* the overlapped operation and use only _its_ result.
* For example, CancelIo or WaitForSingleObject can
* fail if the handle is closed, yet the read may have
* completed before we attempted to CancelIo...
*/
if (GetOverlappedResult(file->filehand, file->pOverlapped,
&bytesread, TRUE)) {
rv = APR_SUCCESS;
}
else {
rv = apr_get_os_error();
if (((rv == APR_FROM_OS_ERROR(ERROR_IO_INCOMPLETE))
|| (rv == APR_FROM_OS_ERROR(ERROR_OPERATION_ABORTED)))
&& (res == WAIT_TIMEOUT))
rv = APR_TIMEUP;
}
}
if (rv == APR_FROM_OS_ERROR(ERROR_BROKEN_PIPE)) {
/* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */
rv = APR_EOF;
} else if (rv == APR_FROM_OS_ERROR(ERROR_HANDLE_EOF)) {
/* Did we hit EOF reading from the handle? */
rv = APR_EOF;
}
}
/* OK and 0 bytes read ==> end of file */
if (rv == APR_SUCCESS && bytesread == 0)
rv = APR_EOF;
if (rv == APR_SUCCESS && file->pOverlapped && file->ftype == APR_FILETYPE_FILE) {
file->filePtr += bytesread;
}
*nbytes = bytesread;
return rv;
}