Sebastian Lackner : ntdll: Reimplement RtlQueueWorkItem on top of new threadpool API.

Alexandre Julliard julliard at wine.codeweavers.com
Tue Jul 28 13:30:06 CDT 2015


Module: wine
Branch: master
Commit: 9562e818101e67304c613dec922b86a793c26e59
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=9562e818101e67304c613dec922b86a793c26e59

Author: Sebastian Lackner <sebastian at fds-team.de>
Date:   Sun Jul 26 23:24:06 2015 +0200

ntdll: Reimplement RtlQueueWorkItem on top of new threadpool API.

---

 dlls/ntdll/threadpool.c | 143 +++++++++---------------------------------------
 1 file changed, 27 insertions(+), 116 deletions(-)

diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 23091f3..ad4951f 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -42,44 +42,28 @@ WINE_DEFAULT_DEBUG_CHANNEL(threadpool);
  * Old thread pooling API
  */
 
-#define OLD_WORKER_TIMEOUT 30000        /* 30 seconds */
+struct rtl_work_item
+{
+    PRTL_WORK_ITEM_ROUTINE function;
+    PVOID context;
+};
+
 #define EXPIRE_NEVER       (~(ULONGLONG)0)
 #define TIMER_QUEUE_MAGIC  0x516d6954   /* TimQ */
 
-static RTL_CRITICAL_SECTION_DEBUG critsect_debug;
 static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug;
 
 static struct
 {
-    /* threadpool_cs must be held while modifying the following four elements */
-    struct list             work_item_list;
-    LONG                    num_workers;
-    LONG                    num_busy_workers;
-    LONG                    num_items_processed;
-    RTL_CONDITION_VARIABLE  threadpool_cond;
-    RTL_CRITICAL_SECTION    threadpool_cs;
     HANDLE                  compl_port;
     RTL_CRITICAL_SECTION    threadpool_compl_cs;
 }
 old_threadpool =
 {
-    LIST_INIT(old_threadpool.work_item_list),   /* work_item_list */
-    0,                                          /* num_workers */
-    0,                                          /* num_busy_workers */
-    0,                                          /* num_items_processed */
-    RTL_CONDITION_VARIABLE_INIT,                /* threadpool_cond */
-    { &critsect_debug, -1, 0, 0, 0, 0 },        /* threadpool_cs */
     NULL,                                       /* compl_port */
     { &critsect_compl_debug, -1, 0, 0, 0, 0 },  /* threadpool_compl_cs */
 };
 
-static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
-{
-    0, 0, &old_threadpool.threadpool_cs,
-    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
-      0, 0, { (DWORD_PTR)(__FILE__ ": threadpool_cs") }
-};
-
 static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug =
 {
     0, 0, &old_threadpool.threadpool_compl_cs,
@@ -87,13 +71,6 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug =
       0, 0, { (DWORD_PTR)(__FILE__ ": threadpool_compl_cs") }
 };
 
-struct work_item
-{
-    struct list entry;
-    PRTL_WORK_ITEM_ROUTINE function;
-    PVOID context;
-};
-
 struct wait_work_item
 {
     HANDLE Object;
@@ -364,47 +341,14 @@ static inline LONG interlocked_dec( PLONG dest )
     return interlocked_xchg_add( dest, -1 ) - 1;
 }
 
