summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Zhakov <ivan@apache.org>2019-05-26 08:58:43 +0000
committerIvan Zhakov <ivan@apache.org>2019-05-26 08:58:43 +0000
commite13955708b60fd133178d56c545b722bc3a377df (patch)
tree56eacfc7800c7a99d5844ea2d770dcd156dd0be7
parent12e32ba4bcafcabce18c53ec63979cb7335b1bb9 (diff)
downloadapr-e13955708b60fd133178d56c545b722bc3a377df.tar.gz
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
-rw-r--r--file_io/win32/readwrite.c50
1 files 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) {