Rebase against 8b566b1da71a412fe58c3cc1988d610c2aba5f2d.

This commit is contained in:
Sebastian Lackner
2015-07-04 04:01:01 +02:00
parent dfd86e0f91
commit cde323b772
14 changed files with 458 additions and 2065 deletions

View File

@@ -1,175 +0,0 @@
From 1651eab61e449fef2119ff35703d6c9acc43f2b3 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
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

View File

@@ -1,191 +0,0 @@
From 8041e8ccf5ed9021525a95b7c6bcedfa7d945cb4 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
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

View File

@@ -1,18 +1,66 @@
From 0aa4ad9970796cbbbe4fc5f81209e6d5d505a385 Mon Sep 17 00:00:00 2001
From c8a3a30a9d4f4a3609d59298d486b691f682390e Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 6 Feb 2015 20:09:41 +0100
Subject: ntdll/tests: Add tests for threadpool wait objects.
---
dlls/ntdll/tests/threadpool.c | 287 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 287 insertions(+)
dlls/ntdll/tests/threadpool.c | 295 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 295 insertions(+)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 4be3a8b..fd587ba 100644
index 0671202..9904d46 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -869,6 +869,291 @@ static void test_tp_window_length(void)
pTpReleasePool(pool);
@@ -24,11 +24,13 @@ static HMODULE hntdll = 0;
static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+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 NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *);
static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD);
static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *);
static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *);
+static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *);
static VOID (WINAPI *pTpPostWork)(TP_WORK *);
static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
@@ -37,8 +39,10 @@ static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *);
static VOID (WINAPI *pTpReleaseWork)(TP_WORK *);
static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG);
+static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *);
static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL);
+static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
#define NTDLL_GET_PROC(func) \
@@ -61,6 +65,7 @@ static BOOL init_threadpool(void)
NTDLL_GET_PROC(TpAllocCleanupGroup);
NTDLL_GET_PROC(TpAllocPool);
NTDLL_GET_PROC(TpAllocTimer);
+ NTDLL_GET_PROC(TpAllocWait);
NTDLL_GET_PROC(TpAllocWork);
NTDLL_GET_PROC(TpCallbackMayRunLong);
NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion);
@@ -71,11 +76,14 @@ static BOOL init_threadpool(void)
NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
NTDLL_GET_PROC(TpReleasePool);
NTDLL_GET_PROC(TpReleaseTimer);
+ NTDLL_GET_PROC(TpReleaseWait);
NTDLL_GET_PROC(TpReleaseWork);
NTDLL_GET_PROC(TpSetPoolMaxThreads);
NTDLL_GET_PROC(TpSetTimer);
+ NTDLL_GET_PROC(TpSetWait);
NTDLL_GET_PROC(TpSimpleTryPost);
NTDLL_GET_PROC(TpWaitForTimer);
+ NTDLL_GET_PROC(TpWaitForWait);
NTDLL_GET_PROC(TpWaitForWork);
if (!pTpAllocPool)
@@ -906,6 +914,291 @@ static void test_tp_window_length(void)
CloseHandle(semaphore);
}
+static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
@@ -303,15 +351,13 @@ index 4be3a8b..fd587ba 100644
START_TEST(threadpool)
{
if (!init_threadpool())
@@ -882,6 +1167,8 @@ START_TEST(threadpool)
@@ -919,4 +1212,6 @@ START_TEST(threadpool)
test_tp_disassociate();
test_tp_timer();
test_tp_window_length();
+ test_tp_wait();
+ test_tp_multi_wait();
/* FIXME: Make sure worker threads have terminated before. */
Sleep(100);
}
--
2.4.4

View File

