[PATCH v2 2/6] server: Use STATUS_KERNEL_APC to indicate system APCs.

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


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

Notes:
    This uses the same error handling logic in case of alloc_handle
    failure as for the user APC loop, the APC is considered as executed
    although it failed.

 dlls/ntdll/server.c |  2 +-
 dlls/ntdll/sync.c   |  2 +-
 server/thread.c     | 22 +++++++++++++++++-----
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index 089eb3b89aa..73f4d86cf4d 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -624,7 +624,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
         }
         SERVER_END_REQ;
         if (ret == STATUS_PENDING) ret = wait_select_reply( &cookie );
-        if (ret != STATUS_USER_APC) break;
+        if (ret != STATUS_USER_APC && ret != STATUS_KERNEL_APC) break;
         if (invoke_apc( &call, &result ))
         {
             /* if we ran a user apc we have to check once more if additional apcs are queued,
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index c4885973b68..d09b90a9273 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -2497,7 +2497,7 @@ 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) break;
+        if (ret != STATUS_USER_APC && ret != STATUS_KERNEL_APC) break;
         if (invoke_apc( &call, &result ))
         {
             /* if we ran a user apc we have to check once more if additional apcs are queued,
diff --git a/server/thread.c b/server/thread.c
index 0d502eecba5..886b478c9ed 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -749,7 +749,7 @@ static int check_wait( struct thread *thread )
     assert( wait );
 
     if ((wait->flags & SELECT_INTERRUPTIBLE) && !list_empty( &thread->system_apc ))
-        return STATUS_USER_APC;
+        return STATUS_KERNEL_APC;
 
     /* Suspended threads may not acquire locks, but they can run system APCs */
     if (thread->process->suspend + thread->suspend > 0) return -1;
@@ -1083,12 +1083,11 @@ void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_ty
 }
 
 /* remove the head apc from the queue; the returned object must be released by the caller */
-static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system_only )
+static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system )
 {
     struct thread_apc *apc = NULL;
-    struct list *ptr = list_head( &thread->system_apc );
+    struct list *ptr = list_head( system ? &thread->system_apc : &thread->user_apc );
 
-    if (!ptr && !system_only) ptr = list_head( &thread->user_apc );
     if (ptr)
     {
         apc = LIST_ENTRY( ptr, struct thread_apc, entry );
@@ -1583,7 +1582,7 @@ DECL_HANDLER(select)
 
     while (get_error() == STATUS_USER_APC)
     {
-        if (!(apc = thread_dequeue_apc( current, !(req->flags & SELECT_ALERTABLE) )))
+        if (!(apc = thread_dequeue_apc( current, 0 )))
             break;
         /* Optimization: ignore APC_NONE calls, they are only used to
          * wake up a thread, but since we got here the thread woke up already.
@@ -1599,6 +1598,19 @@ DECL_HANDLER(select)
         wake_up( &apc->obj, 0 );
         release_object( apc );
     }
+
+    if (get_error() == STATUS_KERNEL_APC)
+    {
+        apc = thread_dequeue_apc( current, 1 );
+        if ((reply->apc_handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 )))
+            reply->call = apc->call;
+        else
+        {
+            apc->executed = 1;
+            wake_up( &apc->obj, 0 );
+        }
+        release_object( apc );
+    }
 }
 
 /* queue an APC for a thread or process */
-- 
2.25.0




More information about the wine-devel mailing list