-static void WINAPI worker_thread_proc(void * param)
+static void CALLBACK process_rtl_work_item( TP_CALLBACK_INSTANCE *instance, void *userdata )
 {
-    struct list *item;
-    struct work_item *work_item_ptr, work_item;
-    LARGE_INTEGER timeout;
-    timeout.QuadPart = -(OLD_WORKER_TIMEOUT * (ULONGLONG)10000);
-
-    RtlEnterCriticalSection( &old_threadpool.threadpool_cs );
-    old_threadpool.num_workers++;
-
-    for (;;)
-    {
-        if ((item = list_head( &old_threadpool.work_item_list )))
-        {
-            work_item_ptr = LIST_ENTRY( item, struct work_item, entry );
-            list_remove( &work_item_ptr->entry );
-            old_threadpool.num_busy_workers++;
-            old_threadpool.num_items_processed++;
-            RtlLeaveCriticalSection( &old_threadpool.threadpool_cs );
-
-            /* copy item to stack and do the work */
-            work_item = *work_item_ptr;
-            RtlFreeHeap( GetProcessHeap(), 0, work_item_ptr );
-            TRACE("executing %p(%p)\n", work_item.function, work_item.context);
-            work_item.function( work_item.context );
-
-            RtlEnterCriticalSection( &old_threadpool.threadpool_cs );
-            old_threadpool.num_busy_workers--;
-        }
-        else if (RtlSleepConditionVariableCS( &old_threadpool.threadpool_cond,
-                 &old_threadpool.threadpool_cs, &timeout ) != STATUS_SUCCESS)
-        {
-            break;
-        }
-    }
+    struct rtl_work_item *item = userdata;
 
-    old_threadpool.num_workers--;
-    RtlLeaveCriticalSection( &old_threadpool.threadpool_cs );
-    RtlExitUserThread( 0 );
+    TRACE("executing %p(%p)\n", item->function, item->context);
+    item->function( item->context );
 
-    /* never reached */
+    RtlFreeHeap( GetProcessHeap(), 0, item );
 }
 
 /***********************************************************************
@@ -413,9 +357,9 @@ static void WINAPI worker_thread_proc(void * param)
  * Queues a work item into a thread in the thread pool.
  *
  * PARAMS
- *  Function [I] Work function to execute.
- *  Context  [I] Context to pass to the work function when it is executed.
- *  Flags    [I] Flags. See notes.
+ *  function [I] Work function to execute.
+ *  context  [I] Context to pass to the work function when it is executed.
+ *  flags    [I] Flags. See notes.
  *
  * RETURNS
  *  Success: STATUS_SUCCESS.
@@ -429,59 +373,26 @@ static void WINAPI worker_thread_proc(void * param)
  *|WT_EXECUTELONGFUNCTION - Hints that the execution can take a long time.
  *|WT_TRANSFER_IMPERSONATION - Executes the function with the current access token.
  */
-NTSTATUS WINAPI RtlQueueWorkItem(PRTL_WORK_ITEM_ROUTINE Function, PVOID Context, ULONG Flags)
+NTSTATUS WINAPI RtlQueueWorkItem( PRTL_WORK_ITEM_ROUTINE function, PVOID context, ULONG flags )
 {
-    HANDLE thread;
+    TP_CALLBACK_ENVIRON environment;
+    struct rtl_work_item *item;
     NTSTATUS status;
-    LONG items_processed;
-    struct work_item *work_item = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(struct work_item));
 
-    if (!work_item)
+    item = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*item) );
+    if (!item)
         return STATUS_NO_MEMORY;
 
-    work_item->function = Function;
-    work_item->context = Context;
-
-    if (Flags & ~WT_EXECUTELONGFUNCTION)
-        FIXME("Flags 0x%x not supported\n", Flags);
-
-    RtlEnterCriticalSection( &old_threadpool.threadpool_cs );
-    list_add_tail( &old_threadpool.work_item_list, &work_item->entry );
-    status = (old_threadpool.num_workers > old_threadpool.num_busy_workers) ?
-             STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
-    items_processed = old_threadpool.num_items_processed;
-    RtlLeaveCriticalSection( &old_threadpool.threadpool_cs );
-
-    /* FIXME: tune this algorithm to not be as aggressive with creating threads
-     * if WT_EXECUTELONGFUNCTION isn't specified */
-    if (status == STATUS_SUCCESS)
-        RtlWakeConditionVariable( &old_threadpool.threadpool_cond );
-    else
-    {
-        status = RtlCreateUserThread( GetCurrentProcess(), NULL, FALSE, NULL, 0, 0,
-                                      worker_thread_proc, NULL, &thread, NULL );
+    memset( &environment, 0, sizeof(environment) );
+    environment.Version = 1;
+    environment.u.s.LongFunction = (flags & WT_EXECUTELONGFUNCTION) != 0;
+    environment.u.s.Persistent   = (flags & WT_EXECUTEINPERSISTENTTHREAD) != 0;
 
-        /* NOTE: we don't care if we couldn't create the thread if there is at
-         * least one other available to process the request */
-        if (status == STATUS_SUCCESS)
-            NtClose( thread );
-        else
-        {
-            RtlEnterCriticalSection( &old_threadpool.threadpool_cs );
-            if (old_threadpool.num_workers > 0 ||
-                old_threadpool.num_items_processed != items_processed)
-            {
-                status = STATUS_SUCCESS;
-            }
-            else
-                list_remove( &work_item->entry );
-            RtlLeaveCriticalSection( &old_threadpool.threadpool_cs );
-
-            if (status != STATUS_SUCCESS)
-                RtlFreeHeap( GetProcessHeap(), 0, work_item );
-        }
-    }
+    item->function = function;
+    item->context  = context;
 
+    status = TpSimpleTryPost( process_rtl_work_item, item, &environment );
+    if (status) RtlFreeHeap( GetProcessHeap(), 0, item );
     return status;
 }
 




More information about the wine-cvs mailing list