Rebase against 7a3c9889e38ede659230a66a167b82c024f0dc85.

This commit is contained in:
Sebastian Lackner 2015-07-01 17:09:18 +02:00
parent 62117ba8d6
commit 16aad8a55f
22 changed files with 390 additions and 1894 deletions

2
debian/changelog vendored
View File

@ -3,6 +3,8 @@ wine-staging (1.7.47) UNRELEASED; urgency=low
upstream).
* Removed patch to initialize *end with NULL on failure in msvcrt.strtod
(accepted upstream).
* Partially removed patchset for new Threadpool implementation (accepted
upstream).
-- Sebastian Lackner <sebastian@fds-team.de> Mon, 29 Jun 2015 19:39:04 +0200
wine-staging (1.7.46) unstable; urgency=low

View File

@ -1,4 +1,4 @@
From 624d6ab353109a57dfe0d80053795ef64b6adc3e Mon Sep 17 00:00:00 2001
From aec44ffb06857ee5c954136e82500e1dcb71f97b Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 06:57:53 +0100
Subject: ntdll: Add support for threadpool group cancel callback.
@ -8,10 +8,10 @@ Subject: ntdll: Add support for threadpool group cancel callback.
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 1989d56..e30d45c 100644
index da41ba0..93d9b28 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -170,6 +170,7 @@ struct threadpool_object
@@ -171,6 +171,7 @@ struct threadpool_object
struct threadpool *pool;
struct threadpool_group *group;
PVOID userdata;
@ -19,7 +19,7 @@ index 1989d56..e30d45c 100644
/* information about the group, locked via .group->cs */
struct list group_entry;
BOOL is_group_member;
@@ -1290,6 +1291,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
@@ -1370,6 +1371,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
object->pool = pool;
object->group = NULL;
object->userdata = userdata;
@ -27,25 +27,25 @@ index 1989d56..e30d45c 100644
memset( &object->group_entry, 0, sizeof(object->group_entry) );
object->is_group_member = FALSE;
@@ -1305,6 +1307,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
FIXME("unsupported environment version %u\n", environment->Version);
@@ -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");
WARN( "environment not fully implemented yet\n" );
}
@@ -1377,7 +1380,7 @@ out:
RtlLeaveCriticalSection( &pool->cs );
}
@@ -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;
@@ -1394,6 +1397,14 @@ static void tp_object_cancel( struct threadpool_object *object )
@@ -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. */
@ -56,10 +56,10 @@ index 1989d56..e30d45c 100644
+ TRACE( "callback %p returned\n", object->group_cancel_callback );
+ }
+
/* Release references */
while (pending_callbacks--)
tp_object_release( object );
@@ -1673,7 +1684,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p
}
@@ -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 )
{
@ -68,15 +68,14 @@ index 1989d56..e30d45c 100644
}
}
@@ -1791,7 +1802,7 @@ VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending )
if (this)
{
if (cancel_pending)
- tp_object_cancel( this );
+ tp_object_cancel( this, FALSE, NULL );
tp_object_wait( this );
}
@@ -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.3.3
2.4.4

View File

@ -1,448 +0,0 @@
From f8c57c8ed3616f53bbed2d794f1e858ea5051f22 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Tue, 24 Feb 2015 05:42:07 +0100
Subject: ntdll: Implement TpSimpleTryPost and basic threadpool infrastructure.
---
dlls/ntdll/ntdll.spec | 3 +
dlls/ntdll/tests/threadpool.c | 3 +-
dlls/ntdll/threadpool.c | 370 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 375 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 28165ef..cd6b97c 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -968,6 +968,9 @@
@ stdcall RtlxOemStringToUnicodeSize(ptr) RtlOemStringToUnicodeSize
@ stdcall RtlxUnicodeStringToAnsiSize(ptr) RtlUnicodeStringToAnsiSize
@ stdcall RtlxUnicodeStringToOemSize(ptr) RtlUnicodeStringToOemSize
+@ stdcall TpAllocPool(ptr ptr)
+@ stdcall TpReleasePool(ptr)
+@ stdcall TpSimpleTryPost(ptr ptr ptr)
@ stdcall -ret64 VerSetConditionMask(int64 long long)
@ stdcall WinSqmIsOptedIn()
@ stdcall ZwAcceptConnectPort(ptr long ptr long long ptr) NtAcceptConnectPort
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 2e31b34..6f164e9 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -48,7 +48,7 @@ static BOOL init_threadpool(void)
if (!pTpAllocPool)
{
- skip("Threadpool functions not supported, skipping tests\n");
+ win_skip("Threadpool functions not supported, skipping tests\n");
return FALSE;
}
@@ -105,6 +105,7 @@ static void test_tp_simple(void)
environment.Version = 9999;
environment.Pool = pool;
status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
+ todo_wine
ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */,
"TpSimpleTryPost unexpectedly returned status %x\n", status);
if (!status)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 513c13d..cc5f8e9 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -2,6 +2,7 @@
* Thread pooling
*
* Copyright (c) 2006 Robert Shearman
+ * Copyright (c) 2014-2015 Sebastian Lackner
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -37,6 +38,10 @@
WINE_DEFAULT_DEBUG_CHANNEL(threadpool);
+/*
+ * Old thread pooling API
+ */
+
#define OLD_WORKER_TIMEOUT 30000 /* 30 seconds */
#define EXPIRE_NEVER (~(ULONGLONG)0)
#define TIMER_QUEUE_MAGIC 0x516d6954 /* TimQ */
@@ -127,6 +132,64 @@ struct timer_queue
HANDLE thread;
};
+/*
+ * New object-oriented thread pooling API
+ */
+
+#define THREADPOOL_WORKER_TIMEOUT 5000
+
+/* internal threadpool representation */
+struct threadpool
+{
+ LONG refcount;
+ BOOL shutdown;
+ CRITICAL_SECTION cs;
+ /* pool of work items, locked via .cs */
+ struct list pool;
+ RTL_CONDITION_VARIABLE update_event;
+ /* information about worker threads, locked via .cs */
+ int max_workers;
+ int min_workers;
+ int num_workers;
+ int num_busy_workers;
+};
+
+enum threadpool_objtype
+{
+ TP_OBJECT_TYPE_SIMPLE
+};
+
+/* internal threadpool object representation */
+struct threadpool_object
+{
+ LONG refcount;
+ BOOL shutdown;
+ /* read-only information */
+ enum threadpool_objtype type;
+ struct threadpool *pool;
+ PVOID userdata;
+ /* information about the pool, locked via .pool->cs */
+ struct list pool_entry;
+ LONG num_pending_callbacks;
+ LONG num_running_callbacks;
+ /* arguments for callback */
+ union
+ {
+ struct
+ {
+ PTP_SIMPLE_CALLBACK callback;
+ } simple;
+ } u;
+};
+
+static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool )
+{
+ return (struct threadpool *)pool;
+}
+
+static void CALLBACK threadpool_worker_proc( void *param );
+static struct threadpool *default_threadpool = NULL;
+
static inline LONG interlocked_inc( PLONG dest )
{
return interlocked_xchg_add( dest, 1 ) + 1;
@@ -1044,3 +1107,310 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer,
return status;
}
+
+/* allocate a new threadpool (with at least one worker thread) */
+static NTSTATUS tp_threadpool_alloc( struct threadpool **out )
+{
+ struct threadpool *pool;
+ NTSTATUS status;
+ HANDLE thread;
+
+ pool = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*pool) );
+ if (!pool)
+ return STATUS_NO_MEMORY;
+
+ pool->refcount = 2; /* this thread + worker proc */
+ pool->shutdown = FALSE;
+
+ RtlInitializeCriticalSection( &pool->cs );
+ pool->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool.cs");
+
+ list_init( &pool->pool );
+ RtlInitializeConditionVariable( &pool->update_event );
+
+ pool->max_workers = 500;
+ pool->min_workers = 1;
+ pool->num_workers = 1;
+ pool->num_busy_workers = 0;
+
+ status = RtlCreateUserThread( GetCurrentProcess(), NULL, FALSE, NULL, 0, 0,
+ threadpool_worker_proc, pool, &thread, NULL );
+ if (status != STATUS_SUCCESS)
+ {
+ pool->cs.DebugInfo->Spare[0] = 0;
+ RtlDeleteCriticalSection( &pool->cs );
+ RtlFreeHeap( GetProcessHeap(), 0, pool );
+ return status;
+ }
+ NtClose( thread );
+
+ TRACE("allocated threadpool %p\n", pool);
+
+ *out = pool;
+ return STATUS_SUCCESS;
+}
+
+/* shutdown all threads of the threadpool */
+static void tp_threadpool_shutdown( struct threadpool *pool )
+{
+ assert( pool != default_threadpool );
+
+ pool->shutdown = TRUE;
+ RtlWakeAllConditionVariable( &pool->update_event );
+}
+
+/* release a reference to a threadpool */
+static BOOL tp_threadpool_release( struct threadpool *pool )
+{
+ if (interlocked_dec( &pool->refcount ))
+ return FALSE;
+
+ TRACE("destroying threadpool %p\n", pool);
+
+ assert( pool->shutdown );
+ assert( list_empty( &pool->pool ) );
+
+ pool->cs.DebugInfo->Spare[0] = 0;
+ RtlDeleteCriticalSection( &pool->cs );
+
+ RtlFreeHeap( GetProcessHeap(), 0, pool );
+ return TRUE;
+}
+
+/* returns the threadpool based on the environment structure */
+static struct threadpool *get_threadpool( TP_CALLBACK_ENVIRON *environment )
+{
+ struct threadpool *pool;
+
+ if (environment)
+ {
+ pool = (struct threadpool *)environment->Pool;
+ if (pool) return pool;
+ }
+
+ if (!default_threadpool)
+ {
+ if (tp_threadpool_alloc( &pool ) != STATUS_SUCCESS)
+ return NULL;
+
+ if (interlocked_cmpxchg_ptr( (void *)&default_threadpool, pool, NULL ) != NULL)
+ {
+ tp_threadpool_shutdown( pool );
+ tp_threadpool_release( pool );
+ }
+ }
+
+ return default_threadpool;
+}
+
+/* initializes a new threadpool object */
+static void tp_object_initialize( struct threadpool_object *object, struct threadpool *pool,
+ PVOID userdata, TP_CALLBACK_ENVIRON *environment )
+{
+ object->refcount = 1;
+ object->shutdown = FALSE;
+
+ object->pool = pool;
+ object->userdata = userdata;
+
+ memset( &object->pool_entry, 0, sizeof(object->pool_entry) );
+ object->num_pending_callbacks = 0;
+ object->num_running_callbacks = 0;
+
+ if (environment)
+ FIXME("environment not implemented yet\n");
+
+ /* Increase reference-count on the pool */
+ interlocked_inc( &pool->refcount );
+
+ TRACE("allocated object %p of type %u\n", object, object->type);
+}
+
+/* submits an object to a threadpool */
+static void tp_object_submit( struct threadpool_object *object )
+{
+ struct threadpool *pool = object->pool;
+
+ assert( !object->shutdown );
+ assert( !pool->shutdown );
+
+ RtlEnterCriticalSection( &pool->cs );
+
+ /* Start new worker threads if required (and allowed) */
+ if (pool->num_busy_workers >= pool->num_workers && pool->num_workers < pool->max_workers)
+ {
+ NTSTATUS status;
+ 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 );
+ goto out;
+ }
+ }
+
+ assert( pool->num_workers > 0 );
+ RtlWakeConditionVariable( &pool->update_event );
+
+out:
+ /* Queue work item into pool and increment refcount */
+ interlocked_inc( &object->refcount );
+ if (!object->num_pending_callbacks++)
+ list_add_tail( &pool->pool, &object->pool_entry );
+
+ RtlLeaveCriticalSection( &pool->cs );
+}
+
+/* mark an object as 'shutdown', submitting is no longer possible */
+static void tp_object_shutdown( struct threadpool_object *object )
+{
+ object->shutdown = TRUE;
+}
+
+/* release a reference to a threadpool object */
+static BOOL tp_object_release( struct threadpool_object *object )
+{
+ if (interlocked_dec( &object->refcount ))
+ return FALSE;
+
+ TRACE("destroying object %p of type %u\n", object, object->type);
+
+ assert( object->shutdown );
+ assert( !object->num_pending_callbacks );
+ assert( !object->num_running_callbacks );
+
+ /* release reference to threadpool */
+ tp_threadpool_release( object->pool );
+
+ RtlFreeHeap( GetProcessHeap(), 0, object );
+ return TRUE;
+}
+
+/* threadpool worker function */
+static void CALLBACK threadpool_worker_proc( void *param )
+{
+ struct threadpool *pool = param;
+ LARGE_INTEGER timeout;
+ struct list *ptr;
+
+ RtlEnterCriticalSection( &pool->cs );
+ for (;;)
+ {
+ while ((ptr = list_head( &pool->pool )))
+ {
+ struct threadpool_object *object = LIST_ENTRY( ptr, struct threadpool_object, pool_entry );
+ assert( object->num_pending_callbacks > 0 );
+
+ /* If further pending callbacks are queued, move the work item to
+ * the end of the pool list. Otherwise remove it from the pool. */
+ list_remove( &object->pool_entry );
+ if (--object->num_pending_callbacks)
+ list_add_tail( &pool->pool, &object->pool_entry );
+
+ /* Leave critical section and do the actual callback. */
+ object->num_running_callbacks++;
+ pool->num_busy_workers++;
+ RtlLeaveCriticalSection( &pool->cs );
+
+ 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( "callback %p returned\n", object->u.simple.callback );
+ break;
+ }
+
+ default:
+ assert(0);
+ break;
+ }
+
+ RtlEnterCriticalSection( &pool->cs );
+ pool->num_busy_workers--;
+ object->num_running_callbacks--;
+ tp_object_release( object );
+ }
+
+ /* Shutdown worker thread if requested. */
+ if (pool->shutdown)
+ break;
+
+ /* Wait for new tasks or until timeout expires. Never terminate the last worker. */
+ timeout.QuadPart = (ULONGLONG)THREADPOOL_WORKER_TIMEOUT * -10000;
+ if (RtlSleepConditionVariableCS( &pool->update_event, &pool->cs, &timeout ) == STATUS_TIMEOUT &&
+ !list_head( &pool->pool ) && pool->num_workers > 1)
+ {
+ break;
+ }
+ }
+ pool->num_workers--;
+ RtlLeaveCriticalSection( &pool->cs );
+ tp_threadpool_release( pool );
+}
+
+/***********************************************************************
+ * TpAllocPool (NTDLL.@)
+ */
+NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved )
+{
+ TRACE("%p %p\n", out, reserved);
+
+ if (reserved)
+ FIXME("reserved argument is nonzero (%p)", reserved);
+
+ if (!out)
+ return STATUS_ACCESS_VIOLATION;
+
+ return tp_threadpool_alloc( (struct threadpool **)out );
+}
+
+/***********************************************************************
+ * TpReleasePool (NTDLL.@)
+ */
+VOID WINAPI TpReleasePool( TP_POOL *pool )
+{
+ struct threadpool *this = impl_from_TP_POOL( pool );
+ TRACE("%p\n", pool);
+
+ if (this)
+ {
+ tp_threadpool_shutdown( this );
+ tp_threadpool_release( this );
+ }
+}
+
+/***********************************************************************
+ * TpSimpleTryPost (NTDLL.@)
+ */
+NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
+ TP_CALLBACK_ENVIRON *environment )
+{
+ struct threadpool_object *object;
+ struct threadpool *pool;
+
+ TRACE("%p %p %p\n", callback, userdata, environment);
+
+ if (!(pool = get_threadpool( environment )))
+ return STATUS_NO_MEMORY;
+
+ object = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*object) );
+ if (!object)
+ return STATUS_NO_MEMORY;
+
+ object->type = TP_OBJECT_TYPE_SIMPLE;
+ object->u.simple.callback = callback;
+ tp_object_initialize( object, pool, userdata, environment );
+
+ tp_object_submit( object );
+
+ tp_object_shutdown( object );
+ tp_object_release( object );
+ return STATUS_SUCCESS;
+}
--
2.3.5