@@ -1,4 +1,4 @@
From b32a93ef14e23672df3a11ef1e9718857c933ff9 Mon Sep 17 00:00:00 2001
From 898045c05b21aa7cbdfb168f4b4ce8ffb06b1ae0 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 6 Feb 2015 20:24:27 +0100
Subject: kernel32: Forward threadpool wait functions to ntdll.
@@ -10,7 +10,7 @@ Subject: kernel32: Forward threadpool wait functions to ntdll.
3 files changed, 51 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 337b339..146db0f 100644
index a14d03b..77e55e1 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -233,7 +233,7 @@
@@ -50,10 +50,10 @@ index 337b339..146db0f 100644
@ stdcall WaitNamedPipeA (str long)
@ stdcall WaitNamedPipeW (wstr long)
diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c
index 945fe0b..89b0b60 100644
index 21ec276..d592692 100644
--- a/dlls/kernel32/thread.c
+++ b/dlls/kernel32/thread.c
@@ -923,6 +923,27 @@ PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userd
@@ -942,6 +942,27 @@ PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userd
}
/***********************************************************************
@@ -81,9 +81,9 @@ index 945fe0b..89b0b60 100644
* CreateThreadpoolWork (KERNEL32.@)
*/
PTP_WORK WINAPI CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata,
@@ -961,3 +982,25 @@ VOID WINAPI SetThreadpoolTimer( TP_TIMER *timer, FILETIME *due_time,
@@ -1000,3 +1021,25 @@ BOOL WINAPI TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback, PVOID use
TpSetTimer( timer, due_time ? &timeout : NULL, period, window_length );
return TRUE;
}
+
+/***********************************************************************

View File

@@ -1,84 +0,0 @@
From aef4ab9059bc29f2449c7ec19cb6562896ac1708 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 08:01:00 +0100
Subject: ntdll: Add remaining threadpool functions to specfile.
---
dlls/ntdll/ntdll.spec | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index ee90705..d75efdc 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -970,24 +970,67 @@
@ stdcall RtlxOemStringToUnicodeSize(ptr) RtlOemStringToUnicodeSize
@ stdcall RtlxUnicodeStringToAnsiSize(ptr) RtlUnicodeStringToAnsiSize
@ stdcall RtlxUnicodeStringToOemSize(ptr) RtlUnicodeStringToOemSize
+# @ stub TpAllocAlpcCompletion
+# @ stub TpAllocAlpcCompletionEx
@ stdcall TpAllocCleanupGroup(ptr)
+# @ stub TpAllocIoCompletion
+# @ stub TpAllocJobNotification
@ stdcall TpAllocPool(ptr ptr)
+# @ stub TpAllocTimer
+# @ stub TpAllocWait
@ stdcall TpAllocWork(ptr ptr ptr ptr)
+# @ stub TpAlpcRegisterCompletionList
+# @ stub TpAlpcUnregisterCompletionList
+# @ stub TpCallbackDetectedUnrecoverableError
+# @ stub TpCallbackIndependent
@ stdcall TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr)
@ stdcall TpCallbackMayRunLong(ptr)
@ stdcall TpCallbackReleaseMutexOnCompletion(ptr long)
@ stdcall TpCallbackReleaseSemaphoreOnCompletion(ptr long long)
+# @ stub TpCallbackSendAlpcMessageOnCompletion
+# @ stub TpCallbackSendPendingAlpcMessage
@ stdcall TpCallbackSetEventOnCompletion(ptr long)
@ stdcall TpCallbackUnloadDllOnCompletion(ptr ptr)
+# @ stub TpCancelAsyncIoOperation
+# @ stub TpCaptureCaller
+# @ stub TpCheckTerminateWorker
+# @ stub TpDbgDumpHeapUsage
+# @ stub TpDbgSetLogRoutine
+# @ stub TpDisablePoolCallbackChecks
@ stdcall TpDisassociateCallback(ptr)
+# @ stub TpIsTimerSet
@ stdcall TpPostWork(ptr)
+# @ stub TpQueryPoolStackInformation
+# @ stub TpReleaseAlpcCompletion
@ stdcall TpReleaseCleanupGroup(ptr)
@ stdcall TpReleaseCleanupGroupMembers(ptr long ptr)
+# @ stub TpReleaseIoCompletion
+# @ stub TpReleaseJobNotification
@ stdcall TpReleasePool(ptr)
+# @ stub TpReleaseTimer
+# @ stub TpReleaseWait
@ stdcall TpReleaseWork(ptr)
+# @ stub TpSetDefaultPoolMaxThreads
+# @ stub TpSetDefaultPoolStackInformation
@ stdcall TpSetPoolMaxThreads(ptr long)
+# @ stub TpSetPoolMaxThreadsSoftLimit
@ stdcall TpSetPoolMinThreads(ptr long)
+# @ stub TpSetPoolStackInformation
+# @ stub TpSetPoolThreadBasePriority
+# @ stub TpSetPoolWorkerThreadIdleTimeout
+# @ stub TpSetTimer
+# @ stub TpSetTimerEx
+# @ stub TpSetWait
+# @ stub TpSetWaitEx
@ stdcall TpSimpleTryPost(ptr ptr ptr)
+# @ stub TpStartAsyncIoOperation
+# @ stub TpTimerOutstandingCallbackCount
+# @ stub TpTrimPools
+# @ stub TpWaitForAlpcCompletion
+# @ stub TpWaitForIoCompletion
+# @ stub TpWaitForJobNotification
+# @ stub TpWaitForTimer
+# @ stub TpWaitForWait
@ stdcall TpWaitForWork(ptr long)
@ stdcall -ret64 VerSetConditionMask(int64 long long)
@ stdcall WinSqmIsOptedIn()
--
2.4.4

View File

@@ -1,294 +0,0 @@
From 8e03c37240d2a0fafbe6347bc8d509ce5555757a Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 13:17:04 +0100
Subject: ntdll/tests: Add tests for Tp* threadpool functions.
---
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 a75b622..4be3a8b 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -22,18 +22,37 @@
static HMODULE hntdll = 0;
static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
+static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_WIN32_IO_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
+static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+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 VOID (WINAPI *pTpCallbackReleaseMutexOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE);
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 BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *);
static VOID (WINAPI *pTpPostWork)(TP_WORK *);
static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
+static VOID (WINAPI *pTpReleaseIoCompletion)(TP_IO *);
static VOID (WINAPI *pTpReleasePool)(TP_POOL *);
+static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *);
+static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *);
static VOID (WINAPI *pTpReleaseWork)(TP_WORK *);
static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
+static BOOL (WINAPI *pTpSetPoolMinThreads)(TP_POOL *,DWORD);
+static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG);
+static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *);
static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+static VOID (WINAPI *pTpStartAsyncIoOperation)(TP_IO *);
+static VOID (WINAPI *pTpWaitForIoCompletion)(TP_IO *,BOOL);
+static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL);
+static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
#define NTDLL_GET_PROC(func) \
@@ -54,18 +73,37 @@ static BOOL init_threadpool(void)
}
NTDLL_GET_PROC(TpAllocCleanupGroup);
+ NTDLL_GET_PROC(TpAllocIoCompletion);
NTDLL_GET_PROC(TpAllocPool);
+ NTDLL_GET_PROC(TpAllocTimer);
+ NTDLL_GET_PROC(TpAllocWait);
NTDLL_GET_PROC(TpAllocWork);
+ NTDLL_GET_PROC(TpCallbackLeaveCriticalSectionOnCompletion);
NTDLL_GET_PROC(TpCallbackMayRunLong);
+ NTDLL_GET_PROC(TpCallbackReleaseMutexOnCompletion);
NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion);
+ NTDLL_GET_PROC(TpCallbackSetEventOnCompletion);
+ NTDLL_GET_PROC(TpCallbackUnloadDllOnCompletion);
+ NTDLL_GET_PROC(TpCancelAsyncIoOperation);
NTDLL_GET_PROC(TpDisassociateCallback);
+ NTDLL_GET_PROC(TpIsTimerSet);
NTDLL_GET_PROC(TpPostWork);
NTDLL_GET_PROC(TpReleaseCleanupGroup);
NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
+ NTDLL_GET_PROC(TpReleaseIoCompletion);
NTDLL_GET_PROC(TpReleasePool);
+ NTDLL_GET_PROC(TpReleaseTimer);
+ NTDLL_GET_PROC(TpReleaseWait);
NTDLL_GET_PROC(TpReleaseWork);
NTDLL_GET_PROC(TpSetPoolMaxThreads);
+ NTDLL_GET_PROC(TpSetPoolMinThreads);
+ NTDLL_GET_PROC(TpSetTimer);
+ NTDLL_GET_PROC(TpSetWait);
NTDLL_GET_PROC(TpSimpleTryPost);
+ NTDLL_GET_PROC(TpStartAsyncIoOperation);
+ NTDLL_GET_PROC(TpWaitForIoCompletion);
+ NTDLL_GET_PROC(TpWaitForTimer);
+ NTDLL_GET_PROC(TpWaitForWait);
NTDLL_GET_PROC(TpWaitForWork);
if (!pTpAllocPool)
@@ -646,6 +684,191 @@ static void test_tp_disassociate(void)
CloseHandle(semaphores[1]);
}
+static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
+{
+ trace("Running timer callback\n");
+ InterlockedIncrement( (LONG *)userdata );
+}
+
+static void test_tp_timer(void)
+{
+ TP_CALLBACK_ENVIRON environment;
+ TP_TIMER *timer;
+ TP_POOL *pool;
+ NTSTATUS status;
+ LONG userdata;
+ BOOL success;
+ LARGE_INTEGER when;
+ DWORD ticks;
+
+ /* 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");
+
+ /* Allocate new timer item */
+ timer = NULL;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ status = pTpAllocTimer(&timer, timer_cb, &userdata, &environment);
+ ok(!status, "TpAllocTimer failed with status %x\n", status);
+ ok(timer != NULL, "expected timer != NULL\n");
+
+ success = pTpIsTimerSet(timer);
+ ok(!success, "expected TpIsTimerSet(...) = FALSE\n");
+
+ /* Set a relative timeout */
+ userdata = 0;
+ when.QuadPart = (ULONGLONG)500 * -10000;
+ pTpSetTimer(timer, &when, 0, 0);
+ success = pTpIsTimerSet(timer);
+ ok(success, "expected TpIsTimerSet(...) = TRUE\n");
+
+ /* Wait until timer has triggered */
+ pTpWaitForTimer(timer, FALSE);
+ Sleep(250);
+ ok(userdata == 0, "expected userdata = 0, got %u\n", userdata);
+ while (userdata == 0) Sleep(10);
+ ok(userdata == 1, "expected userdata = 1, got %u\n", userdata);
+ success = pTpIsTimerSet(timer);
+ ok(success, "expected TpIsTimerSet(...) = TRUE\n");
+
+ /* Set an absolute timeout */
+ userdata = 0;
+ NtQuerySystemTime( &when );
+ when.QuadPart += (ULONGLONG)500 * 10000;
+ pTpSetTimer(timer, &when, 0, 0);
+ success = pTpIsTimerSet(timer);
+ ok(success, "expected TpIsTimerSet(...) = TRUE\n");
+
+ /* Wait until timer has triggered */
+ pTpWaitForTimer(timer, FALSE);
+ Sleep(250);
+ ok(userdata == 0, "expected userdata = 0, got %u\n", userdata);
+ while (userdata == 0) Sleep(10);
+ ok(userdata == 1, "expected userdata = 1, got %u\n", userdata);
+ success = pTpIsTimerSet(timer);
+ ok(success, "expected TpIsTimerSet(...) = TRUE\n");
+
+ /* Test a relative timeout repeated periodically */
+ userdata = 0;
+ when.QuadPart = (ULONGLONG)50 * -10000;
+ pTpSetTimer(timer, &when, 50, 0);
+ success = pTpIsTimerSet(timer);
+ ok(success, "expected TpIsTimerSet(...) = TRUE\n");
+
+ /* Wait until the timer was triggered a couple of times */
+ ticks = GetTickCount();
+ while (userdata < 100) Sleep(10);
+ ticks = GetTickCount() - ticks;
+ pTpSetTimer(timer, NULL, 0, 0);
+ pTpWaitForTimer(timer, TRUE);
+ ok(ticks >= 4500 && ticks <= 5500, "expected approximately 5000 ticks, got %u\n", ticks);
+ success = pTpIsTimerSet(timer);
+ ok(!success, "expected TpIsTimerSet(...) = FALSE\n");
+
+ /* Test with zero timeout, we expect a call immediately */
+ userdata = 0;
+ when.QuadPart = 0;
+ pTpSetTimer(timer, &when, 0, 0);
+ success = pTpIsTimerSet(timer);
+ ok(success, "expected TpIsTimerSet(...) = TRUE\n");
+
+ /* Wait until timer has triggered */
+ pTpWaitForTimer(timer, FALSE);
+ ok(userdata == 1 || broken(userdata == 0) /* Win 8 */,
+ "expected userdata = 1, got %u\n", userdata);
+ while (userdata == 0) Sleep(10);
+ success = pTpIsTimerSet(timer);
+ ok(success, "expected TpIsTimerSet(...) = TRUE\n");
+
+ /* Unset the timer again */
+ pTpSetTimer(timer, NULL, 0, 0);
+ success = pTpIsTimerSet(timer);
+ ok(!success, "expected TpIsTimerSet(...) = FALSE\n");
+
+ /* Cleanup */
+ pTpReleaseTimer(timer);
+ pTpReleasePool(pool);
+}
+
+static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
+{
+ trace("Running window length callback\n");
+ (*(DWORD *)userdata) = GetTickCount();
+}
+
+static void test_tp_window_length(void)
+{
+ TP_CALLBACK_ENVIRON environment;
+ TP_TIMER *timer, *timer2;
+ DWORD ticks, ticks2;
+ TP_POOL *pool;
+ NTSTATUS status;
+ LARGE_INTEGER when;
+
+ /* 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");
+
+ /* Allocate two identical timers */
+ timer = NULL;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ status = pTpAllocTimer(&timer, window_length_cb, &ticks, &environment);
+ ok(!status, "TpAllocTimer failed with status %x\n", status);
+ ok(timer != NULL, "expected timer != NULL\n");
+
+ timer2 = NULL;
+ status = pTpAllocTimer(&timer2, window_length_cb, &ticks2, &environment);
+ ok(!status, "TpAllocTimer failed with status %x\n", status);
+ ok(timer2 != NULL, "expected timer2 != NULL\n");
+
+ /* Choose parameters so that timers are not merged */
+ ticks = ticks2 = 0;
+ NtQuerySystemTime( &when );
+ when.QuadPart += (ULONGLONG)500 * 10000;
+ pTpSetTimer(timer2, &when, 0, 0);
+ Sleep(50);
+ when.QuadPart -= (ULONGLONG)400 * 10000;
+ pTpSetTimer(timer, &when, 0, 200);
+ while (!ticks || !ticks2) Sleep(10);
+ ok(ticks2 >= ticks + 150, "expected that timers are not merged\n");
+
+ /* On Windows the timers also get merged in this case */
+ ticks = ticks2 = 0;
+ NtQuerySystemTime( &when );
+ when.QuadPart += (ULONGLONG)100 * 10000;
+ pTpSetTimer(timer, &when, 0, 450);
+ Sleep(50);
+ when.QuadPart += (ULONGLONG)400 * 10000;
+ pTpSetTimer(timer2, &when, 0, 0);
+ while (!ticks || !ticks2) Sleep(10);
+ todo_wine
+ ok(ticks2 >= ticks - 50 && ticks2 <= ticks + 50, "expected that timers are merged\n");
+
+ /* Timers will be merged */
+ ticks = ticks2 = 0;
+ NtQuerySystemTime( &when );
+ when.QuadPart += (ULONGLONG)500 * 10000;
+ pTpSetTimer(timer2, &when, 0, 0);
+ Sleep(50);
+ when.QuadPart -= (ULONGLONG)400 * 10000;
+ pTpSetTimer(timer, &when, 0, 450);
+ while (!ticks || !ticks2) Sleep(10);
+ ok(ticks2 >= ticks - 50 && ticks2 <= ticks + 50, "expected that timers are merged\n");
+
+ /* Cleanup */
+ pTpReleaseTimer(timer);
+ pTpReleaseTimer(timer2);
+ pTpReleasePool(pool);
+}
+
START_TEST(threadpool)
{
if (!init_threadpool())
@@ -657,4 +880,9 @@ START_TEST(threadpool)
test_tp_group_cancel();
test_tp_instance();
test_tp_disassociate();
+ test_tp_timer();
+ test_tp_window_length();
+
+ /* FIXME: Make sure worker threads have terminated before. */
+ Sleep(100);
}
--
2.4.4

