From dfd86e0f9137610bf1bff0d76b1e3cb6755ffcf9 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Thu, 2 Jul 2015 17:45:32 +0200 Subject: [PATCH] Rebase against 3d8353fe182f3e7742cd7dab3420635e45ace129. --- ...t-for-threadpool-group-cancel-callba.patch | 81 ------ ...TpDisassociateCallback-and-add-separ.patch | 175 +++++++++++ ...t-for-threadpool-finalization-callba.patch | 56 ---- ...Add-tests-for-TpDisassociateCallback.patch | 191 ++++++++++++ ...ng-threadpool-functions-to-specfile.patch} | 2 +- ...threadpool-RaceDll-environment-varia.patch | 57 ---- ...TpCallbackMayRunLong-and-instance-st.patch | 195 ------------- ...t-threadpool-timer-functions.-rev-2.patch} | 34 +-- ...dll-Implement-TpDisassociateCallback.patch | 99 ------- ...d-tests-for-Tp-threadpool-functions.patch} | 272 ++---------------- ...various-threadpool-functions-to-ntd.patch} | 2 +- ...various-TpCallback-OnCompletion-func.patch | 186 ------------ ...l-Implement-threadpool-wait-objects.patch} | 54 ++-- ...d-tests-for-threadpool-wait-objects.patch} | 10 +- ...-threadpool-wait-functions-to-ntdll.patch} | 2 +- patches/patchinstall.sh | 32 +-- 16 files changed, 448 insertions(+), 1000 deletions(-) delete mode 100644 patches/ntdll-Vista_Threadpool/0001-ntdll-Add-support-for-threadpool-group-cancel-callba.patch create mode 100644 patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch delete mode 100644 patches/ntdll-Vista_Threadpool/0002-ntdll-Add-support-for-threadpool-finalization-callba.patch create mode 100644 patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch rename patches/ntdll-Vista_Threadpool/{0007-ntdll-Add-remaining-threadpool-functions-to-specfile.patch => 0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch} (97%) delete mode 100644 patches/ntdll-Vista_Threadpool/0003-ntdll-Implement-threadpool-RaceDll-environment-varia.patch delete mode 100644 patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-TpCallbackMayRunLong-and-instance-st.patch rename patches/ntdll-Vista_Threadpool/{0008-ntdll-Implement-threadpool-timer-functions.-rev-2.patch => 0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch} (93%) delete mode 100644 patches/ntdll-Vista_Threadpool/0005-ntdll-Implement-TpDisassociateCallback.patch rename patches/ntdll-Vista_Threadpool/{0009-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch => 0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch} (52%) rename patches/ntdll-Vista_Threadpool/{0010-kernel32-Forward-various-threadpool-functions-to-ntd.patch => 0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch} (99%) delete mode 100644 patches/ntdll-Vista_Threadpool/0006-ntdll-Implement-various-TpCallback-OnCompletion-func.patch rename patches/ntdll-Vista_Threadpool/{0011-ntdll-Implement-threadpool-wait-objects.patch => 0007-ntdll-Implement-threadpool-wait-objects.patch} (92%) rename patches/ntdll-Vista_Threadpool/{0012-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch => 0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch} (97%) rename patches/ntdll-Vista_Threadpool/{0013-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch => 0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch} (98%) diff --git a/patches/ntdll-Vista_Threadpool/0001-ntdll-Add-support-for-threadpool-group-cancel-callba.patch b/patches/ntdll-Vista_Threadpool/0001-ntdll-Add-support-for-threadpool-group-cancel-callba.patch deleted file mode 100644 index f1a3364e..00000000 --- a/patches/ntdll-Vista_Threadpool/0001-ntdll-Add-support-for-threadpool-group-cancel-callba.patch +++ /dev/null @@ -1,81 +0,0 @@ -From aec44ffb06857ee5c954136e82500e1dcb71f97b Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 06:57:53 +0100 -Subject: ntdll: Add support for threadpool group cancel callback. - ---- - dlls/ntdll/threadpool.c | 17 ++++++++++++++--- - 1 file changed, 14 insertions(+), 3 deletions(-) - -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index da41ba0..93d9b28 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -171,6 +171,7 @@ struct threadpool_object - struct threadpool *pool; - struct threadpool_group *group; - PVOID userdata; -+ PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback; - /* information about the group, locked via .group->cs */ - struct list group_entry; - BOOL is_group_member; -@@ -1370,6 +1371,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - object->pool = pool; - object->group = NULL; - object->userdata = userdata; -+ object->group_cancel_callback = NULL; - - memset( &object->group_entry, 0, sizeof(object->group_entry) ); - object->is_group_member = FALSE; -@@ -1385,6 +1387,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - FIXME( "unsupported environment version %u\n", environment->Version ); - - object->group = impl_from_TP_CLEANUP_GROUP( environment->CleanupGroup ); -+ object->group_cancel_callback = environment->CleanupGroupCancelCallback; - - WARN( "environment not fully implemented yet\n" ); - } -@@ -1467,7 +1470,7 @@ static void tp_object_submit( struct threadpool_object *object ) - * - * Cancels all currently pending callbacks for a specific object. - */ --static void tp_object_cancel( struct threadpool_object *object ) -+static void tp_object_cancel( struct threadpool_object *object, BOOL group_cancel, PVOID userdata ) - { - struct threadpool *pool = object->pool; - LONG pending_callbacks = 0; -@@ -1481,6 +1484,14 @@ static void tp_object_cancel( struct threadpool_object *object ) - } - RtlLeaveCriticalSection( &pool->cs ); - -+ /* Execute group cancellation callback if defined, and if this was actually a group cancel. */ -+ if (pending_callbacks && group_cancel && object->group_cancel_callback) -+ { -+ TRACE( "executing group cancel callback %p(%p, %p)\n", object->group_cancel_callback, object, userdata ); -+ object->group_cancel_callback( object, userdata ); -+ TRACE( "callback %p returned\n", object->group_cancel_callback ); -+ } -+ - while (pending_callbacks--) - tp_object_release( object ); - } -@@ -1766,7 +1777,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p - { - LIST_FOR_EACH_ENTRY( object, &members, struct threadpool_object, group_entry ) - { -- tp_object_cancel( object ); -+ tp_object_cancel( object, TRUE, userdata ); - } - } - -@@ -1894,6 +1905,6 @@ VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending ) - TRACE( "%p %u\n", work, cancel_pending ); - - if (cancel_pending) -- tp_object_cancel( this ); -+ tp_object_cancel( this, FALSE, NULL ); - tp_object_wait( this ); - } --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch b/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch new file mode 100644 index 00000000..2a3313f9 --- /dev/null +++ b/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch @@ -0,0 +1,175 @@ +From 1651eab61e449fef2119ff35703d6c9acc43f2b3 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 2 Jul 2015 17:15:41 +0200 +Subject: ntdll: Implement TpDisassociateCallback and add separate group + finished event. + +--- + dlls/ntdll/ntdll.spec | 1 + + dlls/ntdll/threadpool.c | 67 ++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 62 insertions(+), 6 deletions(-) + +diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec +index 134a3f7..ee90705 100644 +--- a/dlls/ntdll/ntdll.spec ++++ b/dlls/ntdll/ntdll.spec +@@ -979,6 +979,7 @@ + @ stdcall TpCallbackReleaseSemaphoreOnCompletion(ptr long long) + @ stdcall TpCallbackSetEventOnCompletion(ptr long) + @ stdcall TpCallbackUnloadDllOnCompletion(ptr ptr) ++@ stdcall TpDisassociateCallback(ptr) + @ stdcall TpPostWork(ptr) + @ stdcall TpReleaseCleanupGroup(ptr) + @ stdcall TpReleaseCleanupGroupMembers(ptr long ptr) +diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c +index eeb275f..0e09d0f 100644 +--- a/dlls/ntdll/threadpool.c ++++ b/dlls/ntdll/threadpool.c +@@ -181,8 +181,10 @@ struct threadpool_object + /* information about the pool, locked via .pool->cs */ + struct list pool_entry; + RTL_CONDITION_VARIABLE finished_event; ++ RTL_CONDITION_VARIABLE group_finished_event; + LONG num_pending_callbacks; + LONG num_running_callbacks; ++ LONG num_associated_callbacks; + /* arguments for callback */ + union + { +@@ -202,6 +204,7 @@ struct threadpool_instance + { + struct threadpool_object *object; + DWORD threadid; ++ BOOL associated; + BOOL may_run_long; + struct + { +@@ -1406,8 +1409,10 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa + + memset( &object->pool_entry, 0, sizeof(object->pool_entry) ); + RtlInitializeConditionVariable( &object->finished_event ); ++ RtlInitializeConditionVariable( &object->group_finished_event ); + object->num_pending_callbacks = 0; + object->num_running_callbacks = 0; ++ object->num_associated_callbacks = 0; + + if (environment) + { +@@ -1540,13 +1545,21 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance + * Waits until all pending and running callbacks of a specific object + * have been processed. + */ +-static void tp_object_wait( struct threadpool_object *object ) ++static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) + { + struct threadpool *pool = object->pool; + + RtlEnterCriticalSection( &pool->cs ); +- while (object->num_pending_callbacks || object->num_running_callbacks) +- RtlSleepConditionVariableCS( &object->finished_event, &pool->cs, NULL ); ++ if (group_wait) ++ { ++ while (object->num_pending_callbacks || object->num_running_callbacks) ++ RtlSleepConditionVariableCS( &object->group_finished_event, &pool->cs, NULL ); ++ } ++ else ++ { ++ while (object->num_pending_callbacks || object->num_associated_callbacks) ++ RtlSleepConditionVariableCS( &object->finished_event, &pool->cs, NULL ); ++ } + RtlLeaveCriticalSection( &pool->cs ); + } + +@@ -1631,6 +1644,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) + list_add_tail( &pool->pool, &object->pool_entry ); + + /* Leave critical section and do the actual callback. */ ++ object->num_associated_callbacks++; + object->num_running_callbacks++; + pool->num_busy_workers++; + RtlLeaveCriticalSection( &pool->cs ); +@@ -1639,6 +1653,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) + callback_instance = (TP_CALLBACK_INSTANCE *)&instance; + instance.object = object; + instance.threadid = GetCurrentThreadId(); ++ instance.associated = TRUE; + instance.may_run_long = object->may_run_long; + instance.cleanup.critical_section = NULL; + instance.cleanup.mutex = NULL; +@@ -1709,9 +1724,18 @@ static void CALLBACK threadpool_worker_proc( void *param ) + skip_cleanup: + RtlEnterCriticalSection( &pool->cs ); + pool->num_busy_workers--; ++ + object->num_running_callbacks--; + if (!object->num_pending_callbacks && !object->num_running_callbacks) +- RtlWakeAllConditionVariable( &object->finished_event ); ++ RtlWakeAllConditionVariable( &object->group_finished_event ); ++ ++ if (instance.associated) ++ { ++ object->num_associated_callbacks--; ++ if (!object->num_pending_callbacks && !object->num_associated_callbacks) ++ RtlWakeAllConditionVariable( &object->finished_event ); ++ } ++ + tp_object_release( object ); + } + +@@ -1913,6 +1937,37 @@ VOID WINAPI TpCallbackUnloadDllOnCompletion( TP_CALLBACK_INSTANCE *instance, HMO + } + + /*********************************************************************** ++ * TpDisassociateCallback (NTDLL.@) ++ */ ++VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) ++{ ++ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); ++ struct threadpool_object *object = this->object; ++ struct threadpool *pool; ++ ++ TRACE( "%p\n", instance ); ++ ++ if (this->threadid != GetCurrentThreadId()) ++ { ++ ERR("called from wrong thread, ignoring\n"); ++ return; ++ } ++ ++ if (!this->associated) ++ return; ++ ++ pool = object->pool; ++ RtlEnterCriticalSection( &pool->cs ); ++ ++ object->num_associated_callbacks--; ++ if (!object->num_pending_callbacks && !object->num_associated_callbacks) ++ RtlWakeAllConditionVariable( &object->finished_event ); ++ ++ RtlLeaveCriticalSection( &pool->cs ); ++ this->associated = FALSE; ++} ++ ++/*********************************************************************** + * TpPostWork (NTDLL.@) + */ + VOID WINAPI TpPostWork( TP_WORK *work ) +@@ -1993,7 +2048,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p + /* Wait for remaining callbacks to finish */ + LIST_FOR_EACH_ENTRY_SAFE( object, next, &members, struct threadpool_object, group_entry ) + { +- tp_object_wait( object ); ++ tp_object_wait( object, TRUE ); + tp_object_release( object ); + } + } +@@ -2115,5 +2170,5 @@ VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending ) + + if (cancel_pending) + tp_object_cancel( this, FALSE, NULL ); +- tp_object_wait( this ); ++ tp_object_wait( this, FALSE ); + } +-- +2.4.4 + diff --git a/patches/ntdll-Vista_Threadpool/0002-ntdll-Add-support-for-threadpool-finalization-callba.patch b/patches/ntdll-Vista_Threadpool/0002-ntdll-Add-support-for-threadpool-finalization-callba.patch deleted file mode 100644 index 6d96c466..00000000 --- a/patches/ntdll-Vista_Threadpool/0002-ntdll-Add-support-for-threadpool-finalization-callba.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 9a973853b87ff70fac8fbc42308300a861dc39de Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 07:03:15 +0100 -Subject: ntdll: Add support for threadpool finalization callback. - ---- - dlls/ntdll/threadpool.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 93d9b28..0133e66 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -172,6 +172,7 @@ struct threadpool_object - struct threadpool_group *group; - PVOID userdata; - PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback; -+ PTP_SIMPLE_CALLBACK finalization_callback; - /* information about the group, locked via .group->cs */ - struct list group_entry; - BOOL is_group_member; -@@ -1372,6 +1373,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - object->group = NULL; - object->userdata = userdata; - object->group_cancel_callback = NULL; -+ object->finalization_callback = NULL; - - memset( &object->group_entry, 0, sizeof(object->group_entry) ); - object->is_group_member = FALSE; -@@ -1388,6 +1390,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - - object->group = impl_from_TP_CLEANUP_GROUP( environment->CleanupGroup ); - object->group_cancel_callback = environment->CleanupGroupCancelCallback; -+ object->finalization_callback = environment->FinalizationCallback; - - WARN( "environment not fully implemented yet\n" ); - } -@@ -1616,6 +1619,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) - break; - } - -+ /* Execute finalization callback. */ -+ if (object->finalization_callback) -+ { -+ TRACE( "executing finalization callback %p(NULL, %p)\n", -+ object->finalization_callback, object->userdata ); -+ object->finalization_callback( NULL, object->userdata ); -+ TRACE( "callback %p returned\n", object->finalization_callback ); -+ } -+ - RtlEnterCriticalSection( &pool->cs ); - pool->num_busy_workers--; - object->num_running_callbacks--; --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch b/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch new file mode 100644 index 00000000..61dfe226 --- /dev/null +++ b/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch @@ -0,0 +1,191 @@ +From 8041e8ccf5ed9021525a95b7c6bcedfa7d945cb4 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 2 Jul 2015 17:18:00 +0200 +Subject: ntdll/tests: Add tests for TpDisassociateCallback. + +--- + dlls/ntdll/tests/threadpool.c | 149 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 149 insertions(+) + +diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c +index 62bd064..a75b622 100644 +--- a/dlls/ntdll/tests/threadpool.c ++++ b/dlls/ntdll/tests/threadpool.c +@@ -26,6 +26,7 @@ static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID); + static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); + static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); + static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); ++static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); + static VOID (WINAPI *pTpPostWork)(TP_WORK *); + static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); + static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID); +@@ -57,6 +58,7 @@ static BOOL init_threadpool(void) + NTDLL_GET_PROC(TpAllocWork); + NTDLL_GET_PROC(TpCallbackMayRunLong); + NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); ++ NTDLL_GET_PROC(TpDisassociateCallback); + NTDLL_GET_PROC(TpPostWork); + NTDLL_GET_PROC(TpReleaseCleanupGroup); + NTDLL_GET_PROC(TpReleaseCleanupGroupMembers); +@@ -498,6 +500,152 @@ static void test_tp_instance(void) + CloseHandle(semaphores[1]); + } + ++static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) ++{ ++ HANDLE *semaphores = userdata; ++ DWORD result; ++ ++ trace("Running disassociate callback\n"); ++ ++ pTpDisassociateCallback(instance); ++ result = WaitForSingleObject(semaphores[0], 1000); ++ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); ++ ReleaseSemaphore(semaphores[1], 1, NULL); ++} ++ ++static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) ++{ ++ HANDLE *semaphores = userdata; ++ DWORD result; ++ ++ trace("Running disassociate2 callback\n"); ++ ++ pTpDisassociateCallback(instance); ++ result = WaitForSingleObject(semaphores[0], 100); ++ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); ++ ReleaseSemaphore(semaphores[1], 1, NULL); ++} ++ ++static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) ++{ ++ HANDLE *semaphores = userdata; ++ DWORD result; ++ ++ trace("Running disassociate3 callback\n"); ++ ++ pTpDisassociateCallback(instance); ++ result = WaitForSingleObject(semaphores[0], 100); ++ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); ++ ReleaseSemaphore(semaphores[1], 1, NULL); ++} ++ ++static void test_tp_disassociate(void) ++{ ++ TP_CALLBACK_ENVIRON environment; ++ TP_CLEANUP_GROUP *group; ++ HANDLE semaphores[2]; ++ NTSTATUS status; ++ TP_POOL *pool; ++ TP_WORK *work; ++ DWORD result; ++ ++ semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL); ++ ok(semaphores[0] != NULL, "failed to create semaphore\n"); ++ semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); ++ ok(semaphores[1] != NULL, "failed to create semaphore\n"); ++ ++ /* allocate new threadpool and cleanup group */ ++ pool = NULL; ++ status = pTpAllocPool(&pool, NULL); ++ ok(!status, "TpAllocPool failed with status %x\n", status); ++ ok(pool != NULL, "expected pool != NULL\n"); ++ ++ group = NULL; ++ status = pTpAllocCleanupGroup(&group); ++ ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); ++ ok(group != NULL, "expected pool != NULL\n"); ++ ++ /* test TpDisassociateCallback on work objects without group */ ++ work = NULL; ++ memset(&environment, 0, sizeof(environment)); ++ environment.Version = 1; ++ environment.Pool = pool; ++ status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); ++ ok(!status, "TpAllocWork failed with status %x\n", status); ++ ok(work != NULL, "expected work != NULL\n"); ++ ++ pTpPostWork(work); ++ pTpWaitForWork(work, FALSE); ++ ++ result = WaitForSingleObject(semaphores[1], 100); ++ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); ++ ReleaseSemaphore(semaphores[0], 1, NULL); ++ result = WaitForSingleObject(semaphores[1], 1000); ++ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); ++ pTpReleaseWork(work); ++ ++ /* test TpDisassociateCallback on work objects with group (1) */ ++ work = NULL; ++ memset(&environment, 0, sizeof(environment)); ++ environment.Version = 1; ++ environment.Pool = pool; ++ environment.CleanupGroup = group; ++ status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); ++ ok(!status, "TpAllocWork failed with status %x\n", status); ++ ok(work != NULL, "expected work != NULL\n"); ++ ++ pTpPostWork(work); ++ pTpWaitForWork(work, FALSE); ++ ++ result = WaitForSingleObject(semaphores[1], 100); ++ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); ++ ReleaseSemaphore(semaphores[0], 1, NULL); ++ result = WaitForSingleObject(semaphores[1], 1000); ++ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); ++ pTpReleaseCleanupGroupMembers(group, FALSE, NULL); ++ ++ /* test TpDisassociateCallback on work objects with group (2) */ ++ work = NULL; ++ memset(&environment, 0, sizeof(environment)); ++ environment.Version = 1; ++ environment.Pool = pool; ++ environment.CleanupGroup = group; ++ status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment); ++ ok(!status, "TpAllocWork failed with status %x\n", status); ++ ok(work != NULL, "expected work != NULL\n"); ++ ++ pTpPostWork(work); ++ pTpReleaseCleanupGroupMembers(group, FALSE, NULL); ++ ++ ReleaseSemaphore(semaphores[0], 1, NULL); ++ result = WaitForSingleObject(semaphores[1], 1000); ++ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); ++ result = WaitForSingleObject(semaphores[0], 1000); ++ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); ++ ++ /* test TpDisassociateCallback on simple callbacks */ ++ memset(&environment, 0, sizeof(environment)); ++ environment.Version = 1; ++ environment.Pool = pool; ++ environment.CleanupGroup = group; ++ status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment); ++ ok(!status, "TpSimpleTryPost failed with status %x\n", status); ++ ++ pTpReleaseCleanupGroupMembers(group, FALSE, NULL); ++ ++ ReleaseSemaphore(semaphores[0], 1, NULL); ++ result = WaitForSingleObject(semaphores[1], 1000); ++ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); ++ result = WaitForSingleObject(semaphores[0], 1000); ++ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); ++ ++ /* cleanup */ ++ pTpReleaseCleanupGroup(group); ++ pTpReleasePool(pool); ++ CloseHandle(semaphores[0]); ++ CloseHandle(semaphores[1]); ++} ++ + START_TEST(threadpool) + { + if (!init_threadpool()) +@@ -508,4 +656,5 @@ START_TEST(threadpool) + test_tp_work_scheduler(); + test_tp_group_cancel(); + test_tp_instance(); ++ test_tp_disassociate(); + } +-- +2.4.4 + diff --git a/patches/ntdll-Vista_Threadpool/0007-ntdll-Add-remaining-threadpool-functions-to-specfile.patch b/patches/ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch similarity index 97% rename from patches/ntdll-Vista_Threadpool/0007-ntdll-Add-remaining-threadpool-functions-to-specfile.patch rename to patches/ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch index e5736d51..e66cd5de 100644 --- a/patches/ntdll-Vista_Threadpool/0007-ntdll-Add-remaining-threadpool-functions-to-specfile.patch +++ b/patches/ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch @@ -1,4 +1,4 @@ -From 75e6178d889b0883a03119d372858751d130b751 Mon Sep 17 00:00:00 2001 +From aef4ab9059bc29f2449c7ec19cb6562896ac1708 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 4 Mar 2015 08:01:00 +0100 Subject: ntdll: Add remaining threadpool functions to specfile. diff --git a/patches/ntdll-Vista_Threadpool/0003-ntdll-Implement-threadpool-RaceDll-environment-varia.patch b/patches/ntdll-Vista_Threadpool/0003-ntdll-Implement-threadpool-RaceDll-environment-varia.patch deleted file mode 100644 index 5c51c0a2..00000000 --- a/patches/ntdll-Vista_Threadpool/0003-ntdll-Implement-threadpool-RaceDll-environment-varia.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 6bc11921f0b13e7029d5f42f3fd9d2c88891cd41 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 07:07:07 +0100 -Subject: ntdll: Implement threadpool RaceDll environment variable. - ---- - dlls/ntdll/threadpool.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 0133e66..4ae81b0 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -173,6 +173,7 @@ struct threadpool_object - PVOID userdata; - PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback; - PTP_SIMPLE_CALLBACK finalization_callback; -+ HMODULE race_dll; - /* information about the group, locked via .group->cs */ - struct list group_entry; - BOOL is_group_member; -@@ -1374,6 +1375,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - object->userdata = userdata; - object->group_cancel_callback = NULL; - object->finalization_callback = NULL; -+ object->race_dll = NULL; - - memset( &object->group_entry, 0, sizeof(object->group_entry) ); - object->is_group_member = FALSE; -@@ -1391,10 +1393,14 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - object->group = impl_from_TP_CLEANUP_GROUP( environment->CleanupGroup ); - object->group_cancel_callback = environment->CleanupGroupCancelCallback; - object->finalization_callback = environment->FinalizationCallback; -+ object->race_dll = environment->RaceDll; - - WARN( "environment not fully implemented yet\n" ); - } - -+ if (object->race_dll) -+ LdrAddRefDll( 0, object->race_dll ); -+ - TRACE( "allocated object %p of type %u\n", object, object->type ); - - /* For simple callbacks we have to run tp_object_submit before adding this object -@@ -1560,6 +1566,9 @@ static BOOL tp_object_release( struct threadpool_object *object ) - - tp_threadpool_unlock( object->pool ); - -+ if (object->race_dll) -+ LdrUnloadDll( object->race_dll ); -+ - RtlFreeHeap( GetProcessHeap(), 0, object ); - return TRUE; - } --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-TpCallbackMayRunLong-and-instance-st.patch b/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-TpCallbackMayRunLong-and-instance-st.patch deleted file mode 100644 index c2bfca19..00000000 --- a/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-TpCallbackMayRunLong-and-instance-st.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 592d1e479946fc84440b05cc03041ccd5ba07a2b Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 07:25:35 +0100 -Subject: ntdll: Implement TpCallbackMayRunLong and instance structure. - ---- - dlls/ntdll/ntdll.spec | 1 + - dlls/ntdll/threadpool.c | 91 +++++++++++++++++++++++++++++++++++++++++++------ - 2 files changed, 82 insertions(+), 10 deletions(-) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index 4b5ece5..5a698c4 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -973,6 +973,7 @@ - @ stdcall TpAllocCleanupGroup(ptr) - @ stdcall TpAllocPool(ptr ptr) - @ stdcall TpAllocWork(ptr ptr ptr ptr) -+@ stdcall TpCallbackMayRunLong(ptr) - @ stdcall TpPostWork(ptr) - @ stdcall TpReleaseCleanupGroup(ptr) - @ stdcall TpReleaseCleanupGroupMembers(ptr long ptr) -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 4ae81b0..8634f44 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -173,6 +173,7 @@ struct threadpool_object - PVOID userdata; - PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback; - PTP_SIMPLE_CALLBACK finalization_callback; -+ BOOL may_run_long; - HMODULE race_dll; - /* information about the group, locked via .group->cs */ - struct list group_entry; -@@ -196,6 +197,14 @@ struct threadpool_object - } u; - }; - -+/* internal threadpool instance representation */ -+struct threadpool_instance -+{ -+ struct threadpool_object *object; -+ DWORD threadid; -+ BOOL may_run_long; -+}; -+ - /* internal threadpool group representation */ - struct threadpool_group - { -@@ -223,6 +232,11 @@ static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GR - return (struct threadpool_group *)group; - } - -+static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CALLBACK_INSTANCE *instance ) -+{ -+ return (struct threadpool_instance *)instance; -+} -+ - static void CALLBACK threadpool_worker_proc( void *param ); - static void tp_object_submit( struct threadpool_object *object ); - static void tp_object_shutdown( struct threadpool_object *object ); -@@ -1375,6 +1389,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - object->userdata = userdata; - object->group_cancel_callback = NULL; - object->finalization_callback = NULL; -+ object->may_run_long = 0; - object->race_dll = NULL; - - memset( &object->group_entry, 0, sizeof(object->group_entry) ); -@@ -1393,9 +1408,14 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - object->group = impl_from_TP_CLEANUP_GROUP( environment->CleanupGroup ); - object->group_cancel_callback = environment->CleanupGroupCancelCallback; - object->finalization_callback = environment->FinalizationCallback; -+ object->may_run_long = environment->u.s.LongFunction != 0; - object->race_dll = environment->RaceDll; - -- WARN( "environment not fully implemented yet\n" ); -+ if (environment->ActivationContext) -+ FIXME("activation context not supported yet\n"); -+ -+ if (environment->u.s.Persistent) -+ FIXME("persistent threads not supported yet\n"); - } - - if (object->race_dll) -@@ -1578,6 +1598,8 @@ static BOOL tp_object_release( struct threadpool_object *object ) - */ - static void CALLBACK threadpool_worker_proc( void *param ) - { -+ struct threadpool_instance instance; -+ TP_CALLBACK_INSTANCE *cb_instance = (TP_CALLBACK_INSTANCE *)&instance; - struct threadpool *pool = param; - LARGE_INTEGER timeout; - struct list *ptr; -@@ -1603,22 +1625,27 @@ static void CALLBACK threadpool_worker_proc( void *param ) - pool->num_busy_workers++; - RtlLeaveCriticalSection( &pool->cs ); - -+ /* Initialize threadpool instance struct. */ -+ instance.object = object; -+ instance.threadid = GetCurrentThreadId(); -+ instance.may_run_long = object->may_run_long; -+ - switch (object->type) - { - case TP_OBJECT_TYPE_SIMPLE: - { -- TRACE( "executing simple callback %p(NULL, %p)\n", -- object->u.simple.callback, object->userdata ); -- object->u.simple.callback( NULL, object->userdata ); -+ TRACE( "executing simple callback %p(%p, %p)\n", -+ object->u.simple.callback, cb_instance, object->userdata ); -+ object->u.simple.callback( cb_instance, object->userdata ); - TRACE( "callback %p returned\n", object->u.simple.callback ); - break; - } - - case TP_OBJECT_TYPE_WORK: - { -- TRACE( "executing work callback %p(NULL, %p, %p)\n", -- object->u.work.callback, object->userdata, object ); -- object->u.work.callback( NULL, object->userdata, (TP_WORK *)object ); -+ TRACE( "executing work callback %p(%p, %p, %p)\n", -+ object->u.work.callback, cb_instance, object->userdata, object ); -+ object->u.work.callback( cb_instance, object->userdata, (TP_WORK *)object ); - TRACE( "callback %p returned\n", object->u.work.callback ); - break; - } -@@ -1631,9 +1658,9 @@ static void CALLBACK threadpool_worker_proc( void *param ) - /* Execute finalization callback. */ - if (object->finalization_callback) - { -- TRACE( "executing finalization callback %p(NULL, %p)\n", -- object->finalization_callback, object->userdata ); -- object->finalization_callback( NULL, object->userdata ); -+ TRACE( "executing finalization callback %p(%p, %p)\n", -+ object->finalization_callback, cb_instance, object->userdata ); -+ object->finalization_callback( cb_instance, object->userdata ); - TRACE( "callback %p returned\n", object->finalization_callback ); - } - -@@ -1725,6 +1752,50 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us - } - - /*********************************************************************** -+ * TpCallbackMayRunLong (NTDLL.@) -+ */ -+NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ struct threadpool_object *object = this->object; -+ struct threadpool *pool; -+ NTSTATUS status = STATUS_SUCCESS; -+ -+ TRACE( "%p\n", instance ); -+ -+ if (this->threadid != GetCurrentThreadId()) -+ { -+ ERR("called from wrong thread, ignoring\n"); -+ return STATUS_UNSUCCESSFUL; /* FIXME */ -+ } -+ -+ if (this->may_run_long) -+ return STATUS_SUCCESS; -+ -+ pool = object->pool; -+ RtlEnterCriticalSection( &pool->cs ); -+ -+ /* Start new worker threads if required. */ -+ if (pool->num_busy_workers >= pool->num_workers && -+ pool->num_workers < pool->max_workers) -+ { -+ HANDLE thread; -+ status = RtlCreateUserThread( GetCurrentProcess(), NULL, FALSE, NULL, 0, 0, -+ threadpool_worker_proc, pool, &thread, NULL ); -+ if (status == STATUS_SUCCESS) -+ { -+ interlocked_inc( &pool->refcount ); -+ pool->num_workers++; -+ NtClose( thread ); -+ } -+ } -+ -+ RtlLeaveCriticalSection( &pool->cs ); -+ this->may_run_long = TRUE; -+ return status; -+} -+ -+/*********************************************************************** - * TpPostWork (NTDLL.@) - */ - VOID WINAPI TpPostWork( TP_WORK *work ) --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0008-ntdll-Implement-threadpool-timer-functions.-rev-2.patch b/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch similarity index 93% rename from patches/ntdll-Vista_Threadpool/0008-ntdll-Implement-threadpool-timer-functions.-rev-2.patch rename to patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch index 4ba212ab..16655c57 100644 --- a/patches/ntdll-Vista_Threadpool/0008-ntdll-Implement-threadpool-timer-functions.-rev-2.patch +++ b/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch @@ -1,4 +1,4 @@ -From 04e6df6c221a7f6fc57cfb431d889e62fe64fc47 Mon Sep 17 00:00:00 2001 +From e138d4b3eedeb471f70f2e48cdbb8c4c55207554 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 4 Mar 2015 08:19:47 +0100 Subject: ntdll: Implement threadpool timer functions. (rev 2) @@ -58,7 +58,7 @@ index d75efdc..0f4374e 100644 @ stdcall TpWaitForWork(ptr long) @ stdcall -ret64 VerSetConditionMask(int64 long long) diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 9874315..f4c9cba 100644 +index 0e09d0f..c44988c 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -158,7 +158,8 @@ struct threadpool @@ -71,7 +71,7 @@ index 9874315..f4c9cba 100644 }; /* internal threadpool object representation */ -@@ -194,6 +195,18 @@ struct threadpool_object +@@ -196,6 +197,18 @@ struct threadpool_object { PTP_WORK_CALLBACK callback; } work; @@ -90,7 +90,7 @@ index 9874315..f4c9cba 100644 } u; }; -@@ -225,6 +238,33 @@ struct threadpool_group +@@ -227,6 +240,33 @@ struct threadpool_group struct list members; }; @@ -124,7 +124,7 @@ index 9874315..f4c9cba 100644 static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool ) { return (struct threadpool *)pool; -@@ -237,6 +277,13 @@ static inline struct threadpool_object *impl_from_TP_WORK( TP_WORK *work ) +@@ -239,6 +279,13 @@ static inline struct threadpool_object *impl_from_TP_WORK( TP_WORK *work ) return object; } @@ -138,7 +138,7 @@ index 9874315..f4c9cba 100644 static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group ) { return (struct threadpool_group *)group; -@@ -248,6 +295,7 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL +@@ -250,6 +297,7 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL } static void CALLBACK threadpool_worker_proc( void *param ); @@ -146,7 +146,7 @@ index 9874315..f4c9cba 100644 static void tp_object_submit( struct threadpool_object *object ); static void tp_object_shutdown( struct threadpool_object *object ); static BOOL tp_object_release( struct threadpool_object *object ); -@@ -1171,6 +1219,230 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer, +@@ -1173,6 +1221,230 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer, return status; } @@ -377,7 +377,7 @@ index 9874315..f4c9cba 100644 /*********************************************************************** * tp_threadpool_alloc (internal) * -@@ -1559,6 +1831,9 @@ static void tp_object_wait( struct threadpool_object *object ) +@@ -1571,6 +1843,9 @@ static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) */ static void tp_object_shutdown( struct threadpool_object *object ) { @@ -387,15 +387,15 @@ index 9874315..f4c9cba 100644 object->shutdown = TRUE; } -@@ -1668,6 +1943,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) +@@ -1682,6 +1957,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) break; } + case TP_OBJECT_TYPE_TIMER: + { + TRACE( "executing timer callback %p(%p, %p, %p)\n", -+ object->u.timer.callback, cb_instance, object->userdata, object ); -+ object->u.timer.callback( cb_instance, object->userdata, (TP_TIMER *)object ); ++ object->u.timer.callback, callback_instance, object->userdata, object ); ++ object->u.timer.callback( callback_instance, object->userdata, (TP_TIMER *)object ); + TRACE( "callback %p returned\n", object->u.timer.callback ); + break; + } @@ -403,7 +403,7 @@ index 9874315..f4c9cba 100644 default: assert(0); break; -@@ -1768,6 +2052,46 @@ NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved ) +@@ -1788,6 +2072,46 @@ NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved ) } /*********************************************************************** @@ -450,7 +450,7 @@ index 9874315..f4c9cba 100644 * TpAllocWork (NTDLL.@) */ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata, -@@ -1942,6 +2266,17 @@ VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) +@@ -1968,6 +2292,17 @@ VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) } /*********************************************************************** @@ -468,7 +468,7 @@ index 9874315..f4c9cba 100644 * TpPostWork (NTDLL.@) */ VOID WINAPI TpPostWork( TP_WORK *work ) -@@ -2041,6 +2376,19 @@ VOID WINAPI TpReleasePool( TP_POOL *pool ) +@@ -2067,6 +2402,19 @@ VOID WINAPI TpReleasePool( TP_POOL *pool ) } /*********************************************************************** @@ -488,7 +488,7 @@ index 9874315..f4c9cba 100644 * TpReleaseWork (NTDLL.@) */ VOID WINAPI TpReleaseWork( TP_WORK *work ) -@@ -2104,6 +2452,18 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum ) +@@ -2130,6 +2478,18 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum ) } /*********************************************************************** @@ -507,7 +507,7 @@ index 9874315..f4c9cba 100644 * TpSimpleTryPost (NTDLL.@) */ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, -@@ -2134,6 +2494,20 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, +@@ -2160,6 +2520,20 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, } /*********************************************************************** @@ -521,7 +521,7 @@ index 9874315..f4c9cba 100644 + + if (cancel_pending) + tp_object_cancel( this, FALSE, NULL ); -+ tp_object_wait( this ); ++ tp_object_wait( this, FALSE ); +} + +/*********************************************************************** diff --git a/patches/ntdll-Vista_Threadpool/0005-ntdll-Implement-TpDisassociateCallback.patch b/patches/ntdll-Vista_Threadpool/0005-ntdll-Implement-TpDisassociateCallback.patch deleted file mode 100644 index 5a82127e..00000000 --- a/patches/ntdll-Vista_Threadpool/0005-ntdll-Implement-TpDisassociateCallback.patch +++ /dev/null @@ -1,99 +0,0 @@ -From e6ab4f5a5525d2d65cafef3b45ccd156105ebe46 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 07:31:27 +0100 -Subject: ntdll: Implement TpDisassociateCallback. - ---- - dlls/ntdll/ntdll.spec | 1 + - dlls/ntdll/threadpool.c | 42 +++++++++++++++++++++++++++++++++++++++--- - 2 files changed, 40 insertions(+), 3 deletions(-) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index 5a698c4..f61728f 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -974,6 +974,7 @@ - @ stdcall TpAllocPool(ptr ptr) - @ stdcall TpAllocWork(ptr ptr ptr ptr) - @ stdcall TpCallbackMayRunLong(ptr) -+@ stdcall TpDisassociateCallback(ptr) - @ stdcall TpPostWork(ptr) - @ stdcall TpReleaseCleanupGroup(ptr) - @ stdcall TpReleaseCleanupGroupMembers(ptr long ptr) -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 8634f44..6bd3206 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -202,6 +202,7 @@ struct threadpool_instance - { - struct threadpool_object *object; - DWORD threadid; -+ BOOL disassociated; - BOOL may_run_long; - }; - -@@ -1628,6 +1629,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - /* Initialize threadpool instance struct. */ - instance.object = object; - instance.threadid = GetCurrentThreadId(); -+ instance.disassociated = FALSE; - instance.may_run_long = object->may_run_long; - - switch (object->type) -@@ -1666,9 +1668,12 @@ static void CALLBACK threadpool_worker_proc( void *param ) - - RtlEnterCriticalSection( &pool->cs ); - pool->num_busy_workers--; -- object->num_running_callbacks--; -- if (!object->num_pending_callbacks && !object->num_running_callbacks) -- RtlWakeAllConditionVariable( &object->finished_event ); -+ if (!instance.disassociated) -+ { -+ object->num_running_callbacks--; -+ if (!object->num_pending_callbacks && !object->num_running_callbacks) -+ RtlWakeAllConditionVariable( &object->finished_event ); -+ } - tp_object_release( object ); - } - -@@ -1796,6 +1801,37 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) - } - - /*********************************************************************** -+ * TpDisassociateCallback (NTDLL.@) -+ */ -+VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ struct threadpool_object *object = this->object; -+ struct threadpool *pool; -+ -+ TRACE( "%p\n", instance ); -+ -+ if (this->threadid != GetCurrentThreadId()) -+ { -+ ERR("called from wrong thread, ignoring\n"); -+ return; -+ } -+ -+ if (this->disassociated) -+ return; -+ -+ pool = object->pool; -+ RtlEnterCriticalSection( &pool->cs ); -+ -+ object->num_running_callbacks--; -+ if (!object->num_pending_callbacks && !object->num_running_callbacks) -+ RtlWakeAllConditionVariable( &object->finished_event ); -+ -+ RtlLeaveCriticalSection( &pool->cs ); -+ this->disassociated = TRUE; -+} -+ -+/*********************************************************************** - * TpPostWork (NTDLL.@) - */ - VOID WINAPI TpPostWork( TP_WORK *work ) --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0009-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch b/patches/ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch similarity index 52% rename from patches/ntdll-Vista_Threadpool/0009-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch rename to patches/ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch index 293bc9df..d9b8e07e 100644 --- a/patches/ntdll-Vista_Threadpool/0009-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch +++ b/patches/ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch @@ -1,17 +1,17 @@ -From 8d1fba2b1f7b014130cfb64447cba2c2d257864a Mon Sep 17 00:00:00 2001 +From 8e03c37240d2a0fafbe6347bc8d509ce5555757a Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 4 Mar 2015 13:17:04 +0100 Subject: ntdll/tests: Add tests for Tp* threadpool functions. --- - dlls/ntdll/tests/threadpool.c | 470 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 470 insertions(+) + dlls/ntdll/tests/threadpool.c | 228 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 228 insertions(+) diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index b261cd1..76db2d0 100644 +index a75b622..4be3a8b 100644 --- a/dlls/ntdll/tests/threadpool.c +++ b/dlls/ntdll/tests/threadpool.c -@@ -22,15 +22,37 @@ +@@ -22,18 +22,37 @@ static HMODULE hntdll = 0; static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **); @@ -21,13 +21,13 @@ index b261cd1..76db2d0 100644 +static NTSTATUS (WINAPI *pTpAllocWait)(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); +static VOID (WINAPI *pTpCallbackLeaveCriticalSectionOnCompletion)(TP_CALLBACK_INSTANCE *,CRITICAL_SECTION *); -+static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); + static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); +static VOID (WINAPI *pTpCallbackReleaseMutexOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE); -+static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); + static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); +static VOID (WINAPI *pTpCallbackSetEventOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE); +static VOID (WINAPI *pTpCallbackUnloadDllOnCompletion)(TP_CALLBACK_INSTANCE *,HMODULE); +static VOID (WINAPI *pTpCancelAsyncIoOperation)(TP_IO *); -+static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); + static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); +static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *); static VOID (WINAPI *pTpPostWork)(TP_WORK *); static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); @@ -49,7 +49,7 @@ index b261cd1..76db2d0 100644 static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL); #define NTDLL_GET_PROC(func) \ -@@ -51,15 +73,37 @@ static BOOL init_threadpool(void) +@@ -54,18 +73,37 @@ static BOOL init_threadpool(void) } NTDLL_GET_PROC(TpAllocCleanupGroup); @@ -59,13 +59,13 @@ index b261cd1..76db2d0 100644 + NTDLL_GET_PROC(TpAllocWait); NTDLL_GET_PROC(TpAllocWork); + NTDLL_GET_PROC(TpCallbackLeaveCriticalSectionOnCompletion); -+ NTDLL_GET_PROC(TpCallbackMayRunLong); + NTDLL_GET_PROC(TpCallbackMayRunLong); + NTDLL_GET_PROC(TpCallbackReleaseMutexOnCompletion); -+ NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); + NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); + NTDLL_GET_PROC(TpCallbackSetEventOnCompletion); + NTDLL_GET_PROC(TpCallbackUnloadDllOnCompletion); + NTDLL_GET_PROC(TpCancelAsyncIoOperation); -+ NTDLL_GET_PROC(TpDisassociateCallback); + NTDLL_GET_PROC(TpDisassociateCallback); + NTDLL_GET_PROC(TpIsTimerSet); NTDLL_GET_PROC(TpPostWork); NTDLL_GET_PROC(TpReleaseCleanupGroup); @@ -87,244 +87,10 @@ index b261cd1..76db2d0 100644 NTDLL_GET_PROC(TpWaitForWork); if (!pTpAllocPool) -@@ -307,6 +351,425 @@ static void test_tp_work_scheduler(void) - pTpReleasePool(pool); +@@ -646,6 +684,191 @@ static void test_tp_disassociate(void) + CloseHandle(semaphores[1]); } -+static void CALLBACK instance_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ trace("Running instance callback\n"); -+ pTpCallbackMayRunLong(instance); -+ Sleep(100); -+ InterlockedIncrement( (LONG *)userdata ); -+} -+ -+static void CALLBACK instance2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ trace("Running instance2 callback\n"); -+ ok(*(LONG *)userdata == 1, "expected *userdata = 1, got %u\n", *(LONG *)userdata); -+ InterlockedIncrement( (LONG *)userdata ); -+} -+ -+static void CALLBACK instance3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ trace("Running instance3 callback\n"); -+ pTpDisassociateCallback(instance); -+ Sleep(100); -+ InterlockedIncrement( (LONG *)userdata ); -+} -+ -+static void CALLBACK instance4_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ trace("Running instance4 callback\n"); -+ pTpCallbackReleaseSemaphoreOnCompletion(instance, userdata, 1); -+} -+ -+static HANDLE instance_finalization_semaphore; -+ -+static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ DWORD ret; -+ trace("Running instance finalization callback\n"); -+ ok(*(LONG *)userdata == 1, "expected *userdata = 1, got %u\n", *(LONG *)userdata); -+ -+ /* Make sure that this callback is called before the regular instance cleanup tasks */ -+ ret = WaitForSingleObject(instance_finalization_semaphore, 100); -+ ok(ret == WAIT_TIMEOUT, "expected ret = WAIT_TIMEOUT, got %u\n", ret); -+ -+ InterlockedIncrement( (LONG *)userdata ); -+} -+ -+static void CALLBACK instance5_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ trace("Running instance5 callback\n"); -+ pTpCallbackReleaseSemaphoreOnCompletion(instance, instance_finalization_semaphore, 1); -+ InterlockedIncrement( (LONG *)userdata ); -+} -+ -+ -+static void test_tp_instance(void) -+{ -+ TP_CALLBACK_ENVIRON environment; -+ TP_CLEANUP_GROUP *group; -+ TP_POOL *pool; -+ NTSTATUS status; -+ LONG userdata; -+ HANDLE semaphore; -+ DWORD ret; -+ -+ /* Allocate new threadpool */ -+ pool = NULL; -+ status = pTpAllocPool(&pool, NULL); -+ ok(!status, "TpAllocPool failed with status %x\n", status); -+ ok(pool != NULL, "expected pool != NULL\n"); -+ -+ /* We limit the pool to a single thread */ -+ pTpSetPoolMaxThreads(pool, 1); -+ -+ /* Test behaviour of TpCallbackMayRunLong when the max number of threads is reached */ -+ userdata = 0; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ status = pTpSimpleTryPost(instance_cb, &userdata, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ status = pTpSimpleTryPost(instance2_cb, &userdata, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ while (userdata != 2) Sleep(10); -+ -+ /* Test behaviour of TpDisassociateCallback on wait functions */ -+ group = NULL; -+ status = pTpAllocCleanupGroup(&group); -+ ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); -+ ok(group != NULL, "expected pool != NULL\n"); -+ -+ userdata = 0; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ environment.CleanupGroup = group; -+ status = pTpSimpleTryPost(instance3_cb, &userdata, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ -+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL); -+ todo_wine /* behaviour contradicts the MSDN description? */ -+ ok(userdata == 1, "expected userdata = 1, got %u\n", userdata); -+ while (userdata == 0) Sleep(10); -+ -+ pTpReleaseCleanupGroup(group); -+ -+ /* Test for TpCallbackReleaseSemaphoreOnCompletion */ -+ semaphore = CreateSemaphoreW(NULL, 0, 1, NULL); -+ ok(semaphore != NULL, "failed to create semaphore\n"); -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ status = pTpSimpleTryPost(instance4_cb, semaphore, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ ret = WaitForSingleObject(semaphore, 1000); -+ ok(ret == WAIT_OBJECT_0, "expected ret = WAIT_OBJECT_0, got %u\n", ret); -+ -+ /* Test for finalization callback */ -+ userdata = 0; -+ instance_finalization_semaphore = semaphore; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ environment.FinalizationCallback = instance_finalization_cb; -+ status = pTpSimpleTryPost(instance5_cb, &userdata, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ ret = WaitForSingleObject(semaphore, 1000); -+ ok(ret == WAIT_OBJECT_0, "expected ret = WAIT_OBJECT_0, got %u\n", ret); -+ while (userdata != 2) Sleep(10); -+ -+ CloseHandle(semaphore); -+ -+ /* Cleanup */ -+ pTpReleasePool(pool); -+} -+ -+static DWORD group_cancel_tid; -+ -+static void CALLBACK group_cancel_cleanup_cb(void *object, void *userdata) -+{ -+ trace("Running group cancel cleanup callback\n"); -+ InterlockedIncrement( (LONG *)userdata ); -+ group_cancel_tid = GetCurrentThreadId(); -+} -+ -+static void CALLBACK group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ trace("Running group cancel callback\n"); -+ pTpCallbackMayRunLong(instance); -+ Sleep(100); -+ ok(*(LONG *)userdata == 1, "expected *userdata = 1, got %u\n", *(LONG *)userdata); -+ InterlockedIncrement( (LONG *)userdata ); -+} -+ -+static void CALLBACK dummy_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ ok(0, "Unexpected call to dummy_cb function\n"); -+} -+ -+static void test_tp_group_cancel(void) -+{ -+ TP_CALLBACK_ENVIRON environment; -+ TP_CLEANUP_GROUP *group; -+ TP_WORK *work; -+ TP_POOL *pool; -+ NTSTATUS status; -+ LONG userdata, userdata2; -+ int i; -+ -+ /* Allocate new threadpool */ -+ pool = NULL; -+ status = pTpAllocPool(&pool, NULL); -+ ok(!status, "TpAllocPool failed with status %x\n", status); -+ ok(pool != NULL, "expected pool != NULL\n"); -+ -+ /* We limit the pool to a single thread */ -+ pTpSetPoolMaxThreads(pool, 1); -+ -+ /* Allocate a cleanup group */ -+ group = NULL; -+ status = pTpAllocCleanupGroup(&group); -+ ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); -+ ok(group != NULL, "expected pool != NULL\n"); -+ -+ /* Test execution of cancellation callback */ -+ userdata = 0; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ status = pTpSimpleTryPost(group_cancel_cb, &userdata, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ environment.CleanupGroup = group; -+ environment.CleanupGroupCancelCallback = group_cancel_cleanup_cb; -+ status = pTpSimpleTryPost(dummy_cb, NULL, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ -+ group_cancel_tid = 0; -+ pTpReleaseCleanupGroupMembers(group, TRUE, &userdata); -+ ok(userdata == 1, "expected userdata = 1, got %u\n", userdata); -+ ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", -+ GetCurrentThreadId(), group_cancel_tid); -+ while (userdata != 2) Sleep(10); -+ -+ /* Test cancellation callback for elements with multiple instances */ -+ /* Allocate new work item */ -+ work = NULL; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ environment.CleanupGroup = group; -+ environment.CleanupGroupCancelCallback = group_cancel_cleanup_cb; -+ status = pTpAllocWork(&work, work_cb, &userdata, &environment); -+ ok(!status, "TpAllocWork failed with status %x\n", status); -+ ok(work != NULL, "expected work != NULL\n"); -+ -+ /* Post 10 identical work items at once */ -+ userdata = userdata2 = 0; -+ for (i = 0; i < 10; i++) -+ pTpPostWork(work); -+ -+ /* Check if we get multiple cancellation callbacks */ -+ group_cancel_tid = 0; -+ pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2); -+ ok(userdata < 10, "expected userdata < 10, got %u\n", userdata); -+ ok(userdata2 == 1, "expected only one cancellation callback, got %u\n", userdata2); -+ ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", -+ GetCurrentThreadId(), group_cancel_tid); -+ -+ /* Cleanup */ -+ pTpReleaseCleanupGroup(group); -+ pTpReleasePool(pool); -+} -+ +static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) +{ + trace("Running timer callback\n"); @@ -513,12 +279,10 @@ index b261cd1..76db2d0 100644 START_TEST(threadpool) { if (!init_threadpool()) -@@ -315,4 +778,11 @@ START_TEST(threadpool) - test_tp_simple(); - test_tp_work(); - test_tp_work_scheduler(); -+ test_tp_instance(); -+ test_tp_group_cancel(); +@@ -657,4 +880,9 @@ START_TEST(threadpool) + test_tp_group_cancel(); + test_tp_instance(); + test_tp_disassociate(); + test_tp_timer(); + test_tp_window_length(); + diff --git a/patches/ntdll-Vista_Threadpool/0010-kernel32-Forward-various-threadpool-functions-to-ntd.patch b/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch similarity index 99% rename from patches/ntdll-Vista_Threadpool/0010-kernel32-Forward-various-threadpool-functions-to-ntd.patch rename to patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch index 5da4225f..7a9f10bb 100644 --- a/patches/ntdll-Vista_Threadpool/0010-kernel32-Forward-various-threadpool-functions-to-ntd.patch +++ b/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch @@ -1,4 +1,4 @@ -From e6dda25c2975565acf141011fba0694b27c8c8a0 Mon Sep 17 00:00:00 2001 +From 37906069933d6bd73b8c6a691292288c57b09e22 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sun, 1 Feb 2015 19:41:13 +0100 Subject: kernel32: Forward various threadpool functions to ntdll. diff --git a/patches/ntdll-Vista_Threadpool/0006-ntdll-Implement-various-TpCallback-OnCompletion-func.patch b/patches/ntdll-Vista_Threadpool/0006-ntdll-Implement-various-TpCallback-OnCompletion-func.patch deleted file mode 100644 index 87715f51..00000000 --- a/patches/ntdll-Vista_Threadpool/0006-ntdll-Implement-various-TpCallback-OnCompletion-func.patch +++ /dev/null @@ -1,186 +0,0 @@ -From c38bf17c8f87444feca7e4ce3508e55c581671e9 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 07:40:02 +0100 -Subject: ntdll: Implement various TpCallback*OnCompletion functions. - ---- - dlls/ntdll/ntdll.spec | 5 +++ - dlls/ntdll/threadpool.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 115 insertions(+) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index f61728f..ee90705 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -973,7 +973,12 @@ - @ stdcall TpAllocCleanupGroup(ptr) - @ stdcall TpAllocPool(ptr ptr) - @ stdcall TpAllocWork(ptr ptr ptr ptr) -+@ stdcall TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr) - @ stdcall TpCallbackMayRunLong(ptr) -+@ stdcall TpCallbackReleaseMutexOnCompletion(ptr long) -+@ stdcall TpCallbackReleaseSemaphoreOnCompletion(ptr long long) -+@ stdcall TpCallbackSetEventOnCompletion(ptr long) -+@ stdcall TpCallbackUnloadDllOnCompletion(ptr ptr) - @ stdcall TpDisassociateCallback(ptr) - @ stdcall TpPostWork(ptr) - @ stdcall TpReleaseCleanupGroup(ptr) -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 6bd3206..9874315 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -204,6 +204,15 @@ struct threadpool_instance - DWORD threadid; - BOOL disassociated; - BOOL may_run_long; -+ struct -+ { -+ CRITICAL_SECTION *critical_section; -+ HANDLE mutex; -+ HANDLE semaphore; -+ LONG semaphore_count; -+ HANDLE event; -+ HMODULE library; -+ } cleanup; - }; - - /* internal threadpool group representation */ -@@ -1604,6 +1613,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - struct threadpool *pool = param; - LARGE_INTEGER timeout; - struct list *ptr; -+ NTSTATUS status; - - TRACE( "starting worker thread for pool %p\n", pool ); - -@@ -1631,6 +1641,12 @@ static void CALLBACK threadpool_worker_proc( void *param ) - instance.threadid = GetCurrentThreadId(); - instance.disassociated = FALSE; - instance.may_run_long = object->may_run_long; -+ instance.cleanup.critical_section = NULL; -+ instance.cleanup.mutex = NULL; -+ instance.cleanup.semaphore = NULL; -+ instance.cleanup.semaphore_count = 0; -+ instance.cleanup.event = NULL; -+ instance.cleanup.library = NULL; - - switch (object->type) - { -@@ -1666,6 +1682,32 @@ static void CALLBACK threadpool_worker_proc( void *param ) - TRACE( "callback %p returned\n", object->finalization_callback ); - } - -+ /* Execute cleanup tasks. */ -+ if (instance.cleanup.critical_section) -+ { -+ RtlLeaveCriticalSection( instance.cleanup.critical_section ); -+ } -+ if (instance.cleanup.mutex) -+ { -+ status = NtReleaseMutant( instance.cleanup.mutex, NULL ); -+ if (status != STATUS_SUCCESS) goto skip_cleanup; -+ } -+ if (instance.cleanup.semaphore) -+ { -+ status = NtReleaseSemaphore( instance.cleanup.semaphore, instance.cleanup.semaphore_count, NULL ); -+ if (status != STATUS_SUCCESS) goto skip_cleanup; -+ } -+ if (instance.cleanup.event) -+ { -+ status = NtSetEvent( instance.cleanup.event, NULL ); -+ if (status != STATUS_SUCCESS) goto skip_cleanup; -+ } -+ if (instance.cleanup.library) -+ { -+ LdrUnloadDll( instance.cleanup.library ); -+ } -+ -+ skip_cleanup: - RtlEnterCriticalSection( &pool->cs ); - pool->num_busy_workers--; - if (!instance.disassociated) -@@ -1757,6 +1799,19 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us - } - - /*********************************************************************** -+ * TpCallbackLeaveCriticalSectionOnCompletion (NTDLL.@) -+ */ -+VOID WINAPI TpCallbackLeaveCriticalSectionOnCompletion( TP_CALLBACK_INSTANCE *instance, CRITICAL_SECTION *crit ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ -+ TRACE( "%p %p\n", instance, crit ); -+ -+ if (!this->cleanup.critical_section) -+ this->cleanup.critical_section = crit; -+} -+ -+/*********************************************************************** - * TpCallbackMayRunLong (NTDLL.@) - */ - NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) -@@ -1801,6 +1856,61 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) - } - - /*********************************************************************** -+ * TpCallbackReleaseMutexOnCompletion (NTDLL.@) -+ */ -+VOID WINAPI TpCallbackReleaseMutexOnCompletion( TP_CALLBACK_INSTANCE *instance, HANDLE mutex ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ -+ TRACE( "%p %p\n", instance, mutex ); -+ -+ if (!this->cleanup.mutex) -+ this->cleanup.mutex = mutex; -+} -+ -+/*********************************************************************** -+ * TpCallbackReleaseSemaphoreOnCompletion (NTDLL.@) -+ */ -+VOID WINAPI TpCallbackReleaseSemaphoreOnCompletion( TP_CALLBACK_INSTANCE *instance, HANDLE semaphore, DWORD count ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ -+ TRACE( "%p %p %u\n", instance, semaphore, count ); -+ -+ if (!this->cleanup.semaphore) -+ { -+ this->cleanup.semaphore = semaphore; -+ this->cleanup.semaphore_count = count; -+ } -+} -+ -+/*********************************************************************** -+ * TpCallbackSetEventOnCompletion (NTDLL.@) -+ */ -+VOID WINAPI TpCallbackSetEventOnCompletion( TP_CALLBACK_INSTANCE *instance, HANDLE event ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ -+ TRACE( "%p %p\n", instance, event ); -+ -+ if (!this->cleanup.event) -+ this->cleanup.event = event; -+} -+ -+/*********************************************************************** -+ * TpCallbackUnloadDllOnCompletion (NTDLL.@) -+ */ -+VOID WINAPI TpCallbackUnloadDllOnCompletion( TP_CALLBACK_INSTANCE *instance, HMODULE module ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ -+ TRACE( "%p %p\n", instance, module ); -+ -+ if (!this->cleanup.library) -+ this->cleanup.library = module; -+} -+ -+/*********************************************************************** - * TpDisassociateCallback (NTDLL.@) - */ - VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0011-ntdll-Implement-threadpool-wait-objects.patch b/patches/ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch similarity index 92% rename from patches/ntdll-Vista_Threadpool/0011-ntdll-Implement-threadpool-wait-objects.patch rename to patches/ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch index 2982c58f..0e8f1173 100644 --- a/patches/ntdll-Vista_Threadpool/0011-ntdll-Implement-threadpool-wait-objects.patch +++ b/patches/ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch @@ -1,4 +1,4 @@ -From 008bb589716259fa962bdff580d5ec436bbf8ce4 Mon Sep 17 00:00:00 2001 +From 5dd5ac0fa0ef0845cc8611ce664e48e8b25f290b Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 4 Mar 2015 13:33:25 +0100 Subject: ntdll: Implement threadpool wait objects. @@ -49,7 +49,7 @@ index 0f4374e..ffcf58d 100644 @ stdcall -ret64 VerSetConditionMask(int64 long long) @ stdcall WinSqmIsOptedIn() diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index f4c9cba..f569506 100644 +index c44988c..b8d761b 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -137,6 +137,7 @@ struct timer_queue @@ -70,7 +70,7 @@ index f4c9cba..f569506 100644 }; /* internal threadpool object representation */ -@@ -207,6 +209,17 @@ struct threadpool_object +@@ -209,6 +211,17 @@ struct threadpool_object LONG period; LONG window_length; } timer; @@ -88,7 +88,7 @@ index f4c9cba..f569506 100644 } u; }; -@@ -265,6 +278,38 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug = +@@ -267,6 +280,38 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug = 0, 0, { (DWORD_PTR)(__FILE__ ": timerqueue.cs") } }; @@ -127,7 +127,7 @@ index f4c9cba..f569506 100644 static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool ) { return (struct threadpool *)pool; -@@ -284,6 +329,13 @@ static inline struct threadpool_object *impl_from_TP_TIMER( TP_TIMER *timer ) +@@ -286,6 +331,13 @@ static inline struct threadpool_object *impl_from_TP_TIMER( TP_TIMER *timer ) return object; } @@ -141,7 +141,7 @@ index f4c9cba..f569506 100644 static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group ) { return (struct threadpool_group *)group; -@@ -296,7 +348,8 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL +@@ -298,7 +350,8 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL static void CALLBACK threadpool_worker_proc( void *param ); static void CALLBACK timerqueue_thread_proc( void *param ); @@ -151,7 +151,7 @@ index f4c9cba..f569506 100644 static void tp_object_shutdown( struct threadpool_object *object ); static BOOL tp_object_release( struct threadpool_object *object ); static struct threadpool *default_threadpool = NULL; -@@ -1350,7 +1403,7 @@ update_timer: +@@ -1352,7 +1405,7 @@ update_timer: RtlLeaveCriticalSection( &timerqueue.cs ); if (submit_timer) @@ -160,7 +160,7 @@ index f4c9cba..f569506 100644 } static void CALLBACK timerqueue_thread_proc( void *param ) -@@ -1377,7 +1430,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) +@@ -1379,7 +1432,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) /* Queue a new callback in one of the worker threads */ list_remove( &timer->u.timer.timer_entry ); @@ -169,7 +169,7 @@ index f4c9cba..f569506 100644 /* Requeue the timer, except its marked for shutdown */ if (!timer->shutdown && timer->u.timer.period) -@@ -1443,6 +1496,301 @@ static void CALLBACK timerqueue_thread_proc( void *param ) +@@ -1445,6 +1498,301 @@ static void CALLBACK timerqueue_thread_proc( void *param ) RtlLeaveCriticalSection( &timerqueue.cs ); } @@ -471,7 +471,7 @@ index f4c9cba..f569506 100644 /*********************************************************************** * tp_threadpool_alloc (internal) * -@@ -1710,7 +2058,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa +@@ -1714,7 +2062,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa * will be set, and tp_object_submit would fail with an assertion. */ if (is_simple_callback) @@ -480,7 +480,7 @@ index f4c9cba..f569506 100644 if (object->group) { -@@ -1736,7 +2084,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa +@@ -1740,7 +2088,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa * Submits a threadpool object to the associcated threadpool. This * function has to be VOID because TpPostWork can never fail on Windows. */ @@ -489,7 +489,7 @@ index f4c9cba..f569506 100644 { struct threadpool *pool = object->pool; NTSTATUS status = STATUS_UNSUCCESSFUL; -@@ -1766,6 +2114,10 @@ static void tp_object_submit( struct threadpool_object *object ) +@@ -1770,6 +2118,10 @@ static void tp_object_submit( struct threadpool_object *object ) if (!object->num_pending_callbacks++) list_add_tail( &pool->pool, &object->pool_entry ); @@ -500,7 +500,7 @@ index f4c9cba..f569506 100644 /* No new thread started - wake up one existing thread. */ if (status != STATUS_SUCCESS) { -@@ -1793,6 +2145,9 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance +@@ -1797,6 +2149,9 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance object->num_pending_callbacks = 0; list_remove( &object->pool_entry ); } @@ -510,7 +510,7 @@ index f4c9cba..f569506 100644 RtlLeaveCriticalSection( &pool->cs ); /* Execute group cancellation callback if defined, and if this was actually a group cancel. */ -@@ -1833,6 +2188,8 @@ static void tp_object_shutdown( struct threadpool_object *object ) +@@ -1845,6 +2200,8 @@ static void tp_object_shutdown( struct threadpool_object *object ) { if (object->type == TP_OBJECT_TYPE_TIMER) tp_timerqueue_release( object ); @@ -519,15 +519,15 @@ index f4c9cba..f569506 100644 object->shutdown = TRUE; } -@@ -1886,6 +2243,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) +@@ -1898,6 +2255,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) + TP_CALLBACK_INSTANCE *callback_instance; struct threadpool_instance instance; - TP_CALLBACK_INSTANCE *cb_instance = (TP_CALLBACK_INSTANCE *)&instance; struct threadpool *pool = param; + TP_WAIT_RESULT wait_result; LARGE_INTEGER timeout; struct list *ptr; NTSTATUS status; -@@ -1906,6 +2264,18 @@ static void CALLBACK threadpool_worker_proc( void *param ) +@@ -1918,6 +2276,18 @@ static void CALLBACK threadpool_worker_proc( void *param ) if (--object->num_pending_callbacks) list_add_tail( &pool->pool, &object->pool_entry ); @@ -544,17 +544,17 @@ index f4c9cba..f569506 100644 + } + /* Leave critical section and do the actual callback. */ + object->num_associated_callbacks++; object->num_running_callbacks++; - pool->num_busy_workers++; -@@ -1952,6 +2322,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) +@@ -1966,6 +2336,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) break; } + case TP_OBJECT_TYPE_WAIT: + { + TRACE( "executing wait callback %p(%p, %p, %p, %u)\n", -+ object->u.wait.callback, cb_instance, object->userdata, object, wait_result ); -+ object->u.wait.callback( cb_instance, object->userdata, (TP_WAIT *)object, wait_result ); ++ object->u.wait.callback, callback_instance, object->userdata, object, wait_result ); ++ object->u.wait.callback( callback_instance, object->userdata, (TP_WAIT *)object, wait_result ); + TRACE( "callback %p returned\n", object->u.wait.callback ); + break; + } @@ -562,7 +562,7 @@ index f4c9cba..f569506 100644 default: assert(0); break; -@@ -2092,6 +2471,46 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID +@@ -2112,6 +2491,46 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID } /*********************************************************************** @@ -609,7 +609,7 @@ index f4c9cba..f569506 100644 * TpAllocWork (NTDLL.@) */ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata, -@@ -2285,7 +2704,7 @@ VOID WINAPI TpPostWork( TP_WORK *work ) +@@ -2311,7 +2730,7 @@ VOID WINAPI TpPostWork( TP_WORK *work ) TRACE( "%p\n", work ); @@ -618,7 +618,7 @@ index f4c9cba..f569506 100644 } /*********************************************************************** -@@ -2389,6 +2808,19 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer ) +@@ -2415,6 +2834,19 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer ) } /*********************************************************************** @@ -638,7 +638,7 @@ index f4c9cba..f569506 100644 * TpReleaseWork (NTDLL.@) */ VOID WINAPI TpReleaseWork( TP_WORK *work ) -@@ -2464,6 +2896,18 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO +@@ -2490,6 +2922,18 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO } /*********************************************************************** @@ -657,7 +657,7 @@ index f4c9cba..f569506 100644 * TpSimpleTryPost (NTDLL.@) */ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, -@@ -2508,6 +2952,20 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending ) +@@ -2534,6 +2978,20 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending ) } /*********************************************************************** @@ -671,7 +671,7 @@ index f4c9cba..f569506 100644 + + if (cancel_pending) + tp_object_cancel( this, FALSE, NULL ); -+ tp_object_wait( this ); ++ tp_object_wait( this, FALSE ); +} + +/*********************************************************************** diff --git a/patches/ntdll-Vista_Threadpool/0012-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch b/patches/ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch similarity index 97% rename from patches/ntdll-Vista_Threadpool/0012-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch rename to patches/ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch index 910e204f..6a9363f9 100644 --- a/patches/ntdll-Vista_Threadpool/0012-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch +++ b/patches/ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch @@ -1,4 +1,4 @@ -From 0f5fd3ad8c585b98f2754738fb9a7bb0e9b83708 Mon Sep 17 00:00:00 2001 +From 0aa4ad9970796cbbbe4fc5f81209e6d5d505a385 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 6 Feb 2015 20:09:41 +0100 Subject: ntdll/tests: Add tests for threadpool wait objects. @@ -8,10 +8,10 @@ Subject: ntdll/tests: Add tests for threadpool wait objects. 1 file changed, 287 insertions(+) diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index 76db2d0..368692b 100644 +index 4be3a8b..fd587ba 100644 --- a/dlls/ntdll/tests/threadpool.c +++ b/dlls/ntdll/tests/threadpool.c -@@ -770,6 +770,291 @@ static void test_tp_window_length(void) +@@ -869,6 +869,291 @@ static void test_tp_window_length(void) pTpReleasePool(pool); } @@ -303,8 +303,8 @@ index 76db2d0..368692b 100644 START_TEST(threadpool) { if (!init_threadpool()) -@@ -782,6 +1067,8 @@ START_TEST(threadpool) - test_tp_group_cancel(); +@@ -882,6 +1167,8 @@ START_TEST(threadpool) + test_tp_disassociate(); test_tp_timer(); test_tp_window_length(); + test_tp_wait(); diff --git a/patches/ntdll-Vista_Threadpool/0013-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch b/patches/ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch similarity index 98% rename from patches/ntdll-Vista_Threadpool/0013-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch rename to patches/ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch index 1ba80e7e..fbb858f4 100644 --- a/patches/ntdll-Vista_Threadpool/0013-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch +++ b/patches/ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch @@ -1,4 +1,4 @@ -From 2427c8fb3757a84085d22d176f9f6e797ea64498 Mon Sep 17 00:00:00 2001 +From b32a93ef14e23672df3a11ef1e9718857c933ff9 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 6 Feb 2015 20:24:27 +0100 Subject: kernel32: Forward threadpool wait functions to ntdll. diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 5c30e23d..a285fca5 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -55,7 +55,7 @@ version() echo "Copyright (C) 2014-2015 the Wine Staging project authors." echo "" echo "Patchset to be applied on upstream Wine:" - echo " commit 7a3c9889e38ede659230a66a167b82c024f0dc85" + echo " commit 3d8353fe182f3e7742cd7dab3420635e45ace129" echo "" } @@ -3701,26 +3701,18 @@ fi # | dlls/ntdll/tests/threadpool.c, dlls/ntdll/threadpool.c, include/winternl.h # | if test "$enable_ntdll_Vista_Threadpool" -eq 1; then - patch_apply ntdll-Vista_Threadpool/0001-ntdll-Add-support-for-threadpool-group-cancel-callba.patch - patch_apply ntdll-Vista_Threadpool/0002-ntdll-Add-support-for-threadpool-finalization-callba.patch - patch_apply ntdll-Vista_Threadpool/0003-ntdll-Implement-threadpool-RaceDll-environment-varia.patch - patch_apply ntdll-Vista_Threadpool/0004-ntdll-Implement-TpCallbackMayRunLong-and-instance-st.patch - patch_apply ntdll-Vista_Threadpool/0005-ntdll-Implement-TpDisassociateCallback.patch - patch_apply ntdll-Vista_Threadpool/0006-ntdll-Implement-various-TpCallback-OnCompletion-func.patch - patch_apply ntdll-Vista_Threadpool/0007-ntdll-Add-remaining-threadpool-functions-to-specfile.patch - patch_apply ntdll-Vista_Threadpool/0008-ntdll-Implement-threadpool-timer-functions.-rev-2.patch - patch_apply ntdll-Vista_Threadpool/0009-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch - patch_apply ntdll-Vista_Threadpool/0010-kernel32-Forward-various-threadpool-functions-to-ntd.patch - patch_apply ntdll-Vista_Threadpool/0011-ntdll-Implement-threadpool-wait-objects.patch - patch_apply ntdll-Vista_Threadpool/0012-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch - patch_apply ntdll-Vista_Threadpool/0013-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch + patch_apply ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch + patch_apply ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch + patch_apply ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch + patch_apply ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch + patch_apply ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch + patch_apply ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch + patch_apply ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch + patch_apply ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch + patch_apply ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch ( - echo '+ { "Sebastian Lackner", "ntdll: Add support for threadpool group cancel callback.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Add support for threadpool finalization callback.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool RaceDll environment variable.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Implement TpCallbackMayRunLong and instance structure.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Implement TpDisassociateCallback.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Implement various TpCallback*OnCompletion functions.", 1 },'; + echo '+ { "Sebastian Lackner", "ntdll: Implement TpDisassociateCallback and add separate group finished event.", 1 },'; + echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for TpDisassociateCallback.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll: Add remaining threadpool functions to specfile.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool timer functions.", 2 },'; echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for Tp* threadpool functions.", 1 },';