View File

@ -1,4 +1,4 @@
From d92b2f79160613f6d2f258cbf98624fee30844a8 Mon Sep 17 00:00:00 2001
From 9a973853b87ff70fac8fbc42308300a861dc39de Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 07:03:15 +0100
Subject: ntdll: Add support for threadpool finalization callback.
@ -8,10 +8,10 @@ Subject: ntdll: Add support for threadpool finalization callback.
1 file changed, 12 insertions(+)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index e30d45c..927d31c 100644
index 93d9b28..0133e66 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -171,6 +171,7 @@ struct threadpool_object
@@ -172,6 +172,7 @@ struct threadpool_object
struct threadpool_group *group;
PVOID userdata;
PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback;
@ -19,7 +19,7 @@ index e30d45c..927d31c 100644
/* information about the group, locked via .group->cs */
struct list group_entry;
BOOL is_group_member;
@@ -1292,6 +1293,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
@@ -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;
@ -27,19 +27,19 @@ index e30d45c..927d31c 100644
memset( &object->group_entry, 0, sizeof(object->group_entry) );
object->is_group_member = FALSE;
@@ -1308,6 +1310,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
@@ -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");
WARN( "environment not fully implemented yet\n" );
}
@@ -1515,6 +1518,15 @@ static void CALLBACK threadpool_worker_proc( void *param )
@@ -1616,6 +1619,15 @@ static void CALLBACK threadpool_worker_proc( void *param )
break;
}
+ /* Execute finalization callback */
+ /* Execute finalization callback. */
+ if (object->finalization_callback)
+ {
+ TRACE( "executing finalization callback %p(NULL, %p)\n",
@ -52,5 +52,5 @@ index e30d45c..927d31c 100644
pool->num_busy_workers--;
object->num_running_callbacks--;
--
2.3.3
2.4.4

View File

@ -1,72 +0,0 @@
From c362c574aa6611f80c6965ea66cbfab33e421d0f Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 00:16:20 +0100
Subject: ntdll: Implement TpSetPool[Min|Max]Threads. (v2)
---
dlls/ntdll/ntdll.spec | 2 ++
dlls/ntdll/threadpool.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index cd6b97c..f755286 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -970,6 +970,8 @@
@ stdcall RtlxUnicodeStringToOemSize(ptr) RtlUnicodeStringToOemSize
@ stdcall TpAllocPool(ptr ptr)
@ stdcall TpReleasePool(ptr)
+@ stdcall TpSetPoolMaxThreads(ptr long)
+@ stdcall TpSetPoolMinThreads(ptr long)
@ stdcall TpSimpleTryPost(ptr ptr ptr)
@ stdcall -ret64 VerSetConditionMask(int64 long long)
@ stdcall WinSqmIsOptedIn()
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index cc5f8e9..cb2dcdd 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -1387,6 +1387,41 @@ VOID WINAPI TpReleasePool( TP_POOL *pool )
}
/***********************************************************************
+ * TpSetPoolMaxThreads (NTDLL.@)
+ */
+VOID WINAPI TpSetPoolMaxThreads( TP_POOL *pool, DWORD maximum )
+{
+ struct threadpool *this = impl_from_TP_POOL( pool );
+ TRACE("%p %d\n", pool, maximum);
+
+ if (this)
+ {
+ RtlEnterCriticalSection( &this->cs );
+ this->max_workers = max( maximum, 1 );
+ this->min_workers = min( this->min_workers, this->max_workers );
+ RtlLeaveCriticalSection( &this->cs );
+ }
+}
+
+/***********************************************************************
+ * TpSetPoolMinThreads (NTDLL.@)
+ */
+BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum )
+{
+ struct threadpool *this = impl_from_TP_POOL( pool );
+ FIXME("%p %d: semi-stub\n", pool, minimum);
+
+ if (this)
+ {
+ RtlEnterCriticalSection( &this->cs );
+ this->min_workers = max( minimum, 1 );
+ this->max_workers = max( this->min_workers, this->max_workers );
+ RtlLeaveCriticalSection( &this->cs );
+ }
+ return TRUE;
+}
+
+/***********************************************************************
* TpSimpleTryPost (NTDLL.@)
*/
NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
--
2.3.5

View File

@ -1,17 +1,17 @@
From a2fdd577db91938092d4c38d16a469ddf46189fb Mon Sep 17 00:00:00 2001
From 6bc11921f0b13e7029d5f42f3fd9d2c88891cd41 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 07:07:07 +0100
Subject: ntdll: Implement threadpool RaceDll environment variable.
---
dlls/ntdll/threadpool.c | 11 +++++++++++
1 file changed, 11 insertions(+)
dlls/ntdll/threadpool.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 927d31c..47f6f6f 100644
index 0133e66..4ae81b0 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -172,6 +172,7 @@ struct threadpool_object
@@ -173,6 +173,7 @@ struct threadpool_object
PVOID userdata;
PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback;
PTP_SIMPLE_CALLBACK finalization_callback;
@ -19,7 +19,7 @@ index 927d31c..47f6f6f 100644
/* information about the group, locked via .group->cs */
struct list group_entry;
BOOL is_group_member;
@@ -1294,6 +1295,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
@@ -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;
@ -27,27 +27,25 @@ index 927d31c..47f6f6f 100644
memset( &object->group_entry, 0, sizeof(object->group_entry) );
object->is_group_member = FALSE;
@@ -1311,10 +1313,15 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
@@ -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");
WARN( "environment not fully implemented yet\n" );
}
+ /* Increase dll refcount */
+ if (object->race_dll)
+ LdrAddRefDll( 0, object->race_dll );
+
/* Increase reference-count on the pool */
interlocked_inc( &pool->refcount );
TRACE( "allocated object %p of type %u\n", object, object->type );
@@ -1463,6 +1470,10 @@ static BOOL tp_object_release( struct threadpool_object *object )
/* release reference to threadpool */
tp_threadpool_release( object->pool );
/* 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 );
+ /* release reference to library */
+ if (object->race_dll)
+ LdrUnloadDll( object->race_dll );
+
@ -55,5 +53,5 @@ index 927d31c..47f6f6f 100644
return TRUE;
}
--
2.3.3
2.4.4

View File

