ntdll-Vista_Threadpool: Make sure that threadpools have always at least one worker thread.

This commit is contained in:
Sebastian Lackner 2015-02-02 14:09:18 +01:00
parent af245c20be
commit 1ac4ac7302
2 changed files with 145 additions and 0 deletions

View File

@ -0,0 +1,143 @@
From 1cd9f0a44db192fb1add9989d040c96fd4f537a3 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 2 Feb 2015 13:26:06 +0100
Subject: ntdll: Make sure that threadpools have always at least one worker
thread.
Since various functions are declared as VOID on Windows, we always have
to make sure that tasks can be processed. We do that by spawning the first
worker immediately when the threadpool is created.
---
dlls/ntdll/threadpool2.c | 45 ++++++++++++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/threadpool2.c b/dlls/ntdll/threadpool2.c
index 76aee5a..7829212 100644
--- a/dlls/ntdll/threadpool2.c
+++ b/dlls/ntdll/threadpool2.c
@@ -233,7 +233,7 @@ static NTSTATUS tp_threadpool_alloc( struct threadpool **out );
static BOOL tp_threadpool_release( struct threadpool *pool );
static void tp_threadpool_shutdown( struct threadpool *pool );
-static NTSTATUS tp_object_submit( struct threadpool_object *object );
+static void tp_object_submit( struct threadpool_object *object );
static BOOL tp_object_release( struct threadpool_object *object );
static void tp_object_shutdown( struct threadpool_object *object );
@@ -598,12 +598,14 @@ static struct threadpool *get_default_threadpool( void )
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 = 1;
+ pool->refcount = 2; /* this thread + worker proc */
pool->shutdown = FALSE;
RtlInitializeCriticalSection( &pool->cs );
@@ -615,9 +617,20 @@ static NTSTATUS tp_threadpool_alloc( struct threadpool **out )
pool->max_workers = 500;
pool->min_workers = 1;
- pool->num_workers = 0;
+ 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;
@@ -745,10 +758,10 @@ static void CALLBACK threadpool_worker_proc( void *param )
if (pool->shutdown)
break;
- /* Wait for new tasks or until timeout expires. */
+ /* 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 ))
+ &timeout ) == STATUS_TIMEOUT && !list_head( &pool->pool ) && pool->num_workers > 1)
{
break;
}
@@ -1005,10 +1018,9 @@ static void tp_object_wait( struct threadpool_object *object )
RtlLeaveCriticalSection( &pool->cs );
}
-static NTSTATUS tp_object_submit( struct threadpool_object *object )
+static void tp_object_submit( struct threadpool_object *object )
{
struct threadpool *pool = object->pool;
- NTSTATUS status = STATUS_SUCCESS;
assert( !object->shutdown );
assert( !pool->shutdown );
@@ -1018,7 +1030,9 @@ static NTSTATUS tp_object_submit( struct threadpool_object *object )
/* 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)
@@ -1027,25 +1041,21 @@ static NTSTATUS tp_object_submit( struct threadpool_object *object )
pool->num_workers++;
NtClose( thread );
}
- else if (pool->num_workers)
+ else
{
+ assert( pool->num_workers > 0 );
RtlWakeConditionVariable( &pool->update_event );
- status = STATUS_SUCCESS;
}
}
else RtlWakeConditionVariable( &pool->update_event );
/* Queue work item into pool and increment refcount */
- if (!status)
- {
- if (!object->num_pending_callbacks++)
- list_add_tail( &pool->pool, &object->pool_entry );
+ if (!object->num_pending_callbacks++)
+ list_add_tail( &pool->pool, &object->pool_entry );
- interlocked_inc(&object->refcount);
- }
+ interlocked_inc( &object->refcount );
RtlLeaveCriticalSection( &pool->cs );
- return status;
}
/***********************************************************************
@@ -1410,7 +1420,8 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, T
status = tp_object_alloc_simple( &object, callback, userdata, environment );
if (!status)
{
- status = tp_object_submit( object );
+ tp_object_submit( object );
+
tp_object_shutdown( object );
tp_object_release( object );
}
--
2.2.2

View File

@ -2235,6 +2235,7 @@ if test "$enable_ntdll_Vista_Threadpool" -eq 1; then
patch_apply ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.patch
patch_apply ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch
patch_apply ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch
patch_apply ntdll-Vista_Threadpool/0007-ntdll-Make-sure-that-threadpools-have-always-at-leas.patch
(
echo '+ { "Sebastian Lackner", "ntdll: Add threadpool stub functions to specfile.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool, cleanup group and callback instance functions.", 1 },';
@ -2242,6 +2243,7 @@ if test "$enable_ntdll_Vista_Threadpool" -eq 1; then
echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool timer functions.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for Tp* threadpool functions.", 1 },';
echo '+ { "Sebastian Lackner", "kernel32: Forward various threadpool functions to ntdll.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll: Make sure that threadpools have always at least one worker thread.", 1 },';
) >> "$patchlist"
fi