From 6cb23362174cc43ba1d34b7d545fbc143ff7b2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Feb 2020 11:49:37 +0100 Subject: [PATCH] ntdll: Reorder code to make the select logic clearer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wait_select_reply call may return STATUS_USER_APC/STATUS_KERNEL_APC, depending on which APC is about to be returned but the apc call will always be APC_NONE right after the wait. It needs an additional select request to actually return the call. Signed-off-by: RĂ©mi Bernon Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/ntdll/server.c | 17 ++++++++++------- dlls/ntdll/sync.c | 10 ++++++---- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 73f4d86cf4d..18ee41790f3 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -607,7 +607,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT memset( &result, 0, sizeof(result) ); - for (;;) + do { SERVER_START_REQ( select ) { @@ -623,9 +623,13 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT call = reply->call; } SERVER_END_REQ; - if (ret == STATUS_PENDING) ret = wait_select_reply( &cookie ); - if (ret != STATUS_USER_APC && ret != STATUS_KERNEL_APC) break; - if (invoke_apc( &call, &result )) + + /* don't signal multiple times */ + if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) + size = offsetof( select_op_t, signal_and_wait.signal ); + + if ((ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC) && + invoke_apc( &call, &result )) { /* if we ran a user apc we have to check once more if additional apcs are queued, * but we don't want to wait */ @@ -634,10 +638,9 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT size = 0; } - /* don't signal multiple times */ - if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) - size = offsetof( select_op_t, signal_and_wait.signal ); + if (ret == STATUS_PENDING) ret = wait_select_reply( &cookie ); } + while (ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC); if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC; diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index d09b90a9273..3b8b4f4eaaa 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -2470,7 +2470,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size memset( &result, 0, sizeof(result) ); - for (;;) + do { RtlEnterCriticalSection( &addr_section ); if (!compare_addr( addr, cmp, size )) @@ -2496,16 +2496,18 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size RtlLeaveCriticalSection( &addr_section ); - if (ret == STATUS_PENDING) ret = wait_select_reply( &cookie ); - if (ret != STATUS_USER_APC && ret != STATUS_KERNEL_APC) break; - if (invoke_apc( &call, &result )) + if ((ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC) && + invoke_apc( &call, &result )) { /* if we ran a user apc we have to check once more if additional apcs are queued, * but we don't want to wait */ abs_timeout = 0; user_apc = TRUE; } + + if (ret == STATUS_PENDING) ret = wait_select_reply( &cookie ); } + while (ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC); if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC;