From e13955708b60fd133178d56c545b722bc3a377df Mon Sep 17 00:00:00 2001 From: Ivan Zhakov Date: Sun, 26 May 2019 08:58:43 +0000 Subject: win32: Correctly cancel write operation on timeout. * file_io/win32/readwrite.c (apr_file_write): Get operation result after we cancelled I/O operation: operation may be finished after we got timeout, but before CancelIoEx() call. git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1860042 13f79535-47bb-0310-9956-ffa450edef68 --- file_io/win32/readwrite.c | 50 +++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/file_io/win32/readwrite.c b/file_io/win32/readwrite.c index ef3f7ad85..bf7cbfb30 100644 --- a/file_io/win32/readwrite.c +++ b/file_io/win32/readwrite.c @@ -490,10 +490,10 @@ APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, a (*nbytes) = 0; rv = apr_get_os_error(); - /* XXX: This must be corrected, per the apr_file_read logic!!! */ if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { DWORD timeout_ms; + DWORD res; if (thefile->timeout == 0) { timeout_ms = 0; @@ -505,26 +505,38 @@ APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, a timeout_ms = (DWORD)(thefile->timeout / 1000); } - rv = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms); - switch (rv) { - case WAIT_OBJECT_0: - GetOverlappedResult(thefile->filehand, thefile->pOverlapped, - &bwrote, TRUE); - *nbytes = bwrote; - rv = APR_SUCCESS; - break; - case WAIT_TIMEOUT: - rv = (timeout_ms == 0) ? APR_EAGAIN : APR_TIMEUP; - break; - case WAIT_FAILED: - rv = apr_get_os_error(); - break; - default: - break; - } - if (rv != APR_SUCCESS) { + res = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms); + + /* There is one case that represents entirely + * successful operations, otherwise we will cancel + * the operation in progress. + */ + if (res != WAIT_OBJECT_0) { CancelIoEx(thefile->filehand, thefile->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(thefile->filehand, thefile->pOverlapped, + &bwrote, TRUE)) { + *nbytes = bwrote; + 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_TIMEUP && timeout_ms == 0) { + rv = APR_EAGAIN; + } + } } } if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) { -- cgit v1.2.1