@ -1,382 +0,0 @@
From 63ebc5c972502aaa60d50b1f6ca54f6a9646fca6 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 00:52:18 +0100
Subject: ntdll: Implement threadpool cleanup group functions.
---
dlls/ntdll/ntdll.spec | 3 +
dlls/ntdll/threadpool.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 257 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 88d915b..853ca09 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -968,7 +968,10 @@
@ stdcall RtlxOemStringToUnicodeSize(ptr) RtlOemStringToUnicodeSize
@ stdcall RtlxUnicodeStringToAnsiSize(ptr) RtlUnicodeStringToAnsiSize
@ stdcall RtlxUnicodeStringToOemSize(ptr) RtlUnicodeStringToOemSize
+@ stdcall TpAllocCleanupGroup(ptr)
@ stdcall TpAllocPool(ptr ptr)
+@ stdcall TpReleaseCleanupGroup(ptr)
+@ stdcall TpReleaseCleanupGroupMembers(ptr long ptr)
@ stdcall TpReleasePool(ptr)
@ stdcall TpSetPoolMaxThreads(ptr long)
@ stdcall TpSetPoolMinThreads(ptr long)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 16d9209..092fa6f 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -167,9 +167,14 @@ struct threadpool_object
/* read-only information */
enum threadpool_objtype type;
struct threadpool *pool;
+ struct threadpool_group *group;
PVOID userdata;
+ /* information about the group, locked via .group->cs */
+ struct list group_entry;
+ BOOL is_group_member;
/* information about the pool, locked via .pool->cs */
struct list pool_entry;
+ RTL_CONDITION_VARIABLE finished_event;
LONG num_pending_callbacks;
LONG num_running_callbacks;
/* arguments for callback */
@@ -182,12 +187,30 @@ struct threadpool_object
} u;
};
+/* internal threadpool group representation */
+struct threadpool_group
+{
+ LONG refcount;
+ BOOL shutdown;
+ CRITICAL_SECTION cs;
+ /* list of group members, locked via .cs */
+ struct list members;
+};
+
static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool )
{
return (struct threadpool *)pool;
}
+static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group )
+{
+ return (struct threadpool_group *)group;
+}
+
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 );
+static BOOL tp_object_release( struct threadpool_object *object );
static struct threadpool *default_threadpool = NULL;
static inline LONG interlocked_inc( PLONG dest )
@@ -1196,27 +1219,111 @@ static struct threadpool *get_default_threadpool( void )
return default_threadpool;
}
+/* allocates a new cleanup group */
+static NTSTATUS tp_group_alloc( struct threadpool_group **out )
+{
+ struct threadpool_group *group;
+
+ group = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*group) );
+ if (!group)
+ return STATUS_NO_MEMORY;
+
+ group->refcount = 1;
+ group->shutdown = FALSE;
+
+ RtlInitializeCriticalSection( &group->cs );
+ group->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool_group.cs");
+
+ list_init( &group->members );
+
+ TRACE("allocated group %p\n", group);
+
+ *out = group;
+ return STATUS_SUCCESS;
+}
+
+/* marks a cleanup group for shutdown */
+static void tp_group_shutdown( struct threadpool_group *group )
+{
+ group->shutdown = TRUE;
+}
+
+/* releases a reference to a cleanup group */
+static BOOL tp_group_release( struct threadpool_group *group )
+{
+ if (interlocked_dec( &group->refcount ))
+ return FALSE;
+
+ TRACE("destroying group %p\n", group);
+
+ assert( group->shutdown );
+ assert( list_empty( &group->members ) );
+
+ group->cs.DebugInfo->Spare[0] = 0;
+ RtlDeleteCriticalSection( &group->cs );
+
+ RtlFreeHeap( GetProcessHeap(), 0, group );
+ return TRUE;
+}
+
/* initializes a new threadpool object */
static void tp_object_initialize( struct threadpool_object *object, struct threadpool *pool,
PVOID userdata, TP_CALLBACK_ENVIRON *environment )
{
+ BOOL simple_cb = (object->type == TP_OBJECT_TYPE_SIMPLE);
+
object->refcount = 1;
object->shutdown = FALSE;
object->pool = pool;
+ object->group = NULL;
object->userdata = userdata;
+ memset( &object->group_entry, 0, sizeof(object->group_entry) );
+ object->is_group_member = FALSE;
+
memset( &object->pool_entry, 0, sizeof(object->pool_entry) );
+ RtlInitializeConditionVariable( &object->finished_event );
object->num_pending_callbacks = 0;
object->num_running_callbacks = 0;
if (environment)
- FIXME("environment not implemented yet\n");
+ {
+ if (environment->Version != 1)
+ FIXME("unsupported environment version %u\n", environment->Version);
+
+ object->group = impl_from_TP_CLEANUP_GROUP( environment->CleanupGroup );
+
+ WARN("environment not fully implemented yet\n");
+ }
/* Increase reference-count on the pool */
interlocked_inc( &pool->refcount );
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
+ * to the cleanup group. As soon as the cleanup group members are released ->shutdown
+ * will be set, and tp_object_submit would fail with an assertion. */
+ if (simple_cb)
+ tp_object_submit( object );
+
+ if (object->group)
+ {
+ struct threadpool_group *group = object->group;
+ interlocked_inc( &group->refcount );
+
+ RtlEnterCriticalSection( &group->cs );
+ list_add_tail( &group->members, &object->group_entry );
+ object->is_group_member = TRUE;
+ RtlLeaveCriticalSection( &group->cs );
+ }
+
+ if (simple_cb)
+ {
+ tp_object_shutdown( object );
+ tp_object_release( object );
+ }
}
/* submits an object to a threadpool */
@@ -1258,6 +1365,41 @@ out:
RtlLeaveCriticalSection( &pool->cs );
}
+static void tp_object_cancel( struct threadpool_object *object )
+{
+ struct threadpool *pool = object->pool;
+ LONG pending_callbacks = 0;
+
+ RtlEnterCriticalSection( &pool->cs );
+
+ /* Remove the pending callbacks from the pool */
+ if (object->num_pending_callbacks)
+ {
+ pending_callbacks = object->num_pending_callbacks;
+ object->num_pending_callbacks = 0;
+ list_remove( &object->pool_entry );
+ }
+
+ RtlLeaveCriticalSection( &pool->cs );
+
+ /* Release references */
+ while (pending_callbacks--)
+ tp_object_release( object );
+}
+
+static void tp_object_wait( struct threadpool_object *object )
+{
+ struct threadpool *pool = object->pool;
+
+ RtlEnterCriticalSection( &pool->cs );
+
+ /* Wait until there are no longer pending or running callbacks */
+ while (object->num_pending_callbacks || object->num_running_callbacks)
+ RtlSleepConditionVariableCS( &object->finished_event, &pool->cs, NULL );
+
+ RtlLeaveCriticalSection( &pool->cs );
+}
+
/* mark an object as 'shutdown', submitting is no longer possible */
static void tp_object_shutdown( struct threadpool_object *object )
{
@@ -1276,6 +1418,22 @@ static BOOL tp_object_release( struct threadpool_object *object )
assert( !object->num_pending_callbacks );
assert( !object->num_running_callbacks );
+ /* release reference to the group */
+ if (object->group)
+ {
+ struct threadpool_group *group = object->group;
+
+ RtlEnterCriticalSection( &group->cs );
+ if (object->is_group_member)
+ {
+ list_remove( &object->group_entry );
+ object->is_group_member = FALSE;
+ }
+ RtlLeaveCriticalSection( &group->cs );
+
+ tp_group_release( group );
+ }
+
/* release reference to threadpool */
tp_threadpool_release( object->pool );
@@ -1328,6 +1486,8 @@ 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 );
tp_object_release( object );
}
@@ -1348,6 +1508,20 @@ static void CALLBACK threadpool_worker_proc( void *param )
tp_threadpool_release( pool );
}
+
+/***********************************************************************
+ * TpAllocCleanupGroup (NTDLL.@)
+ */
+NTSTATUS WINAPI TpAllocCleanupGroup( TP_CLEANUP_GROUP **out )
+{
+ TRACE("%p\n", out);
+
+ if (!out)
+ return STATUS_ACCESS_VIOLATION;
+
+ return tp_group_alloc( (struct threadpool_group **)out );
+}
+
/***********************************************************************
* TpAllocPool (NTDLL.@)
*/
@@ -1365,6 +1539,85 @@ NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved )
}
/***********************************************************************
+ * TpReleaseCleanupGroup (NTDLL.@)
+ */
+VOID WINAPI TpReleaseCleanupGroup( TP_CLEANUP_GROUP *group )
+{
+ struct threadpool_group *this = impl_from_TP_CLEANUP_GROUP( group );
+ TRACE("%p\n", group);
+
+ if (this)
+ {
+ tp_group_shutdown( this );
+ tp_group_release( this );
+ }
+}
+
+/***********************************************************************
+ * TpReleaseCleanupGroupMembers (NTDLL.@)
+ */
+VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_pending, PVOID userdata )
+{
+ struct threadpool_group *this = impl_from_TP_CLEANUP_GROUP( group );
+ struct threadpool_object *object, *next;
+ struct list members;
+
+ TRACE("%p %d %p\n", group, cancel_pending, userdata);
+
+ if (!this)
+ return;
+
+ RtlEnterCriticalSection( &this->cs );
+
+ /* Unset group, increase references, and mark objects for shutdown */
+ LIST_FOR_EACH_ENTRY_SAFE( object, next, &this->members, struct threadpool_object, group_entry )
+ {
+ assert( object->group == this );
+ assert( object->is_group_member );
+
+ /* Simple callbacks are very special. The user doesn't hold any reference, so
+ * they would be released too early. Add one additional temporary reference. */
+ if (object->type == TP_OBJECT_TYPE_SIMPLE)
+ {
+ if (interlocked_inc( &object->refcount ) == 1)
+ {
+ /* Object is basically already destroyed, but group reference
+ * was not deleted yet. We can safely ignore this object. */
+ interlocked_dec( &object->refcount );
+ list_remove( &object->group_entry );
+ object->is_group_member = FALSE;
+ continue;
+ }
+ }
+
+ object->is_group_member = FALSE;
+ tp_object_shutdown( object );
+ }
+
+ /* Move members to a local list */
+ list_init( &members );
+ list_move_tail( &members, &this->members );
+
+ RtlLeaveCriticalSection( &this->cs );
+
+ /* Cancel pending callbacks if requested */
+ if (cancel_pending)
+ {
+ LIST_FOR_EACH_ENTRY( object, &members, struct threadpool_object, group_entry )
+ {
+ tp_object_cancel( object );
+ }
+ }
+
+ /* 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_release( object );
+ }
+}
+
+/***********************************************************************
* TpReleasePool (NTDLL.@)
*/
VOID WINAPI TpReleasePool( TP_POOL *pool )
@@ -1441,9 +1694,5 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
object->u.simple.callback = callback;
tp_object_initialize( object, pool, userdata, environment );
- tp_object_submit( object );
-
- tp_object_shutdown( object );
- tp_object_release( object );
return STATUS_SUCCESS;
}
--
2.3.3

View File

@ -1,18 +1,18 @@
From 11233cc79c1790974d7cb401e64f9f8dcc94e1f3 Mon Sep 17 00:00:00 2001
From 592d1e479946fc84440b05cc03041ccd5ba07a2b Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
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 | 103 +++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 94 insertions(+), 10 deletions(-)
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 96edd67..b7f1555 100644
index 4b5ece5..5a698c4 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -971,6 +971,7 @@
@@ -973,6 +973,7 @@
@ stdcall TpAllocCleanupGroup(ptr)
@ stdcall TpAllocPool(ptr ptr)
@ stdcall TpAllocWork(ptr ptr ptr ptr)
@ -21,10 +21,10 @@ index 96edd67..b7f1555 100644
@ stdcall TpReleaseCleanupGroup(ptr)
@ stdcall TpReleaseCleanupGroupMembers(ptr long ptr)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 47f6f6f..d1733c8 100644
index 4ae81b0..8634f44 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -172,6 +172,7 @@ struct threadpool_object
@@ -173,6 +173,7 @@ struct threadpool_object
PVOID userdata;
PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback;
PTP_SIMPLE_CALLBACK finalization_callback;
@ -32,7 +32,7 @@ index 47f6f6f..d1733c8 100644
HMODULE race_dll;
/* information about the group, locked via .group->cs */
struct list group_entry;
@@ -195,6 +196,14 @@ struct threadpool_object
@@ -196,6 +197,14 @@ struct threadpool_object
} u;
};
@ -47,7 +47,7 @@ index 47f6f6f..d1733c8 100644
/* internal threadpool group representation */
struct threadpool_group
{
@@ -222,6 +231,11 @@ static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GR
@@ -223,6 +232,11 @@ static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GR
return (struct threadpool_group *)group;
}
@ -59,7 +59,7 @@ index 47f6f6f..d1733c8 100644
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 );
@@ -1295,6 +1309,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
@@ -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;
@ -67,73 +67,24 @@ index 47f6f6f..d1733c8 100644
object->race_dll = NULL;
memset( &object->group_entry, 0, sizeof(object->group_entry) );
@@ -1313,9 +1328,14 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
@@ -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");
- WARN( "environment not fully implemented yet\n" );
+ if (environment->ActivationContext)
+ FIXME("activation context not supported yet\n");
+
+ if (environment->u.s.Persistent)
+ FIXME("persistent thread support not supported yet\n");
+ FIXME("persistent threads not supported yet\n");
}
/* Increase dll refcount */
@@ -1478,9 +1498,57 @@ static BOOL tp_object_release( struct threadpool_object *object )
return TRUE;
}
+/* initializes a threadpool instance structure */
+static void tp_instance_initialize( struct threadpool_instance *instance, struct threadpool_object *object )
+{
+ instance->object = object;
+ instance->threadid = GetCurrentThreadId();
+ instance->may_run_long = object->may_run_long;
+}
+
+/* hint for the threadpool that the execution might take long, spawn additional workers */
+static BOOL tp_instance_may_run_long( struct threadpool_instance *instance )
+{
+ struct threadpool_object *object;
+ struct threadpool *pool;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (instance->threadid != GetCurrentThreadId())
+ {
+ ERR("called from wrong thread, ignoring\n");
+ return FALSE;
+ }
+
+ if (instance->may_run_long)
+ return TRUE;
+
+ object = instance->object;
+ pool = object->pool;
+ RtlEnterCriticalSection( &pool->cs );
+
+ 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 );
+ instance->may_run_long = TRUE;
+ return !status;
+}
+
/* threadpool worker function */
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;
@ -141,12 +92,15 @@ index 47f6f6f..d1733c8 100644
struct threadpool *pool = param;
LARGE_INTEGER timeout;
struct list *ptr;
@@ -1503,23 +1571,24 @@ static void CALLBACK threadpool_worker_proc( void *param )
object->num_running_callbacks++;
@@ -1603,22 +1625,27 @@ static void CALLBACK threadpool_worker_proc( void *param )
pool->num_busy_workers++;
RtlLeaveCriticalSection( &pool->cs );
+ tp_instance_initialize( &instance, object );
+ /* 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:
@ -172,8 +126,8 @@ index 47f6f6f..d1733c8 100644
TRACE( "callback %p returned\n", object->u.work.callback );
break;
}
@@ -1532,9 +1601,9 @@ static void CALLBACK threadpool_worker_proc( void *param )
/* Execute finalization callback */
@@ -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",
@ -185,7 +139,7 @@ index 47f6f6f..d1733c8 100644
TRACE( "callback %p returned\n", object->finalization_callback );
}
@@ -1627,6 +1696,20 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us
@@ -1725,6 +1752,50 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us
}
/***********************************************************************
@ -194,12 +148,42 @@ index 47f6f6f..d1733c8 100644
+NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
+{
+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance );
+ TRACE("%p\n", instance);
+ struct threadpool_object *object = this->object;
+ struct threadpool *pool;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (!this)
+ return STATUS_ACCESS_VIOLATION;
+ TRACE( "%p\n", instance );
+
+ return tp_instance_may_run_long( this );
+ 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;
+}
+
+/***********************************************************************
@ -207,5 +191,5 @@ index 47f6f6f..d1733c8 100644
*/
VOID WINAPI TpPostWork( TP_WORK *work )
--
2.3.3
2.4.4

