diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c index 5d5b49d5ee8..eea5a88d468 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -2,7 +2,7 @@ * Thread pooling * * Copyright (c) 2006 Robert Shearman - * Copyright (c) 2014-2015 Sebastian Lackner + * Copyright (c) 2014-2016 Sebastian Lackner * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -327,7 +327,7 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL static void CALLBACK threadpool_worker_proc( void *param ); static void tp_object_submit( struct threadpool_object *object, BOOL signaled ); -static void tp_object_shutdown( struct threadpool_object *object ); +static void tp_object_prepare_shutdown( struct threadpool_object *object ); static BOOL tp_object_release( struct threadpool_object *object ); static struct threadpool *default_threadpool = NULL; @@ -1886,7 +1886,8 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa if (is_simple_callback) { - tp_object_shutdown( object ); + tp_object_prepare_shutdown( object ); + object->shutdown = TRUE; tp_object_release( object ); } } @@ -2001,19 +2002,16 @@ static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) } /*********************************************************************** - * tp_object_shutdown (internal) + * tp_object_prepare_shutdown (internal) * - * Marks a threadpool object for shutdown (which means that no further - * tasks can be submitted). + * Prepares a threadpool object for shutdown. */ -static void tp_object_shutdown( struct threadpool_object *object ) +static void tp_object_prepare_shutdown( struct threadpool_object *object ) { if (object->type == TP_OBJECT_TYPE_TIMER) tp_timerqueue_unlock( object ); else if (object->type == TP_OBJECT_TYPE_WAIT) tp_waitqueue_unlock( object ); - - object->shutdown = TRUE; } /*********************************************************************** @@ -2574,23 +2572,18 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p 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) { - 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 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 ); + tp_object_prepare_shutdown( object ); } /* Move members to a new temporary list */ @@ -2612,6 +2605,11 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p LIST_FOR_EACH_ENTRY_SAFE( object, next, &members, struct threadpool_object, group_entry ) { tp_object_wait( object, TRUE ); + + if (object->type != TP_OBJECT_TYPE_SIMPLE && !object->shutdown) + tp_object_release( object ); + + object->shutdown = TRUE; tp_object_release( object ); } } @@ -2638,7 +2636,8 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer ) TRACE( "%p\n", timer ); - tp_object_shutdown( this ); + tp_object_prepare_shutdown( this ); + this->shutdown = TRUE; tp_object_release( this ); } @@ -2651,7 +2650,8 @@ VOID WINAPI TpReleaseWait( TP_WAIT *wait ) TRACE( "%p\n", wait ); - tp_object_shutdown( this ); + tp_object_prepare_shutdown( this ); + this->shutdown = TRUE; tp_object_release( this ); } @@ -2664,7 +2664,8 @@ VOID WINAPI TpReleaseWork( TP_WORK *work ) TRACE( "%p\n", work ); - tp_object_shutdown( this ); + tp_object_prepare_shutdown( this ); + this->shutdown = TRUE; tp_object_release( this ); }