mirror of
https://github.com/reactos/wine.git
synced 2024-12-03 09:20:56 +00:00
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.
This commit is contained in:
parent
8fc2430c2a
commit
eb974bcd7a
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
@ -1724,6 +1752,56 @@ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID us
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* 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.@)
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user