View File

@ -1,102 +0,0 @@
From f8532f86e968848db4b8e4f87d3556dfcaa753e8 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 01:19:41 +0100
Subject: ntdll/tests: Add tests for TpAllocCleanupGroup and related functions.
---
dlls/ntdll/tests/threadpool.c | 48 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 6f164e9..effa7fc 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -21,7 +21,10 @@
#include "ntdll_test.h"
static HMODULE hntdll = 0;
+static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
+static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
+static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
static VOID (WINAPI *pTpReleasePool)(TP_POOL *);
static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
@@ -42,7 +45,10 @@ static BOOL init_threadpool(void)
return FALSE;
}
+ NTDLL_GET_PROC(TpAllocCleanupGroup);
NTDLL_GET_PROC(TpAllocPool);
+ NTDLL_GET_PROC(TpReleaseCleanupGroup);
+ NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
NTDLL_GET_PROC(TpReleasePool);
NTDLL_GET_PROC(TpSimpleTryPost);
@@ -65,13 +71,23 @@ static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
ReleaseSemaphore(semaphore, 1, NULL);
}
+static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
+{
+ trace("Running simple2 callback\n");
+ Sleep(100);
+ InterlockedIncrement((LONG *)userdata);
+}
+
static void test_tp_simple(void)
{
TP_CALLBACK_ENVIRON environment;
+ TP_CLEANUP_GROUP *group;
HANDLE semaphore;
NTSTATUS status;
TP_POOL *pool;
+ LONG userdata;
DWORD result;
+ int i;
semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
@@ -114,7 +130,39 @@ static void test_tp_simple(void)
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
}
+ /* allocate a cleanup group for synchronization */
+ group = NULL;
+ status = pTpAllocCleanupGroup(&group);
+ ok(!status, "TpAllocCleanupGroup failed with status %x\n", status);
+ ok(group != NULL, "expected pool != NULL\n");
+
+ /* use cleanup group to wait for a simple callback */
+ userdata = 0;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ environment.CleanupGroup = group;
+ status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
+ ok(!status, "TpSimpleTryPost failed with status %x\n", status);
+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
+ ok(userdata == 1, "expected userdata = 1, got %u\n", userdata);
+
+ /* test cancellation of pending simple callbacks */
+ userdata = 0;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ environment.CleanupGroup = group;
+ for (i = 0; i < 100; i++)
+ {
+ status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
+ ok(!status, "TpSimpleTryPost failed with status %x\n", status);
+ }
+ pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
+ ok(userdata < 100, "expected userdata < 100, got %u\n", userdata);
+
/* cleanup */
+ pTpReleaseCleanupGroup(group);
pTpReleasePool(pool);
CloseHandle(semaphore);
}
--
2.3.3

View File

@ -1,18 +1,18 @@
From 472f35764b63622fd5887ac16194e8b5089f0fc6 Mon Sep 17 00:00:00 2001
From e6ab4f5a5525d2d65cafef3b45ccd156105ebe46 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 07:31:27 +0100
Subject: ntdll: Implement TpDisassociateCallback.
---
dlls/ntdll/ntdll.spec | 1 +
dlls/ntdll/threadpool.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 50 insertions(+), 3 deletions(-)
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 b7f1555..63426c5 100644
index 5a698c4..f61728f 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -972,6 +972,7 @@
@@ -974,6 +974,7 @@
@ stdcall TpAllocPool(ptr ptr)
@ stdcall TpAllocWork(ptr ptr ptr ptr)
@ stdcall TpCallbackMayRunLong(ptr)
@ -21,10 +21,10 @@ index b7f1555..63426c5 100644
@ stdcall TpReleaseCleanupGroup(ptr)
@ stdcall TpReleaseCleanupGroupMembers(ptr long ptr)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index d1733c8..4861ba6 100644
index 8634f44..6bd3206 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -201,6 +201,7 @@ struct threadpool_instance
@@ -202,6 +202,7 @@ struct threadpool_instance
{
struct threadpool_object *object;
DWORD threadid;
@ -32,45 +32,15 @@ index d1733c8..4861ba6 100644
BOOL may_run_long;
};
@@ -1503,9 +1504,37 @@ static void tp_instance_initialize( struct threadpool_instance *instance, struct
{
instance->object = object;
instance->threadid = GetCurrentThreadId();
+ instance->disassociated = FALSE;
instance->may_run_long = object->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;
+/* disassociates the current thread from the threadpool object */
+static void tp_instance_disassociate_thread( struct threadpool_instance *instance )
+{
+ struct threadpool_object *object;
+ struct threadpool *pool;
+
+ if (instance->threadid != GetCurrentThreadId())
+ {
+ ERR("called from wrong thread, ignoring\n");
+ return;
+ }
+
+ if (instance->disassociated)
+ return;
+
+ object = instance->object;
+ 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 );
+ instance->disassociated = TRUE;
+}
+
/* hint for the threadpool that the execution might take long, spawn additional workers */
static BOOL tp_instance_may_run_long( struct threadpool_instance *instance )
{
@@ -1609,9 +1638,12 @@ static void CALLBACK threadpool_worker_proc( void *param )
switch (object->type)
@@ -1666,9 +1668,12 @@ static void CALLBACK threadpool_worker_proc( void *param )
RtlEnterCriticalSection( &pool->cs );
pool->num_busy_workers--;
@ -86,7 +56,7 @@ index d1733c8..4861ba6 100644
tp_object_release( object );
}
@@ -1710,6 +1742,20 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
@@ -1796,6 +1801,37 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
}
/***********************************************************************
@ -95,12 +65,29 @@ index d1733c8..4861ba6 100644
+VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance )
+{
+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance );
+ TRACE("%p\n", instance);
+ struct threadpool_object *object = this->object;
+ struct threadpool *pool;
+
+ if (this)
+ TRACE( "%p\n", instance );
+
+ if (this->threadid != GetCurrentThreadId())
+ {
+ tp_instance_disassociate_thread( this );
+ 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;
+}
+
+/***********************************************************************
@ -108,5 +95,5 @@ index d1733c8..4861ba6 100644
*/
VOID WINAPI TpPostWork( TP_WORK *work )
--
2.3.3
2.4.4

View File

@ -1,178 +0,0 @@
From 20e50fe1839e89ef32df751130d5fc7b20ea095a Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 01:30:57 +0100
Subject: ntdll: Implement threadpool work item functions.
---
dlls/ntdll/ntdll.spec | 4 +++
dlls/ntdll/threadpool.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 97 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 7c01d43..2180ea9 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -970,12 +970,16 @@
@ stdcall RtlxUnicodeStringToOemSize(ptr) RtlUnicodeStringToOemSize
@ stdcall TpAllocCleanupGroup(ptr)
@ stdcall TpAllocPool(ptr ptr)
+@ stdcall TpAllocWork(ptr ptr ptr ptr)
+@ stdcall TpPostWork(ptr)
@ stdcall TpReleaseCleanupGroup(ptr)
@ stdcall TpReleaseCleanupGroupMembers(ptr long ptr)
@ stdcall TpReleasePool(ptr)
+@ stdcall TpReleaseWork(ptr)
@ stdcall TpSetPoolMaxThreads(ptr long)
@ stdcall TpSetPoolMinThreads(ptr long)
@ stdcall TpSimpleTryPost(ptr ptr ptr)
+@ stdcall TpWaitForWork(ptr long)
@ stdcall -ret64 VerSetConditionMask(int64 long long)
@ stdcall WinSqmIsOptedIn()
@ stdcall ZwAcceptConnectPort(ptr long ptr long long ptr) NtAcceptConnectPort
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 9e0efee..e6bb626 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -156,7 +156,8 @@ struct threadpool
enum threadpool_objtype
{
- TP_OBJECT_TYPE_SIMPLE
+ TP_OBJECT_TYPE_SIMPLE,
+ TP_OBJECT_TYPE_WORK
};
/* internal threadpool object representation */
@@ -184,6 +185,10 @@ struct threadpool_object
{
PTP_SIMPLE_CALLBACK callback;
} simple;
+ struct
+ {
+ PTP_WORK_CALLBACK callback;
+ } work;
} u;
};
@@ -202,6 +207,13 @@ static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool )
return (struct threadpool *)pool;
}
+static inline struct threadpool_object *impl_from_TP_WORK( TP_WORK *work )
+{
+ struct threadpool_object *object = (struct threadpool_object *)work;
+ assert( !object || object->type == TP_OBJECT_TYPE_WORK );
+ return object;
+}
+
static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group )
{
return (struct threadpool_group *)group;
@@ -1485,6 +1497,15 @@ static void CALLBACK threadpool_worker_proc( void *param )
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( "callback %p returned\n", object->u.work.callback );
+ break;
+ }
+
default:
assert(0);
break;
@@ -1546,6 +1567,46 @@ NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved )
}
/***********************************************************************
+ * TpAllocWork (NTDLL.@)
+ */
+NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata,
+ TP_CALLBACK_ENVIRON *environment )
+{
+ struct threadpool_object *object;
+ struct threadpool *pool;
+
+ TRACE("%p %p %p %p\n", out, callback, userdata, environment);
+
+ if (!(pool = get_threadpool( environment )))
+ return STATUS_NO_MEMORY;
+
+ object = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*object) );
+ if (!object)
+ return STATUS_NO_MEMORY;
+
+ object->type = TP_OBJECT_TYPE_WORK;
+ object->u.work.callback = callback;
+ tp_object_initialize( object, pool, userdata, environment );
+
+ *out = (TP_WORK *)object;
+ return STATUS_SUCCESS;
+}
+
+/***********************************************************************
+ * TpPostWork (NTDLL.@)
+ */
+VOID WINAPI TpPostWork( TP_WORK *work )
+{
+ struct threadpool_object *this = impl_from_TP_WORK( work );
+ TRACE("%p\n", work);
+
+ if (this)
+ {
+ tp_object_submit( this );
+ }
+}
+
+/***********************************************************************
* TpReleaseCleanupGroup (NTDLL.@)
*/
VOID WINAPI TpReleaseCleanupGroup( TP_CLEANUP_GROUP *group )
@@ -1640,6 +1701,21 @@ VOID WINAPI TpReleasePool( TP_POOL *pool )
}
/***********************************************************************
+ * TpReleaseWork (NTDLL.@)
+ */
+VOID WINAPI TpReleaseWork( TP_WORK *work )
+{
+ struct threadpool_object *this = impl_from_TP_WORK( work );
+ TRACE("%p\n", work);
+
+ if (this)
+ {
+ tp_object_shutdown( this );
+ tp_object_release( this );
+ }
+}
+
+/***********************************************************************
* TpSetPoolMaxThreads (NTDLL.@)
*/
VOID WINAPI TpSetPoolMaxThreads( TP_POOL *pool, DWORD maximum )
@@ -1698,3 +1774,19 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
return STATUS_SUCCESS;
}
+
+/***********************************************************************
+ * TpWaitForWork (NTDLL.@)
+ */
+VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending )
+{
+ struct threadpool_object *this = impl_from_TP_WORK( work );
+ TRACE("%p %d\n", work, cancel_pending);
+
+ if (this)
+ {
+ if (cancel_pending)
+ tp_object_cancel( this );
+ tp_object_wait( this );
+ }
+}
--
2.3.5