View File

@@ -1,342 +0,0 @@
From 37906069933d6bd73b8c6a691292288c57b09e22 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 1 Feb 2015 19:41:13 +0100
Subject: kernel32: Forward various threadpool functions to ntdll.
---
dlls/kernel32/kernel32.spec | 48 ++++++++++----------
dlls/kernel32/tests/thread.c | 6 +--
dlls/kernel32/thread.c | 101 +++++++++++++++++++++++++++++++++++++++++++
include/winternl.h | 27 ++++++++++++
4 files changed, 155 insertions(+), 27 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 3c40975..337b339 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -204,7 +204,7 @@
@ stdcall BuildCommDCBAndTimeoutsA(str ptr ptr)
@ stdcall BuildCommDCBAndTimeoutsW(wstr ptr ptr)
@ stdcall BuildCommDCBW(wstr ptr)
-# @ stub CallbackMayRunLong
+@ stdcall CallbackMayRunLong(ptr) ntdll.TpCallbackMayRunLong
@ stdcall CallNamedPipeA(str ptr long ptr long ptr long)
@ stdcall CallNamedPipeW(wstr ptr long ptr long ptr long)
@ stub CancelDeviceWakeupRequest
@@ -228,13 +228,13 @@
# @ stub ClosePrivateNamespace
@ stdcall CloseProfileUserMapping()
@ stub CloseSystemHandle
-# @ stub CloseThreadpool
-# @ stub CloseThreadpoolCleanupGroup
-# @ stub CloseThreadpoolCleanupGroupMembers
+@ stdcall CloseThreadpool(ptr) ntdll.TpReleasePool
+@ stdcall CloseThreadpoolCleanupGroup(ptr) ntdll.TpReleaseCleanupGroup
+@ stdcall CloseThreadpoolCleanupGroupMembers(ptr long ptr) ntdll.TpReleaseCleanupGroupMembers
# @ stub CloseThreadpoolIo
-# @ stub CloseThreadpoolTimer
+@ stdcall CloseThreadpoolTimer(ptr) ntdll.TpReleaseTimer
# @ stub CloseThreadpoolWait
-# @ stub CloseThreadpoolWork
+@ stdcall CloseThreadpoolWork(ptr) ntdll.TpReleaseWork
@ stdcall CmdBatNotification(long)
@ stdcall CommConfigDialogA(str long ptr)
@ stdcall CommConfigDialogW(wstr long ptr)
@@ -331,12 +331,12 @@
@ stdcall CreateSymbolicLinkW(wstr wstr long)
@ stdcall CreateTapePartition(long long long long)
@ stdcall CreateThread(ptr long ptr long long ptr)
-# @ stub CreateThreadpool
-# @ stub CreateThreadpoolCleanupGroup
+@ stdcall CreateThreadpool(ptr)
+@ stdcall CreateThreadpoolCleanupGroup()
# @ stub CreateThreadpoolIo
-# @ stub CreateThreadpoolTimer
+@ stdcall CreateThreadpoolTimer(ptr ptr ptr)
# @ stub CreateThreadpoolWait
-# @ stub CreateThreadpoolWork
+@ stdcall CreateThreadpoolWork(ptr ptr ptr)
@ stdcall CreateTimerQueue ()
@ stdcall CreateTimerQueueTimer(ptr long ptr ptr long long long)
@ stdcall CreateToolhelp32Snapshot(long long)
@@ -369,7 +369,7 @@
@ stdcall DeleteFileW(wstr)
# @ stub DeleteProcThreadAttributeList
# @ stub DisableThreadProfiling
-# @ stub DisassociateCurrentThreadFromCallback
+@ stdcall DisassociateCurrentThreadFromCallback(ptr) ntdll.TpDisassociateCallback
@ stdcall DeleteTimerQueue(long)
@ stdcall DeleteTimerQueueEx (long long)
@ stdcall DeleteTimerQueueTimer(long long long)
@@ -495,7 +495,6 @@
@ stdcall FindFirstVolumeMountPointA(str ptr long)
@ stdcall FindFirstVolumeMountPointW(wstr ptr long)
@ stdcall FindFirstVolumeW(ptr long)
-# @ stub FreeLibraryWhenCallbackReturns
@ stdcall FindNextChangeNotification(long)
@ stdcall FindNextFileA(long ptr)
# @ stub FindNextFileNameW
@@ -533,6 +532,7 @@
@ stub -i386 FreeLSCallback
@ stdcall FreeLibrary(long)
@ stdcall FreeLibraryAndExitThread(long long)
+@ stdcall FreeLibraryWhenCallbackReturns(ptr ptr) ntdll.TpCallbackUnloadDllOnCompletion
@ stdcall FreeResource(long)
@ stdcall -i386 -private FreeSLCallback(long) krnl386.exe16.FreeSLCallback
@ stub FreeUserPhysicalPages
@@ -981,7 +981,7 @@
@ stub -i386 IsSLCallback
@ stdcall IsSystemResumeAutomatic()
@ stdcall IsThreadAFiber()
-# @ stub IsThreadpoolTimerSet
+@ stdcall IsThreadpoolTimerSet(ptr) ntdll.TpIsTimerSet
# @ stub IsTimeZoneRedirectionEnabled
# @ stub IsValidCalDateTime
@ stdcall IsValidCodePage(long)
@@ -1035,7 +1035,7 @@
@ stdcall LZSeek(long long long)
@ stdcall LZStart()
@ stdcall LeaveCriticalSection(ptr) ntdll.RtlLeaveCriticalSection
-# @ stub LeaveCriticalSectionWhenCallbackReturns
+@ stdcall LeaveCriticalSectionWhenCallbackReturns(ptr ptr) ntdll.TpCallbackLeaveCriticalSectionOnCompletion
# @ stub LoadAppInitDlls
@ stdcall LoadLibraryA(str)
@ stdcall LoadLibraryExA( str long long)
@@ -1252,9 +1252,9 @@
@ stdcall ReinitializeCriticalSection(ptr)
@ stdcall ReleaseActCtx(ptr)
@ stdcall ReleaseMutex(long)
-# @ stub ReleaseMutexWhenCallbackReturns
+@ stdcall ReleaseMutexWhenCallbackReturns(ptr long) ntdll.TpCallbackReleaseMutexOnCompletion
@ stdcall ReleaseSemaphore(long long ptr)
-# @ stub ReleaseSemaphoreWhenCallbackReturns
+@ stdcall ReleaseSemaphoreWhenCallbackReturns(ptr long long) ntdll.TpCallbackReleaseSemaphoreOnCompletion
@ stdcall ReleaseSRWLockExclusive(ptr) ntdll.RtlReleaseSRWLockExclusive
@ stdcall ReleaseSRWLockShared(ptr) ntdll.RtlReleaseSRWLockShared
@ stdcall RemoveDirectoryA(str)
@@ -1385,7 +1385,7 @@
@ stdcall SetEnvironmentVariableW(wstr wstr)
@ stdcall SetErrorMode(long)
@ stdcall SetEvent(long)
-# @ stub SetEventWhenCallbackReturns
+@ stdcall SetEventWhenCallbackReturns(ptr long) ntdll.TpCallbackSetEventOnCompletion
@ stdcall SetFileApisToANSI()
@ stdcall SetFileApisToOEM()
@ stdcall SetFileAttributesA(str long)
@@ -1454,9 +1454,9 @@
# @ stub SetThreadToken
@ stdcall SetThreadUILanguage(long)
# @ stub SetThreadpoolStackInformation
-# @ stub SetThreadpoolThreadMaximum
-# @ stub SetThreadpoolThreadMinimum
-# @ stub SetThreadpoolTimer
+@ stdcall SetThreadpoolThreadMaximum(ptr long) ntdll.TpSetPoolMaxThreads
+@ stdcall SetThreadpoolThreadMinimum(ptr long) ntdll.TpSetPoolMinThreads
+@ stdcall SetThreadpoolTimer(ptr ptr long long)
# @ stub SetThreadpoolWait
@ stdcall SetTimeZoneInformation(ptr)
@ stub SetTimerQueueTimer
@@ -1482,7 +1482,7 @@
# @ stub SortCloseHandle
# @ stub SortGetHandle
# @ stub StartThreadpoolIo
-# @ stub SubmitThreadpoolWork
+@ stdcall SubmitThreadpoolWork(ptr) ntdll.TpPostWork
@ stdcall SuspendThread(long)
@ stdcall SwitchToFiber(ptr)
@ stdcall SwitchToThread()
@@ -1509,7 +1509,7 @@
@ stdcall TryAcquireSRWLockExclusive(ptr) ntdll.RtlTryAcquireSRWLockExclusive
@ stdcall TryAcquireSRWLockShared(ptr) ntdll.RtlTryAcquireSRWLockShared
@ stdcall TryEnterCriticalSection(ptr) ntdll.RtlTryEnterCriticalSection
-# @ stub TrySubmitThreadpoolCallback
+@ stdcall TrySubmitThreadpoolCallback(ptr ptr ptr) ntdll.TpSimpleTryPost
@ stdcall TzSpecificLocalTimeToSystemTime(ptr ptr ptr)
# @ stub TzSpecificLocalTimeToSystemTimeEx
# @ stub -arch=x86_64 uaw_lstrcmpW
@@ -1571,9 +1571,9 @@
@ stdcall WaitForSingleObject(long long)
@ stdcall WaitForSingleObjectEx(long long long)
# @ stub WaitForThreadpoolIoCallbacks
-# @ stub WaitForThreadpoolTimerCallbacks
+@ stdcall WaitForThreadpoolTimerCallbacks(ptr long) ntdll.TpWaitForTimer
# @ stub WaitForThreadpoolWaitCallbacks
-# @ stub WaitForThreadpoolWorkCallbacks
+@ stdcall WaitForThreadpoolWorkCallbacks(ptr long) ntdll.TpWaitForWork
@ stdcall WaitNamedPipeA (str long)
@ stdcall WaitNamedPipeW (wstr long)
@ stdcall WakeAllConditionVariable(ptr) ntdll.RtlWakeAllConditionVariable
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c
index d3ecd2a..25801b2 100644
--- a/dlls/kernel32/tests/thread.c
+++ b/dlls/kernel32/tests/thread.c
@@ -1627,8 +1627,8 @@ static void test_threadpool(void)
int workcalled = 0;
if (!pCreateThreadpool) {
- todo_wine win_skip("thread pool apis not supported.\n");
- return;
+ win_skip("thread pool apis not supported.\n");
+ return;
}
work = pCreateThreadpoolWork(threadpool_workcallback, &workcalled, NULL);
@@ -1640,7 +1640,7 @@ static void test_threadpool(void)
ok (workcalled == 1, "expected work to be called once, got %d\n", workcalled);
pool = pCreateThreadpool(NULL);
- todo_wine ok (pool != NULL, "CreateThreadpool failed\n");
+ ok (pool != NULL, "CreateThreadpool failed\n");
}
static void test_reserved_tls(void)
diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c
index 3dabf94..945fe0b 100644
--- a/dlls/kernel32/thread.c
+++ b/dlls/kernel32/thread.c
@@ -860,3 +860,104 @@ BOOL WINAPI GetThreadPreferredUILanguages( DWORD flags, PULONG count, PCZZWSTR b
*buffersize = 0;
return TRUE;
}
+
+/***********************************************************************
+ * CreateThreadpool (KERNEL32.@)
+ */
+PTP_POOL WINAPI CreateThreadpool( PVOID reserved )
+{
+ TP_POOL *pool;
+ NTSTATUS status;
+
+ TRACE( "%p\n", reserved );
+
+ status = TpAllocPool( &pool, reserved );
+ if (status)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ return NULL;
+ }
+
+ return pool;
+}
+
+/***********************************************************************
+ * CreateThreadpoolCleanupGroup (KERNEL32.@)
+ */
+PTP_CLEANUP_GROUP WINAPI CreateThreadpoolCleanupGroup( void )
+{
+ TP_CLEANUP_GROUP *group;
+ NTSTATUS status;
+
+ TRACE( "\n" );
+
+ status = TpAllocCleanupGroup( &group );
+ if (status)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ return NULL;
+ }
+
+ return group;
+}
+
+/***********************************************************************
+ * CreateThreadpoolTimer (KERNEL32.@)
+ */
+PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userdata,
+ TP_CALLBACK_ENVIRON *environment )
+{
+ TP_TIMER *timer;
+ NTSTATUS status;
+
+ TRACE( "%p, %p, %p\n", callback, userdata, environment );
+
+ status = TpAllocTimer( &timer, callback, userdata, environment );
+ if (status)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ return NULL;
+ }
+
+ return timer;
+}
+
+/***********************************************************************
+ * CreateThreadpoolWork (KERNEL32.@)
+ */
+PTP_WORK WINAPI CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata,
+ TP_CALLBACK_ENVIRON *environment )
+{
+ TP_WORK *work;
+ NTSTATUS status;
+
+ TRACE( "%p, %p, %p\n", callback, userdata, environment );
+
+ status = TpAllocWork( &work, callback, userdata, environment );
+ if (status)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ return NULL;
+ }
+
+ return work;
+}
+
+/***********************************************************************
+ * SetThreadpoolTimer (KERNEL32.@)
+ */
+VOID WINAPI SetThreadpoolTimer( TP_TIMER *timer, FILETIME *due_time,
+ DWORD period, DWORD window_length )
+{
+ LARGE_INTEGER timeout;
+
+ TRACE( "%p, %p, %u, %u\n", timer, due_time, period, window_length );
+
+ if (due_time)
+ {
+ timeout.u.LowPart = due_time->dwLowDateTime;
+ timeout.u.HighPart = due_time->dwHighDateTime;
+ }
+
+ TpSetTimer( timer, due_time ? &timeout : NULL, period, window_length );
+}
diff --git a/include/winternl.h b/include/winternl.h
index a84c6d4..e1707fd 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -2616,6 +2616,33 @@ NTSYSAPI LONGLONG WINAPI RtlLargeIntegerSubtract(LONGLONG,LONGLONG);
NTSYSAPI NTSTATUS WINAPI RtlLargeIntegerToChar(const ULONGLONG *,ULONG,ULONG,PCHAR);
#endif
+/* Threadpool functions */
+
+NTSYSAPI NTSTATUS WINAPI TpAllocCleanupGroup(TP_CLEANUP_GROUP **);
+NTSYSAPI NTSTATUS WINAPI TpAllocPool(TP_POOL **,PVOID);
+NTSYSAPI NTSTATUS WINAPI TpAllocTimer(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+NTSYSAPI NTSTATUS WINAPI TpAllocWork(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+NTSYSAPI void WINAPI TpCallbackLeaveCriticalSectionOnCompletion(TP_CALLBACK_INSTANCE *,RTL_CRITICAL_SECTION *);
+NTSYSAPI NTSTATUS WINAPI TpCallbackMayRunLong(TP_CALLBACK_INSTANCE *);
+NTSYSAPI void WINAPI TpCallbackReleaseMutexOnCompletion(TP_CALLBACK_INSTANCE *,HANDLE);
+NTSYSAPI void WINAPI TpCallbackReleaseSemaphoreOnCompletion(TP_CALLBACK_INSTANCE *,HANDLE,DWORD);
+NTSYSAPI void WINAPI TpCallbackSetEventOnCompletion(TP_CALLBACK_INSTANCE *,HANDLE);
+NTSYSAPI void WINAPI TpCallbackUnloadDllOnCompletion(TP_CALLBACK_INSTANCE *,HMODULE);
+NTSYSAPI void WINAPI TpDisassociateCallback(TP_CALLBACK_INSTANCE *);
+NTSYSAPI BOOL WINAPI TpIsTimerSet(TP_TIMER *);
+NTSYSAPI void WINAPI TpPostWork(TP_WORK *);
+NTSYSAPI void WINAPI TpReleaseCleanupGroup(TP_CLEANUP_GROUP *);
+NTSYSAPI void WINAPI TpReleaseCleanupGroupMembers(TP_CLEANUP_GROUP *,BOOL,PVOID);
+NTSYSAPI void WINAPI TpReleasePool(TP_POOL *);
+NTSYSAPI void WINAPI TpReleaseTimer(TP_TIMER *);
+NTSYSAPI void WINAPI TpReleaseWork(TP_WORK *);
+NTSYSAPI void WINAPI TpSetPoolMaxThreads(TP_POOL *,DWORD);
+NTSYSAPI BOOL WINAPI TpSetPoolMinThreads(TP_POOL *,DWORD);
+NTSYSAPI void WINAPI TpSetTimer(TP_TIMER *, LARGE_INTEGER *,LONG,LONG);
+NTSYSAPI NTSTATUS WINAPI TpSimpleTryPost(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+NTSYSAPI void WINAPI TpWaitForTimer(TP_TIMER *,BOOL);
+NTSYSAPI void WINAPI TpWaitForWork(TP_WORK *,BOOL);
+
/* Wine internal functions */
NTSYSAPI NTSTATUS CDECL wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
--
2.4.4

View File

@@ -1,4 +1,4 @@
Fixes: [35192] Add implementation for CreateThreadpool
Fixes: [32531] Implement threadpool work items
Fixes: [37306] Implement threadpool timers
# Fixes: [35192] Add implementation for CreateThreadpool
# Fixes: [32531] Implement threadpool work items
# Fixes: [37306] Implement threadpool timers
Fixes: Implement threadpool wait objects