Sebastian Lackner : ntdll: Implement instance objects and the TpCallbackMayRunLong function.
Alexandre Julliard
julliard at wine.codeweavers.com
Thu Jul 2 07:18:07 CDT 2015
Module: wine
Branch: master
Commit: eb974bcd7a4eb6e0205c6309f48b885701f3a56f
URL: http://source.winehq.org/git/wine.git/?a=commit;h=eb974bcd7a4eb6e0205c6309f48b885701f3a56f
Author: Sebastian Lackner <sebastian at fds-team.de>
Date: Wed Jul 1 22:55:30 2015 +0200
ntdll: Implement instance objects and the TpCallbackMayRunLong function.
The instance is marked as long-running even if TpCallbackMayRunLong fails,
a second call will lead to an exception on Windows.
---
dlls/ntdll/ntdll.spec | 1 +
dlls/ntdll/tests/threadpool.c | 9 ++++
dlls/ntdll/threadpool.c | 98 ++++++++++++++++++++++++++++++++++++++-----
3 files changed, 98 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 4b5ece5..5a698c4 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -973,6 +973,7 @@
@ stdcall TpAllocCleanupGroup(ptr)
@ stdcall TpAllocPool(ptr ptr)
@ stdcall TpAllocWork(ptr ptr ptr ptr)
+@ stdcall TpCallbackMayRunLong(ptr)
@ stdcall TpPostWork(ptr)
@ stdcall TpReleaseCleanupGroup(ptr)
@ stdcall TpReleaseCleanupGroupMembers(ptr long ptr)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 2d64471..e920300 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -24,6 +24,7 @@ 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 NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *);
static VOID (WINAPI *pTpPostWork)(TP_WORK *);
static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
@@ -53,6 +54,7 @@ static BOOL init_threadpool(void)
NTDLL_GET_PROC(TpAllocCleanupGroup);
NTDLL_GET_PROC(TpAllocPool);
NTDLL_GET_PROC(TpAllocWork);
+ NTDLL_GET_PROC(TpCallbackMayRunLong);
NTDLL_GET_PROC(TpPostWork);
NTDLL_GET_PROC(TpReleaseCleanupGroup);
NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
@@ -312,8 +314,15 @@ static DWORD group_cancel_tid;
static void CALLBACK group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
{
HANDLE *semaphores = userdata;
+ NTSTATUS status;
DWORD result;
+
trace("Running group cancel callback\n");
+
+ status = pTpCallbackMayRunLong(instance);
+ ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */,
+ "expected STATUS_TOO_MANY_THREADS, got %08x\n", status);
+
result = WaitForSingleObject(semaphores[0], 1000);
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
ReleaseSemaphore(semaphores[1], 1, NULL);
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index 4ae81b0..a0090c0 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -173,6 +173,7 @@ struct threadpool_object
PVOID userdata;
PTP_CLEANUP_GROUP_CANCEL_CALLBACK group_cancel_callback;
PTP_SIMPLE_CALLBACK finalization_callback;
+ BOOL may_run_long;
HMODULE race_dll;
/* information about the group, locked via .group->cs */
struct list group_entry;
@@ -196,6 +197,14 @@ struct threadpool_object
} u;
};
+/* internal threadpool instance representation */
+struct threadpool_instance
+{
+ struct threadpool_object *object;
+ DWORD threadid;
+ BOOL may_run_long;
+};
+
/* internal threadpool group representation */
struct threadpool_group
{
@@ -223,6 +232,11 @@ static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GR
return (struct threadpool_group *)group;
}
+static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CALLBACK_INSTANCE *instance )
+{
+ return (struct threadpool_instance *)instance;
+}
+
static void CALLBACK threadpool_worker_proc( void *param );
static void tp_object_submit( struct threadpool_object *object );
static void tp_object_shutdown( struct threadpool_object *object );
@@ -1375,6 +1389,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
object->userdata = userdata;
object->group_cancel_callback = NULL;
object->finalization_callback = NULL;
+ object->may_run_long = 0;
object->race_dll = NULL;
memset( &object->group_entry, 0, sizeof(object->group_entry) );
@@ -1393,9 +1408,14 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
object->group = impl_from_TP_CLEANUP_GROUP( environment->CleanupGroup );
object->group_cancel_callback = environment->CleanupGroupCancelCallback;
object->finalization_callback = environment->FinalizationCallback;
+ object->may_run_long = environment->u.s.LongFunction != 0;
object->race_dll = environment->RaceDll;
- WARN( "environment not fully implemented yet\n" );
+ if (environment->ActivationContext)
+ FIXME( "activation context not supported yet\n" );
+
+ if (environment->u.s.Persistent)
+ FIXME( "persistent threads not supported yet\n" );
}
if (object->race_dll)
@@ -1578,6 +1598,8 @@ static BOOL tp_object_release( struct threadpool_object *object )
*/
static void CALLBACK threadpool_worker_proc( void *param )
{
+ TP_CALLBACK_INSTANCE *callback_instance;
+ struct threadpool_instance instance;
struct threadpool *pool = param;
LARGE_INTEGER timeout;
struct list *ptr;
@@ -1603,22 +1625,28 @@ static void CALLBACK threadpool_worker_proc( void *param )
pool->num_busy_workers++;
RtlLeaveCriticalSection( &pool->cs );
+ /* Initialize threadpool instance struct. */
+ callback_instance = (TP_CALLBACK_INSTANCE *)&instance;
+ instance.object = object;
+ instance.threadid = GetCurrentThreadId();
+ instance.may_run_long = object->may_run_long;
+
switch (object->type)
{
case TP_OBJECT_TYPE_SIMPLE:
{
- TRACE( "executing simple callback %p(NULL, %p)\n",
- object->u.simple.callback, object->userdata );
- object->u.simple.callback( NULL, object->userdata );
+ TRACE( "executing simple callback %p(%p, %p)\n",
+ object->u.simple.callback, callback_instance, object->userdata );
+ object->u.simple.callback( callback_instance, object->userdata );
TRACE( "callback %p returned\n", object->u.simple.callback );
break;
}
case TP_OBJECT_TYPE_WORK:
{
- TRACE( "executing work callback %p(NULL, %p, %p)\n",
- object->u.work.callback, object->userdata, object );
- object->u.work.callback( NULL, object->userdata, (TP_WORK *)object );
+ TRACE( "executing work callback %p(%p, %p, %p)\n",
+ object->u.work.callback, callback_instance, object->userdata, object );
+ object->u.work.callback( callback_instance, object->userdata, (TP_WORK *)object );
TRACE( "callback %p returned\n", object->u.work.callback );
break;
}
@@ -1631,9 +1659,9 @@ static void CALLBACK threadpool_worker_proc( void *param )
/* Execute finalization callback. */
if (object->finalization_callback)
{
- TRACE( "executing finalization callback %p(NULL, %p)\n",
- object->finalization_callback, object->userdata );
- object->finalization_callback( NULL, object->userdata );
+ TRACE( "executing finalization callback %p(%p, %p)\n",
+ object->finalization_callback, callback_instance, object->userdata );
+ object->finalization_callback( callback_instance, object->userdata );
TRACE( "callback %p returned\n", object->finalization_callback );
}
@@ -1725,6 +1753,56 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us
}
/***********************************************************************
+ * TpCallbackMayRunLong (NTDLL.@)
+ */
+NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance )
+{
+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance );
+ struct threadpool_object *object = this->object;
+ struct threadpool *pool;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ TRACE( "%p\n", instance );
+
+ if (this->threadid != GetCurrentThreadId())
+ {
+ ERR("called from wrong thread, ignoring\n");
+ return STATUS_UNSUCCESSFUL; /* FIXME */
+ }
+
+ if (this->may_run_long)
+ return STATUS_SUCCESS;
+
+ pool = object->pool;
+ RtlEnterCriticalSection( &pool->cs );
+
+ /* Start new worker threads if required. */
+ if (pool->num_busy_workers >= pool->num_workers)
+ {
+ if (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 );
+ }
+ }
+ else
+ {
+ status = STATUS_TOO_MANY_THREADS;
+ }
+ }
+
+ RtlLeaveCriticalSection( &pool->cs );
+ this->may_run_long = TRUE;
+ return status;
+}
+
+/***********************************************************************
* TpPostWork (NTDLL.@)
*/
VOID WINAPI TpPostWork( TP_WORK *work )
More information about the wine-cvs
mailing list