View File

@ -1,18 +1,18 @@
From 16d0eb264d85a90fa7faf1b429dec1f4efe385a2 Mon Sep 17 00:00:00 2001
From c38bf17c8f87444feca7e4ce3508e55c581671e9 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
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 | 153 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 158 insertions(+)
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 63426c5..6100a7e 100644
index f61728f..ee90705 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -971,7 +971,12 @@
@@ -973,7 +973,12 @@
@ stdcall TpAllocCleanupGroup(ptr)
@ stdcall TpAllocPool(ptr ptr)
@ stdcall TpAllocWork(ptr ptr ptr ptr)
@ -21,15 +21,15 @@ index 63426c5..6100a7e 100644
+@ stdcall TpCallbackReleaseMutexOnCompletion(ptr long)
+@ stdcall TpCallbackReleaseSemaphoreOnCompletion(ptr long long)
+@ stdcall TpCallbackSetEventOnCompletion(ptr long)
+@ stdcall TpCallbackUnloadDllOnCompletion(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 4861ba6..aa2d8e9 100644
index 6bd3206..9874315 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -203,6 +203,15 @@ struct threadpool_instance
@@ -204,6 +204,15 @@ struct threadpool_instance
DWORD threadid;
BOOL disassociated;
BOOL may_run_long;
@ -45,66 +45,61 @@ index 4861ba6..aa2d8e9 100644
};
/* internal threadpool group representation */
@@ -1506,8 +1515,50 @@ static void tp_instance_initialize( struct threadpool_instance *instance, struct
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;
}
+static NTSTATUS tp_instance_cleanup( struct threadpool_instance *instance )
+{
@@ -1604,6 +1613,7 @@ static void CALLBACK threadpool_worker_proc( void *param )
struct threadpool *pool = param;
LARGE_INTEGER timeout;
struct list *ptr;
+ NTSTATUS status;
+
+ if (instance->cleanup.critical_section)
+ {
+ RtlLeaveCriticalSection( instance->cleanup.critical_section );
+ }
+ if (instance->cleanup.mutex)
+ {
+ status = NtReleaseMutant( instance->cleanup.mutex, NULL );
+ if (status != STATUS_SUCCESS)
+ return status;
+ }
+ if (instance->cleanup.semaphore)
+ {
+ status = NtReleaseSemaphore( instance->cleanup.semaphore, instance->cleanup.semaphore_count, NULL );
+ if (status != STATUS_SUCCESS)
+ return status;
+ }
+ if (instance->cleanup.event)
+ {
+ status = NtSetEvent( instance->cleanup.event, NULL );
+ if (status != STATUS_SUCCESS)
+ return status;
+ }
+ if (instance->cleanup.library)
+ {
+ status = LdrUnloadDll( instance->cleanup.library );
+ if (status != STATUS_SUCCESS)
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
/* disassociates the current thread from the threadpool object */
static void tp_instance_disassociate_thread( struct threadpool_instance *instance )
{
@@ -1636,6 +1687,7 @@ static void CALLBACK threadpool_worker_proc( void *param )
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 );
}
+ tp_instance_cleanup( &instance );
+ /* 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)
@@ -1728,6 +1780,26 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us
@@ -1757,6 +1799,19 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us
}
/***********************************************************************
@ -113,25 +108,18 @@ index 4861ba6..aa2d8e9 100644
+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)
+ return;
+ TRACE( "%p %p\n", instance, crit );
+
+ if (this->cleanup.critical_section)
+ {
+ FIXME("attempt to set multiple cleanup critical sections\n");
+ return;
+ }
+
+ this->cleanup.critical_section = crit;
+ if (!this->cleanup.critical_section)
+ this->cleanup.critical_section = crit;
+}
+
+/***********************************************************************
* TpCallbackMayRunLong (NTDLL.@)
*/
NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
@@ -1742,6 +1814,87 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
@@ -1801,6 +1856,61 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
}
/***********************************************************************
@ -140,18 +128,11 @@ index 4861ba6..aa2d8e9 100644
+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)
+ return;
+ TRACE( "%p %p\n", instance, mutex );
+
+ if (this->cleanup.mutex)
+ {
+ FIXME("attempt to set multiple cleanup mutexes\n");
+ return;
+ }
+
+ this->cleanup.mutex = mutex;
+ if (!this->cleanup.mutex)
+ this->cleanup.mutex = mutex;
+}
+
+/***********************************************************************
@ -160,19 +141,14 @@ index 4861ba6..aa2d8e9 100644
+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)
+ return;
+ TRACE( "%p %p %u\n", instance, semaphore, count );
+
+ if (this->cleanup.semaphore)
+ if (!this->cleanup.semaphore)
+ {
+ FIXME("attempt to set multiple cleanup semaphores\n");
+ return;
+ this->cleanup.semaphore = semaphore;
+ this->cleanup.semaphore_count = count;
+ }
+
+ this->cleanup.semaphore = semaphore;
+ this->cleanup.semaphore_count = count;
+}
+
+/***********************************************************************
@ -181,18 +157,11 @@ index 4861ba6..aa2d8e9 100644
+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)
+ return;
+ TRACE( "%p %p\n", instance, event );
+
+ if (this->cleanup.event)
+ {
+ FIXME("attempt to set multiple cleanup events\n");
+ return;
+ }
+
+ this->cleanup.event = event;
+ if (!this->cleanup.event)
+ this->cleanup.event = event;
+}
+
+/***********************************************************************
@ -201,18 +170,11 @@ index 4861ba6..aa2d8e9 100644
+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)
+ return;
+ TRACE( "%p %p\n", instance, module );
+
+ if (this->cleanup.library)
+ {
+ FIXME("attempt to set multiple cleanup libraries\n");
+ return;
+ }
+
+ this->cleanup.library = module;
+ if (!this->cleanup.library)
+ this->cleanup.library = module;
+}
+
+/***********************************************************************
@ -220,5 +182,5 @@ index 4861ba6..aa2d8e9 100644
*/
VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance )
--
2.3.3
2.4.4

View File

@ -1,108 +0,0 @@
From a0ad4f0f9186dbce96da918255f2c0cd5f4aae7f Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 01:38:23 +0100
Subject: ntdll/tests: Add basic tests for threadpool work items.
---
dlls/ntdll/tests/threadpool.c | 59 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index effa7fc..420979c 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -23,10 +23,14 @@
static HMODULE hntdll = 0;
static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
+static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+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 *pTpReleasePool)(TP_POOL *);
+static VOID (WINAPI *pTpReleaseWork)(TP_WORK *);
static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
#define NTDLL_GET_PROC(func) \
do \
@@ -47,10 +51,14 @@ static BOOL init_threadpool(void)
NTDLL_GET_PROC(TpAllocCleanupGroup);
NTDLL_GET_PROC(TpAllocPool);
+ NTDLL_GET_PROC(TpAllocWork);
+ NTDLL_GET_PROC(TpPostWork);
NTDLL_GET_PROC(TpReleaseCleanupGroup);
NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
NTDLL_GET_PROC(TpReleasePool);
+ NTDLL_GET_PROC(TpReleaseWork);
NTDLL_GET_PROC(TpSimpleTryPost);
+ NTDLL_GET_PROC(TpWaitForWork);
if (!pTpAllocPool)
{
@@ -167,10 +175,61 @@ static void test_tp_simple(void)
CloseHandle(semaphore);
}
+static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
+{
+ trace("Running work callback\n");
+ Sleep(10);
+ InterlockedIncrement((LONG *)userdata);
+}
+
+static void test_tp_work(void)
+{
+ TP_CALLBACK_ENVIRON environment;
+ TP_WORK *work;
+ TP_POOL *pool;
+ NTSTATUS status;
+ LONG userdata;
+ 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");
+
+ /* allocate new work item */
+ work = NULL;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ 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 = 0;
+ for (i = 0; i < 10; i++)
+ pTpPostWork(work);
+ pTpWaitForWork(work, FALSE);
+ ok(userdata == 10, "expected userdata = 10, got %u\n", userdata);
+
+ /* add more tasks and cancel them immediately */
+ userdata = 0;
+ for (i = 0; i < 10; i++)
+ pTpPostWork(work);
+ pTpWaitForWork(work, TRUE);
+ ok(userdata < 10, "expected userdata < 10, got %u\n", userdata);
+
+ /* cleanup */
+ pTpReleaseWork(work);
+ pTpReleasePool(pool);
+}
+
START_TEST(threadpool)
{
if (!init_threadpool())
return;
test_tp_simple();
+ test_tp_work();
}
--
2.3.3

View File

@ -1,4 +1,4 @@
From 01b8c400e280f1c033878cdc16f902a4c47c82df Mon Sep 17 00:00:00 2001
From 75e6178d889b0883a03119d372858751d130b751 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.
@ -8,10 +8,10 @@ Subject: ntdll: Add remaining threadpool functions to specfile.
1 file changed, 43 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index c42356c..681c75e 100644
index ee90705..d75efdc 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -968,24 +968,67 @@
@@ -970,24 +970,67 @@
@ stdcall RtlxOemStringToUnicodeSize(ptr) RtlOemStringToUnicodeSize
@ stdcall RtlxUnicodeStringToAnsiSize(ptr) RtlUnicodeStringToAnsiSize
@ stdcall RtlxUnicodeStringToOemSize(ptr) RtlUnicodeStringToOemSize
@ -35,7 +35,7 @@ index c42356c..681c75e 100644
+# @ stub TpCallbackSendAlpcMessageOnCompletion
+# @ stub TpCallbackSendPendingAlpcMessage
@ stdcall TpCallbackSetEventOnCompletion(ptr long)
@ stdcall TpCallbackUnloadDllOnCompletion(ptr long)
@ stdcall TpCallbackUnloadDllOnCompletion(ptr ptr)
+# @ stub TpCancelAsyncIoOperation
+# @ stub TpCaptureCaller
+# @ stub TpCheckTerminateWorker
@ -80,5 +80,5 @@ index c42356c..681c75e 100644
@ stdcall -ret64 VerSetConditionMask(int64 long long)
@ stdcall WinSqmIsOptedIn()
--
2.3.5
2.4.4

View File

