[PATCH 1/5] server: Use STATUS_KERNEL_APC to indicate system APCs.

Rémi Bernon rbernon at codeweavers.com
Tue Feb 4 04:09:21 CST 2020


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

This patch series is targetted around this specific status code to
tell system APCs from user APCs, although it is not strictly necessary.

We could already use the APC call type to tell the difference, but I
believe using the specific status makes the logic clearer.

 dlls/ntdll/server.c |  2 +-
 dlls/ntdll/sync.c   |  2 +-
 server/thread.c     | 20 +++++++++++++++-----
 3 files changed, 17 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 aec4c1acf4e..d82463c6baf 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 );
@@ -1585,7 +1584,7 @@ DECL_HANDLER(select)
     {
         for (;;)
         {
-            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.
@@ -1602,6 +1601,17 @@ DECL_HANDLER(select)
             release_object( apc );
         }
     }
+    else if (get_error() == STATUS_KERNEL_APC)
+    {
+        if (!(apc = thread_dequeue_apc( current, 1 )))
+            return;
+
+        if (!(reply->apc_handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 )))
+            return;
+
+        reply->call = apc->call;
+        release_object( apc );
+    }
 }
 
 /* queue an APC for a thread or process */
-- 
2.25.0




More information about the wine-devel mailing list