[PATCH v2 3/6] ntdll: Reorder code to make the select logic clearer.

Rémi Bernon rbernon at codeweavers.com
Wed Feb 5 04:49:37 CST 2020


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 <rbernon at codeweavers.com>
---
 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;
 
-- 
2.25.0




More information about the wine-devel mailing list