@ -1,132 +0,0 @@
From 792ceb3a01f63e523811d42d7a28f6e31a70e2f7 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 01:45:11 +0100
Subject: ntdll/tests: Add threadpool scheduler tests for work items.
---
dlls/ntdll/tests/threadpool.c | 83 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 420979c..1cfd67b 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -29,6 +29,7 @@ static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
static VOID (WINAPI *pTpReleasePool)(TP_POOL *);
static VOID (WINAPI *pTpReleaseWork)(TP_WORK *);
+static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
@@ -57,6 +58,7 @@ static BOOL init_threadpool(void)
NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
NTDLL_GET_PROC(TpReleasePool);
NTDLL_GET_PROC(TpReleaseWork);
+ NTDLL_GET_PROC(TpSetPoolMaxThreads);
NTDLL_GET_PROC(TpSimpleTryPost);
NTDLL_GET_PROC(TpWaitForWork);
@@ -182,6 +184,13 @@ static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_
InterlockedIncrement((LONG *)userdata);
}
+static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
+{
+ trace("Running work2 callback\n");
+ Sleep(10);
+ InterlockedExchangeAdd((LONG *)userdata, 0x10000);
+}
+
static void test_tp_work(void)
{
TP_CALLBACK_ENVIRON environment;
@@ -225,6 +234,79 @@ static void test_tp_work(void)
pTpReleasePool(pool);
}
+static void test_tp_work_scheduler(void)
+{
+ TP_CALLBACK_ENVIRON environment;
+ TP_CLEANUP_GROUP *group;
+ TP_WORK *work, *work2;
+ TP_POOL *pool;
+ NTSTATUS status;
+ LONG userdata;
+ 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);
+
+ /* create a cleanup group */
+ group = NULL;
+ status = pTpAllocCleanupGroup(&group);
+ ok(!status, "TpAllocCleanupGroup failed with status %x\n", status);
+ ok(group != NULL, "expected pool != NULL\n");
+
+ /* the first work item has no cleanup group associated */
+ work = NULL;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ status = pTpAllocWork(&work, work_cb, &userdata, &environment);
+ ok(!status, "TpAllocWork failed with status %x\n", status);
+ ok(work != NULL, "expected work != NULL\n");
+
+ /* allocate a second work item with a cleanup group */
+ work2 = NULL;
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ environment.CleanupGroup = group;
+ status = pTpAllocWork(&work2, work2_cb, &userdata, &environment);
+ ok(!status, "TpAllocWork failed with status %x\n", status);
+ ok(work2 != NULL, "expected work2 != NULL\n");
+
+ /* the 'work' callbacks are not blocking execution of 'work2' callbacks */
+ userdata = 0;
+ for (i = 0; i < 10; i++)
+ pTpPostWork(work);
+ for (i = 0; i < 10; i++)
+ pTpPostWork(work2);
+ Sleep(30);
+ pTpWaitForWork(work, TRUE);
+ pTpWaitForWork(work2, TRUE);
+ ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %u\n", userdata & 0xffff);
+ ok(userdata >> 16, "expected userdata >> 16 != 0, got %u\n", userdata >> 16);
+
+ /* test ReleaseCleanupGroupMembers on a work item */
+ userdata = 0;
+ for (i = 0; i < 100; i++)
+ pTpPostWork(work);
+ for (i = 0; i < 10; i++)
+ pTpPostWork(work2);
+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
+ pTpWaitForWork(work, TRUE);
+ ok((userdata & 0xffff) < 100, "expected userdata & 0xffff < 100, got %u\n", userdata & 0xffff);
+ ok((userdata >> 16) == 10, "expected userdata >> 16 == 10, got %u\n", userdata >> 16);
+
+ /* cleanup */
+ pTpReleaseWork(work);
+ pTpReleaseCleanupGroup(group);
+ pTpReleasePool(pool);
+}
+
START_TEST(threadpool)
{
if (!init_threadpool())
@@ -232,4 +314,5 @@ START_TEST(threadpool)
test_tp_simple();
test_tp_work();
+ test_tp_work_scheduler();
}
--
2.3.3

View File

@ -1,4 +1,4 @@
From 90370a65b5f492ebe3fafb5e35548eb4b6681dac Mon Sep 17 00:00:00 2001
From 04e6df6c221a7f6fc57cfb431d889e62fe64fc47 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 08:19:47 +0100
Subject: ntdll: Implement threadpool timer functions. (rev 2)
@ -9,10 +9,10 @@ Subject: ntdll: Implement threadpool timer functions. (rev 2)
2 files changed, 380 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 19e63a5..7aa8bda 100644
index d75efdc..0f4374e 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -974,7 +974,7 @@
@@ -976,7 +976,7 @@
# @ stub TpAllocIoCompletion
# @ stub TpAllocJobNotification
@ stdcall TpAllocPool(ptr ptr)
@ -21,7 +21,7 @@ index 19e63a5..7aa8bda 100644
# @ stub TpAllocWait
@ stdcall TpAllocWork(ptr ptr ptr ptr)
# @ stub TpAlpcRegisterCompletionList
@@ -996,7 +996,7 @@
@@ -998,7 +998,7 @@
# @ stub TpDbgSetLogRoutine
# @ stub TpDisablePoolCallbackChecks
@ stdcall TpDisassociateCallback(ptr)
@ -30,7 +30,7 @@ index 19e63a5..7aa8bda 100644
@ stdcall TpPostWork(ptr)
# @ stub TpQueryPoolStackInformation
# @ stub TpReleaseAlpcCompletion
@@ -1005,7 +1005,7 @@
@@ -1007,7 +1007,7 @@
# @ stub TpReleaseIoCompletion
# @ stub TpReleaseJobNotification
@ stdcall TpReleasePool(ptr)
@ -39,7 +39,7 @@ index 19e63a5..7aa8bda 100644
# @ stub TpReleaseWait
@ stdcall TpReleaseWork(ptr)
# @ stub TpSetDefaultPoolMaxThreads
@@ -1016,7 +1016,7 @@
@@ -1018,7 +1018,7 @@
# @ stub TpSetPoolStackInformation
# @ stub TpSetPoolThreadBasePriority
# @ stub TpSetPoolWorkerThreadIdleTimeout
@ -48,7 +48,7 @@ index 19e63a5..7aa8bda 100644
# @ stub TpSetTimerEx
# @ stub TpSetWait
# @ stub TpSetWaitEx
@@ -1027,7 +1027,7 @@
@@ -1029,7 +1029,7 @@
# @ stub TpWaitForAlpcCompletion
# @ stub TpWaitForIoCompletion
# @ stub TpWaitForJobNotification
@ -58,10 +58,10 @@ index 19e63a5..7aa8bda 100644
@ stdcall TpWaitForWork(ptr long)
@ stdcall -ret64 VerSetConditionMask(int64 long long)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 351c1bd..493e0af 100644
index 9874315..f4c9cba 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -157,7 +157,8 @@ struct threadpool
@@ -158,7 +158,8 @@ struct threadpool
enum threadpool_objtype
{
TP_OBJECT_TYPE_SIMPLE,
@ -71,7 +71,7 @@ index 351c1bd..493e0af 100644
};
/* internal threadpool object representation */
@@ -193,6 +194,18 @@ struct threadpool_object
@@ -194,6 +195,18 @@ struct threadpool_object
{
PTP_WORK_CALLBACK callback;
} work;
@ -90,7 +90,7 @@ index 351c1bd..493e0af 100644
} u;
};
@@ -224,6 +237,33 @@ struct threadpool_group
@@ -225,6 +238,33 @@ struct threadpool_group
struct list members;
};
@ -124,21 +124,21 @@ index 351c1bd..493e0af 100644
static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool )
{
return (struct threadpool *)pool;
@@ -236,6 +276,13 @@ static inline struct threadpool_object *impl_from_TP_WORK( TP_WORK *work )
@@ -237,6 +277,13 @@ static inline struct threadpool_object *impl_from_TP_WORK( TP_WORK *work )
return object;
}
+static inline struct threadpool_object *impl_from_TP_TIMER( TP_TIMER *timer )
+{
+ struct threadpool_object *object = (struct threadpool_object *)timer;
+ assert( !object || object->type == TP_OBJECT_TYPE_TIMER );
+ assert( object->type == TP_OBJECT_TYPE_TIMER );
+ return object;
+}
+
static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group )
{
return (struct threadpool_group *)group;
@@ -247,6 +294,7 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL
@@ -248,6 +295,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 351c1bd..493e0af 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 );
@@ -1170,6 +1218,230 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer,
@@ -1171,6 +1219,230 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer,
return status;
}
@ -374,11 +374,11 @@ index 351c1bd..493e0af 100644
+ RtlLeaveCriticalSection( &timerqueue.cs );
+}
+
/* allocate a new threadpool (with at least one worker thread) */
static NTSTATUS tp_threadpool_alloc( struct threadpool **out )
{
@@ -1473,6 +1745,9 @@ static void tp_object_wait( struct threadpool_object *object )
/* mark an object as 'shutdown', submitting is no longer possible */
/***********************************************************************
* tp_threadpool_alloc (internal)
*
@@ -1559,6 +1831,9 @@ static void tp_object_wait( struct threadpool_object *object )
*/
static void tp_object_shutdown( struct threadpool_object *object )
{
+ if (object->type == TP_OBJECT_TYPE_TIMER)
@ -387,7 +387,7 @@ index 351c1bd..493e0af 100644
object->shutdown = TRUE;
}
@@ -1680,6 +1955,15 @@ static void CALLBACK threadpool_worker_proc( void *param )
@@ -1668,6 +1943,15 @@ static void CALLBACK threadpool_worker_proc( void *param )
break;
}
@ -403,7 +403,7 @@ index 351c1bd..493e0af 100644
default:
assert(0);
break;
@@ -1754,6 +2038,41 @@ NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved )
@@ -1768,6 +2052,46 @@ NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved )
}
/***********************************************************************
@ -416,21 +416,26 @@ index 351c1bd..493e0af 100644
+ struct threadpool *pool;
+ NTSTATUS status;
+
+ TRACE("%p %p %p %p\n", out, callback, userdata, environment);
+
+ if (!(pool = get_threadpool( environment )))
+ return STATUS_NO_MEMORY;
+ TRACE( "%p %p %p %p\n", out, callback, userdata, environment );
+
+ object = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*object) );
+ if (!object)
+ return STATUS_NO_MEMORY;
+
+ status = tp_threadpool_lock( &pool, environment );
+ if (status)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, object );
+ return status;
+ }
+
+ object->type = TP_OBJECT_TYPE_TIMER;
+ object->u.timer.callback = callback;
+
+ status = tp_timerqueue_acquire( object );
+ if (status)
+ {
+ tp_threadpool_unlock( pool );
+ RtlFreeHeap( GetProcessHeap(), 0, object );
+ return status;
+ }
@ -445,7 +450,7 @@ index 351c1bd..493e0af 100644
* TpAllocWork (NTDLL.@)
*/
NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata,
@@ -1909,6 +2228,17 @@ VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance )
@@ -1942,6 +2266,17 @@ VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance )
}
/***********************************************************************
@ -454,16 +459,16 @@ index 351c1bd..493e0af 100644
+BOOL WINAPI TpIsTimerSet( TP_TIMER *timer )
+{
+ struct threadpool_object *this = impl_from_TP_TIMER( timer );
+ TRACE("%p\n", timer);
+ TRACE( "%p\n", timer );
+
+ return this ? this->u.timer.timer_set : FALSE;
+ return this->u.timer.timer_set;
+}
+
+/***********************************************************************
* TpPostWork (NTDLL.@)
*/
VOID WINAPI TpPostWork( TP_WORK *work )
@@ -2017,6 +2347,21 @@ VOID WINAPI TpReleasePool( TP_POOL *pool )
@@ -2041,6 +2376,19 @@ VOID WINAPI TpReleasePool( TP_POOL *pool )
}
/***********************************************************************
@ -472,20 +477,18 @@ index 351c1bd..493e0af 100644
+VOID WINAPI TpReleaseTimer( TP_TIMER *timer )
+{
+ struct threadpool_object *this = impl_from_TP_TIMER( timer );
+ TRACE("%p\n", timer);
+
+ if (this)
+ {
+ tp_object_shutdown( this );
+ tp_object_release( this );
+ }
+ TRACE( "%p\n", timer );
+
+ tp_object_shutdown( this );
+ tp_object_release( this );
+}
+
+/***********************************************************************
* TpReleaseWork (NTDLL.@)
*/
VOID WINAPI TpReleaseWork( TP_WORK *work )
@@ -2065,6 +2410,20 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum )
@@ -2104,6 +2452,18 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum )
}
/***********************************************************************
@ -494,19 +497,17 @@ index 351c1bd..493e0af 100644
+VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LONG window_length )
+{
+ struct threadpool_object *this = impl_from_TP_TIMER( timer );
+ TRACE("%p %p %u %u\n", timer, timeout, period, window_length);
+
+ if (this)
+ {
+ tp_timerqueue_update_timer( this, timeout, period, window_length );
+ }
+ TRACE( "%p %p %u %u\n", timer, timeout, period, window_length );
+
+ tp_timerqueue_update_timer( this, timeout, period, window_length );
+}
+
+/***********************************************************************
* TpSimpleTryPost (NTDLL.@)
*/
NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
@@ -2090,6 +2449,21 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
@@ -2134,6 +2494,20 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
}
/***********************************************************************
@ -515,13 +516,12 @@ index 351c1bd..493e0af 100644
+VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending )
+{
+ struct threadpool_object *this = impl_from_TP_TIMER( timer );
+ TRACE("%p %d\n", timer, cancel_pending);
+ if (this)
+ {
+ if (cancel_pending)
+ tp_object_cancel( this, FALSE, NULL );
+ tp_object_wait( this );
+ }
+
+ TRACE( "%p %d\n", timer, cancel_pending );
+
+ if (cancel_pending)
+ tp_object_cancel( this, FALSE, NULL );
+ tp_object_wait( this );
+}
+
+/***********************************************************************
@ -529,5 +529,5 @@ index 351c1bd..493e0af 100644
*/
VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending )
--
2.3.3
2.4.4

View File

@ -1,4 +1,4 @@
From 4a3ad1401f815720b35b0ab48e6ab1cc08835f5e Mon Sep 17 00:00:00 2001
From 8d1fba2b1f7b014130cfb64447cba2c2d257864a 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.
@ -8,7 +8,7 @@ Subject: ntdll/tests: Add tests for Tp* threadpool functions.
1 file changed, 470 insertions(+)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 1cfd67b..b44b0f5 100644
index b261cd1..76db2d0 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -22,15 +22,37 @@
@ -526,5 +526,5 @@ index 1cfd67b..b44b0f5 100644
+ Sleep(100);
}
--
2.3.3
2.4.4

View File

@ -1,4 +1,4 @@
From 6a7aaa0145d32fde06229bae7f8cb879ea2ac182 Mon Sep 17 00:00:00 2001
From e6dda25c2975565acf141011fba0694b27c8c8a0 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.
@ -11,7 +11,7 @@ Subject: kernel32: Forward various threadpool functions to ntdll.
4 files changed, 155 insertions(+), 27 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 1179af2..f65f894 100644
index 3c40975..337b339 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -204,7 +204,7 @@
@ -84,7 +84,7 @@ index 1179af2..f65f894 100644
@ stdcall FreeResource(long)
@ stdcall -i386 -private FreeSLCallback(long) krnl386.exe16.FreeSLCallback
@ stub FreeUserPhysicalPages
@@ -980,7 +980,7 @@
@@ -981,7 +981,7 @@
@ stub -i386 IsSLCallback
@ stdcall IsSystemResumeAutomatic()
@ stdcall IsThreadAFiber()
@ -93,7 +93,7 @@ index 1179af2..f65f894 100644
# @ stub IsTimeZoneRedirectionEnabled
# @ stub IsValidCalDateTime
@ stdcall IsValidCodePage(long)
@@ -1034,7 +1034,7 @@
@@ -1035,7 +1035,7 @@
@ stdcall LZSeek(long long long)
@ stdcall LZStart()
@ stdcall LeaveCriticalSection(ptr) ntdll.RtlLeaveCriticalSection
@ -102,7 +102,7 @@ index 1179af2..f65f894 100644
# @ stub LoadAppInitDlls
@ stdcall LoadLibraryA(str)
@ stdcall LoadLibraryExA( str long long)
@@ -1251,9 +1251,9 @@
@@ -1252,9 +1252,9 @@
@ stdcall ReinitializeCriticalSection(ptr)
@ stdcall ReleaseActCtx(ptr)
@ stdcall ReleaseMutex(long)
@ -114,7 +114,7 @@ index 1179af2..f65f894 100644
@ stdcall ReleaseSRWLockExclusive(ptr) ntdll.RtlReleaseSRWLockExclusive
@ stdcall ReleaseSRWLockShared(ptr) ntdll.RtlReleaseSRWLockShared
@ stdcall RemoveDirectoryA(str)
@@ -1384,7 +1384,7 @@
@@ -1385,7 +1385,7 @@
@ stdcall SetEnvironmentVariableW(wstr wstr)
@ stdcall SetErrorMode(long)
@ stdcall SetEvent(long)
@ -123,7 +123,7 @@ index 1179af2..f65f894 100644
@ stdcall SetFileApisToANSI()
@ stdcall SetFileApisToOEM()
@ stdcall SetFileAttributesA(str long)
@@ -1453,9 +1453,9 @@
@@ -1454,9 +1454,9 @@
# @ stub SetThreadToken
@ stdcall SetThreadUILanguage(long)
# @ stub SetThreadpoolStackInformation
@ -136,7 +136,7 @@ index 1179af2..f65f894 100644
# @ stub SetThreadpoolWait
@ stdcall SetTimeZoneInformation(ptr)
@ stub SetTimerQueueTimer
@@ -1481,7 +1481,7 @@
@@ -1482,7 +1482,7 @@
# @ stub SortCloseHandle
# @ stub SortGetHandle
# @ stub StartThreadpoolIo
@ -145,7 +145,7 @@ index 1179af2..f65f894 100644
@ stdcall SuspendThread(long)
@ stdcall SwitchToFiber(ptr)
@ stdcall SwitchToThread()
@@ -1508,7 +1508,7 @@
@@ -1509,7 +1509,7 @@
@ stdcall TryAcquireSRWLockExclusive(ptr) ntdll.RtlTryAcquireSRWLockExclusive
@ stdcall TryAcquireSRWLockShared(ptr) ntdll.RtlTryAcquireSRWLockShared
@ stdcall TryEnterCriticalSection(ptr) ntdll.RtlTryEnterCriticalSection
@ -154,7 +154,7 @@ index 1179af2..f65f894 100644
@ stdcall TzSpecificLocalTimeToSystemTime(ptr ptr ptr)
# @ stub TzSpecificLocalTimeToSystemTimeEx
# @ stub -arch=x86_64 uaw_lstrcmpW
@@ -1570,9 +1570,9 @@
@@ -1571,9 +1571,9 @@
@ stdcall WaitForSingleObject(long long)
@ stdcall WaitForSingleObjectEx(long long long)
# @ stub WaitForThreadpoolIoCallbacks
@ -300,10 +300,10 @@ index 3dabf94..945fe0b 100644
+ TpSetTimer( timer, due_time ? &timeout : NULL, period, window_length );
+}
diff --git a/include/winternl.h b/include/winternl.h
index f88001f..4f16d24 100644
index a84c6d4..e1707fd 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -2596,6 +2596,33 @@ NTSYSAPI LONGLONG WINAPI RtlLargeIntegerSubtract(LONGLONG,LONGLONG);
@@ -2616,6 +2616,33 @@ NTSYSAPI LONGLONG WINAPI RtlLargeIntegerSubtract(LONGLONG,LONGLONG);
NTSYSAPI NTSTATUS WINAPI RtlLargeIntegerToChar(const ULONGLONG *,ULONG,ULONG,PCHAR);
#endif
@ -338,5 +338,5 @@ index f88001f..4f16d24 100644
NTSYSAPI NTSTATUS CDECL wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
--
2.3.3
2.4.4

View File

@ -1,4 +1,4 @@
From 8e1c71f635b4005958e8f8b3a8b3bd654367f71c Mon Sep 17 00:00:00 2001
From 008bb589716259fa962bdff580d5ec436bbf8ce4 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Mar 2015 13:33:25 +0100
Subject: ntdll: Implement threadpool wait objects.
@ -9,10 +9,10 @@ Subject: ntdll: Implement threadpool wait objects.
2 files changed, 469 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 21f39de..9093eb8 100644
index 0f4374e..ffcf58d 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -975,7 +975,7 @@
@@ -977,7 +977,7 @@
# @ stub TpAllocJobNotification
@ stdcall TpAllocPool(ptr ptr)
@ stdcall TpAllocTimer(ptr ptr ptr)
@ -21,7 +21,7 @@ index 21f39de..9093eb8 100644
@ stdcall TpAllocWork(ptr ptr ptr ptr)
# @ stub TpAlpcRegisterCompletionList
# @ stub TpAlpcUnregisterCompletionList
@@ -1006,7 +1006,7 @@
@@ -1008,7 +1008,7 @@
# @ stub TpReleaseJobNotification
@ stdcall TpReleasePool(ptr)
@ stdcall TpReleaseTimer(ptr)
@ -30,7 +30,7 @@ index 21f39de..9093eb8 100644
@ stdcall TpReleaseWork(ptr)
# @ stub TpSetDefaultPoolMaxThreads
# @ stub TpSetDefaultPoolStackInformation
@@ -1018,7 +1018,7 @@
@@ -1020,7 +1020,7 @@
# @ stub TpSetPoolWorkerThreadIdleTimeout
@ stdcall TpSetTimer(ptr ptr long long)
# @ stub TpSetTimerEx
@ -39,7 +39,7 @@ index 21f39de..9093eb8 100644
# @ stub TpSetWaitEx
@ stdcall TpSimpleTryPost(ptr ptr ptr)
# @ stub TpStartAsyncIoOperation
@@ -1028,7 +1028,7 @@
@@ -1030,7 +1030,7 @@
# @ stub TpWaitForIoCompletion
# @ stub TpWaitForJobNotification
@ stdcall TpWaitForTimer(ptr long)
@ -49,7 +49,7 @@ index 21f39de..9093eb8 100644
@ stdcall -ret64 VerSetConditionMask(int64 long long)
@ stdcall WinSqmIsOptedIn()
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index a973409..7df8cb1 100644
index f4c9cba..f569506 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -137,6 +137,7 @@ struct timer_queue
@ -60,7 +60,7 @@ index a973409..7df8cb1 100644
/* internal threadpool representation */
struct threadpool
@@ -158,7 +159,8 @@ enum threadpool_objtype
@@ -159,7 +160,8 @@ enum threadpool_objtype
{
TP_OBJECT_TYPE_SIMPLE,
TP_OBJECT_TYPE_WORK,
@ -70,7 +70,7 @@ index a973409..7df8cb1 100644
};
/* internal threadpool object representation */
@@ -206,6 +208,17 @@ struct threadpool_object
@@ -207,6 +209,17 @@ struct threadpool_object
LONG period;
LONG window_length;
} timer;
@ -88,7 +88,7 @@ index a973409..7df8cb1 100644
} u;
};
@@ -264,6 +277,38 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug =
@@ -265,6 +278,38 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug =
0, 0, { (DWORD_PTR)(__FILE__ ": timerqueue.cs") }
};
@ -127,21 +127,21 @@ index a973409..7df8cb1 100644
static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool )
{
return (struct threadpool *)pool;
@@ -283,6 +328,13 @@ static inline struct threadpool_object *impl_from_TP_TIMER( TP_TIMER *timer )
@@ -284,6 +329,13 @@ static inline struct threadpool_object *impl_from_TP_TIMER( TP_TIMER *timer )
return object;
}
+static inline struct threadpool_object *impl_from_TP_WAIT( TP_WAIT *wait )
+{
+ struct threadpool_object *object = (struct threadpool_object *)wait;
+ assert( !object || object->type == TP_OBJECT_TYPE_WAIT );
+ assert( object->type == TP_OBJECT_TYPE_WAIT );
+ return object;
+}
+
static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group )
{
return (struct threadpool_group *)group;
@@ -295,7 +347,8 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL
@@ -296,7 +348,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 a973409..7df8cb1 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;
@@ -1349,7 +1402,7 @@ update_timer:
@@ -1350,7 +1403,7 @@ update_timer:
RtlLeaveCriticalSection( &timerqueue.cs );
if (submit_timer)
@ -160,7 +160,7 @@ index a973409..7df8cb1 100644
}
static void CALLBACK timerqueue_thread_proc( void *param )
@@ -1376,7 +1429,7 @@ static void CALLBACK timerqueue_thread_proc( void *param )
@@ -1377,7 +1430,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 a973409..7df8cb1 100644
/* Requeue the timer, except its marked for shutdown */
if (!timer->shutdown && timer->u.timer.period)
@@ -1442,6 +1495,301 @@ static void CALLBACK timerqueue_thread_proc( void *param )
@@ -1443,6 +1496,301 @@ static void CALLBACK timerqueue_thread_proc( void *param )
RtlLeaveCriticalSection( &timerqueue.cs );
}
@ -468,28 +468,28 @@ index a973409..7df8cb1 100644
+ RtlFreeHeap( GetProcessHeap(), 0, bucket );
+}
+
/* allocate a new threadpool (with at least one worker thread) */
static NTSTATUS tp_threadpool_alloc( struct threadpool **out )
{
@@ -1640,7 +1988,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
* to the cleanup group. As soon as the cleanup group members are released ->shutdown
/***********************************************************************
* tp_threadpool_alloc (internal)
*
@@ -1710,7 +2058,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 (simple_cb)
if (is_simple_callback)
- tp_object_submit( object );
+ tp_object_submit( object, FALSE );
if (object->group)
{
@@ -1661,7 +2009,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
}
/* submits an object to a threadpool */
@@ -1736,7 +2084,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.
*/
-static void tp_object_submit( struct threadpool_object *object )
+static void tp_object_submit( struct threadpool_object *object, BOOL success )
{
struct threadpool *pool = object->pool;
@@ -1696,6 +2044,10 @@ out:
NTSTATUS status = STATUS_UNSUCCESSFUL;
@@ -1766,6 +2114,10 @@ static void tp_object_submit( struct threadpool_object *object )
if (!object->num_pending_callbacks++)
list_add_tail( &pool->pool, &object->pool_entry );
@ -497,20 +497,20 @@ index a973409..7df8cb1 100644
+ if (object->type == TP_OBJECT_TYPE_WAIT && success)
+ object->u.wait.signaled++;
+
RtlLeaveCriticalSection( &pool->cs );
}
@@ -1714,6 +2066,9 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance
/* 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
object->num_pending_callbacks = 0;
list_remove( &object->pool_entry );
}
+
+ if (object->type == TP_OBJECT_TYPE_WAIT)
+ object->u.wait.signaled = 0;
+
RtlLeaveCriticalSection( &pool->cs );
/* Execute group cancellation callback if defined, and if this was actually a group cancel. */
@@ -1747,6 +2102,8 @@ static void tp_object_shutdown( struct threadpool_object *object )
@@ -1833,6 +2188,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 a973409..7df8cb1 100644
object->shutdown = TRUE;
}
@@ -1912,6 +2269,7 @@ static void CALLBACK threadpool_worker_proc( void *param )
@@ -1886,6 +2243,7 @@ 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;
+ TP_WAIT_RESULT wait_result;
LARGE_INTEGER timeout;
struct list *ptr;
@@ -1929,6 +2287,18 @@ static void CALLBACK threadpool_worker_proc( void *param )
NTSTATUS status;
@@ -1906,6 +2264,18 @@ static void CALLBACK threadpool_worker_proc( void *param )
if (--object->num_pending_callbacks)
list_add_tail( &pool->pool, &object->pool_entry );
@ -546,7 +546,7 @@ index a973409..7df8cb1 100644
/* Leave critical section and do the actual callback. */
object->num_running_callbacks++;
pool->num_busy_workers++;
@@ -1964,6 +2334,15 @@ static void CALLBACK threadpool_worker_proc( void *param )
@@ -1952,6 +2322,15 @@ static void CALLBACK threadpool_worker_proc( void *param )
break;
}
@ -562,7 +562,7 @@ index a973409..7df8cb1 100644
default:
assert(0);
break;
@@ -2073,6 +2452,41 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID
@@ -2092,6 +2471,46 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID
}
/***********************************************************************
@ -575,21 +575,26 @@ index a973409..7df8cb1 100644
+ struct threadpool *pool;
+ NTSTATUS status;
+
+ TRACE("%p %p %p %p\n", out, callback, userdata, environment);
+
+ if (!(pool = get_threadpool( environment )))
+ return STATUS_NO_MEMORY;
+ TRACE( "%p %p %p %p\n", out, callback, userdata, environment );
+
+ object = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*object) );
+ if (!object)
+ return STATUS_NO_MEMORY;
+
+ status = tp_threadpool_lock( &pool, environment );
+ if (status)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, object );
+ return status;
+ }
+
+ object->type = TP_OBJECT_TYPE_WAIT;
+ object->u.wait.callback = callback;
+
+ status = tp_waitqueue_acquire( object );
+ if (status)
+ {
+ tp_threadpool_unlock( pool );
+ RtlFreeHeap( GetProcessHeap(), 0, object );
+ return status;
+ }
@ -604,16 +609,16 @@ index a973409..7df8cb1 100644
* TpAllocWork (NTDLL.@)
*/
NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata,
@@ -2248,7 +2662,7 @@ VOID WINAPI TpPostWork( TP_WORK *work )
@@ -2285,7 +2704,7 @@ VOID WINAPI TpPostWork( TP_WORK *work )
if (this)
{
- tp_object_submit( this );
+ tp_object_submit( this, FALSE );
}
TRACE( "%p\n", work );
- tp_object_submit( this );
+ tp_object_submit( this, FALSE );
}
@@ -2362,6 +2776,21 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer )
/***********************************************************************
@@ -2389,6 +2808,19 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer )
}
/***********************************************************************
@ -622,20 +627,18 @@ index a973409..7df8cb1 100644
+VOID WINAPI TpReleaseWait( TP_WAIT *wait )
+{
+ struct threadpool_object *this = impl_from_TP_WAIT( wait );
+ TRACE("%p\n", wait);
+
+ if (this)
+ {
+ tp_object_shutdown( this );
+ tp_object_release( this );
+ }
+ TRACE( "%p\n", wait );
+
+ tp_object_shutdown( this );
+ tp_object_release( this );
+}
+
+/***********************************************************************
* TpReleaseWork (NTDLL.@)
*/
VOID WINAPI TpReleaseWork( TP_WORK *work )
@@ -2426,6 +2855,20 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO
@@ -2464,6 +2896,18 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO
}
/***********************************************************************
@ -644,19 +647,17 @@ index a973409..7df8cb1 100644
+VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout )
+{
+ struct threadpool_object *this = impl_from_TP_WAIT( wait );
+ TRACE("%p %p %p\n", wait, handle, timeout);
+
+ if (this)
+ {
+ tp_waitqueue_update_wait( this, handle, timeout );
+ }
+ TRACE( "%p %p %p\n", wait, handle, timeout );
+
+ tp_waitqueue_update_wait( this, handle, timeout );
+}
+
+/***********************************************************************
* TpSimpleTryPost (NTDLL.@)
*/
NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata,
@@ -2466,6 +2909,21 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending )
@@ -2508,6 +2952,20 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending )
}
/***********************************************************************
@ -665,13 +666,12 @@ index a973409..7df8cb1 100644
+VOID WINAPI TpWaitForWait( TP_WAIT *wait, BOOL cancel_pending )
+{
+ struct threadpool_object *this = impl_from_TP_WAIT( wait );
+ TRACE("%p %d\n", wait, cancel_pending);
+ if (this)
+ {
+ if (cancel_pending)
+ tp_object_cancel( this, FALSE, NULL );
+ tp_object_wait( this );
+ }
+
+ TRACE( "%p %d\n", wait, cancel_pending );
+
+ if (cancel_pending)
+ tp_object_cancel( this, FALSE, NULL );
+ tp_object_wait( this );
+}
+
+/***********************************************************************
@ -679,5 +679,5 @@ index a973409..7df8cb1 100644
*/
VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending )
--
2.3.5
2.4.4

View File

@ -1,4 +1,4 @@
From 8f4a1b78d16cd1977ef52c55b0729db006fcfb2b Mon Sep 17 00:00:00 2001
From 0f5fd3ad8c585b98f2754738fb9a7bb0e9b83708 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.
@ -8,7 +8,7 @@ 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 b44b0f5..0e845ce 100644
index 76db2d0..368692b 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -770,6 +770,291 @@ static void test_tp_window_length(void)
@ -313,5 +313,5 @@ index b44b0f5..0e845ce 100644
/* FIXME: Make sure worker threads have terminated before. */
Sleep(100);
--
2.4.0
2.4.4

View File

@ -1,4 +1,4 @@
From bd2b6f3c1602f5bd24781ae12052994cae0bad73 Mon Sep 17 00:00:00 2001
From 2427c8fb3757a84085d22d176f9f6e797ea64498 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 f65f894..4eba956 100644
index 337b339..146db0f 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -233,7 +233,7 @@
@ -31,7 +31,7 @@ index f65f894..4eba956 100644
@ stdcall CreateThreadpoolWork(ptr ptr ptr)
@ stdcall CreateTimerQueue ()
@ stdcall CreateTimerQueueTimer(ptr long ptr ptr long long long)
@@ -1456,7 +1456,7 @@
@@ -1457,7 +1457,7 @@
@ stdcall SetThreadpoolThreadMaximum(ptr long) ntdll.TpSetPoolMaxThreads
@ stdcall SetThreadpoolThreadMinimum(ptr long) ntdll.TpSetPoolMinThreads
@ stdcall SetThreadpoolTimer(ptr ptr long long)
@ -40,7 +40,7 @@ index f65f894..4eba956 100644
@ stdcall SetTimeZoneInformation(ptr)
@ stub SetTimerQueueTimer
# @ stub -arch=x86_64 SetUmsThreadInformation
@@ -1571,7 +1571,7 @@
@@ -1572,7 +1572,7 @@
@ stdcall WaitForSingleObjectEx(long long long)
# @ stub WaitForThreadpoolIoCallbacks
@ stdcall WaitForThreadpoolTimerCallbacks(ptr long) ntdll.TpWaitForTimer
@ -108,10 +108,10 @@ index 945fe0b..89b0b60 100644
+ TpSetWait( wait, handle, due_time ? &timeout : NULL );
+}
diff --git a/include/winternl.h b/include/winternl.h
index 4f16d24..ee38c48 100644
index e1707fd..7ab1bd8 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -2601,6 +2601,7 @@ NTSYSAPI NTSTATUS WINAPI RtlLargeIntegerToChar(const ULONGLONG *,ULONG,ULONG,PC
@@ -2621,6 +2621,7 @@ NTSYSAPI NTSTATUS WINAPI RtlLargeIntegerToChar(const ULONGLONG *,ULONG,ULONG,PC
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 *);
@ -119,7 +119,7 @@ index 4f16d24..ee38c48 100644
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 *);
@@ -2615,12 +2616,15 @@ NTSYSAPI void WINAPI TpReleaseCleanupGroup(TP_CLEANUP_GROUP *);
@@ -2635,12 +2636,15 @@ 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 *);
@ -136,5 +136,5 @@ index 4f16d24..ee38c48 100644
/* Wine internal functions */
--
2.3.3
2.4.4

View File

@ -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 6b205e41cf0798fd6dff7c37e9b250fc885cf792"
echo " commit 7a3c9889e38ede659230a66a167b82c024f0dc85"
echo ""
}
@ -3701,34 +3701,20 @@ 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-Implement-TpSimpleTryPost-and-basic-threadpool.patch
patch_apply ntdll-Vista_Threadpool/0002-ntdll-Implement-TpSetPool-Min-Max-Threads.-v2.patch
patch_apply ntdll-Vista_Threadpool/0003-ntdll-Implement-threadpool-cleanup-group-functions.patch
patch_apply ntdll-Vista_Threadpool/0004-ntdll-tests-Add-tests-for-TpAllocCleanupGroup-and-re.patch
patch_apply ntdll-Vista_Threadpool/0005-ntdll-Implement-threadpool-work-item-functions.patch
patch_apply ntdll-Vista_Threadpool/0006-ntdll-tests-Add-basic-tests-for-threadpool-work-item.patch
patch_apply ntdll-Vista_Threadpool/0007-ntdll-tests-Add-threadpool-scheduler-tests-for-work-.patch
patch_apply ntdll-Vista_Threadpool/0008-ntdll-Add-support-for-threadpool-group-cancel-callba.patch
patch_apply ntdll-Vista_Threadpool/0009-ntdll-Add-support-for-threadpool-finalization-callba.patch
patch_apply ntdll-Vista_Threadpool/0010-ntdll-Implement-threadpool-RaceDll-environment-varia.patch
patch_apply ntdll-Vista_Threadpool/0011-ntdll-Implement-TpCallbackMayRunLong-and-instance-st.patch
patch_apply ntdll-Vista_Threadpool/0012-ntdll-Implement-TpDisassociateCallback.patch
patch_apply ntdll-Vista_Threadpool/0013-ntdll-Implement-various-TpCallback-OnCompletion-func.patch
patch_apply ntdll-Vista_Threadpool/0014-ntdll-Add-remaining-threadpool-functions-to-specfile.patch
patch_apply ntdll-Vista_Threadpool/0015-ntdll-Implement-threadpool-timer-functions.-rev-2.patch
patch_apply ntdll-Vista_Threadpool/0016-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch
patch_apply ntdll-Vista_Threadpool/0017-kernel32-Forward-various-threadpool-functions-to-ntd.patch
patch_apply ntdll-Vista_Threadpool/0018-ntdll-Implement-threadpool-wait-objects.patch
patch_apply ntdll-Vista_Threadpool/0019-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch
patch_apply ntdll-Vista_Threadpool/0020-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch
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
(
echo '+ { "Sebastian Lackner", "ntdll: Implement TpSimpleTryPost and basic threadpool infrastructure.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll: Implement TpSetPool[Min|Max]Threads.", 2 },';
echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool cleanup group functions.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for TpAllocCleanupGroup and related functions.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool work item functions.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll/tests: Add basic tests for threadpool work items.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll/tests: Add threadpool scheduler tests for work items.", 1 },';
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 },';