[6/7] ntdll: Do not call group cancel callback for finished simple callbacks.
Sebastian Lackner
sebastian at fds-team.de
Sat Aug 20 14:24:31 CDT 2016
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---
As a nice side effect this also simplifies handling for simple callbacks in
tp_object_initialize. :)
dlls/ntdll/tests/threadpool.c | 20 +++++++++++++++++
dlls/ntdll/threadpool.c | 48 ++++++++++++++++++------------------------
2 files changed, 41 insertions(+), 27 deletions(-)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 7eccb23..af0b667 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -705,6 +705,14 @@ static void test_tp_work_scheduler(void)
pTpReleasePool(pool);
}
+static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
+{
+ HANDLE *semaphores = userdata;
+ trace("Running simple release callback\n");
+ ReleaseSemaphore(semaphores, 1, NULL);
+ Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
+}
+
static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
{
HANDLE semaphore = userdata;
@@ -1008,6 +1016,18 @@ static void test_tp_group_cancel(void)
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
+ /* terminated simple callbacks should not trigger the group cancel callback */
+ memset(&environment, 0, sizeof(environment));
+ environment.Version = 1;
+ environment.Pool = pool;
+ environment.CleanupGroup = group;
+ environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb;
+ status = pTpSimpleTryPost(simple_release_cb, semaphores[1], &environment);
+ ok(!status, "TpSimpleTryPost failed with status %x\n", status);
+ result = WaitForSingleObject(semaphores[1], 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
+
/* test cancellation callback for objects with multiple instances */
work = NULL;
memset(&environment, 0, sizeof(environment));
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index a572869..0b500a7 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -327,7 +327,6 @@ 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_prepare_shutdown( struct threadpool_object *object );
static BOOL tp_object_release( struct threadpool_object *object );
static struct threadpool *default_threadpool = NULL;
@@ -1820,8 +1819,6 @@ static BOOL tp_group_release( struct threadpool_group *group )
static void tp_object_initialize( struct threadpool_object *object, struct threadpool *pool,
PVOID userdata, TP_CALLBACK_ENVIRON *environment )
{
- BOOL is_simple_callback = (object->type == TP_OBJECT_TYPE_SIMPLE);
-
object->refcount = 1;
object->shutdown = FALSE;
@@ -1866,13 +1863,6 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
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 (is_simple_callback)
- tp_object_submit( object, FALSE );
-
if (object->group)
{
struct threadpool_group *group = object->group;
@@ -1883,13 +1873,6 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
object->is_group_member = TRUE;
RtlLeaveCriticalSection( &group->cs );
}
-
- if (is_simple_callback)
- {
- tp_object_prepare_shutdown( object );
- object->shutdown = TRUE;
- tp_object_release( object );
- }
}
/***********************************************************************
@@ -2185,6 +2168,13 @@ static void CALLBACK threadpool_worker_proc( void *param )
RtlEnterCriticalSection( &pool->cs );
pool->num_busy_workers--;
+ /* Simple callbacks are automatically shutdown after execution. */
+ if (object->type == TP_OBJECT_TYPE_SIMPLE)
+ {
+ tp_object_prepare_shutdown( object );
+ object->shutdown = TRUE;
+ }
+
object->num_running_callbacks--;
if (!object->num_pending_callbacks && !object->num_running_callbacks)
RtlWakeAllConditionVariable( &object->group_finished_event );
@@ -2598,18 +2588,20 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p
{
tp_object_wait( object, TRUE );
- /* Execute group cancellation callback if defined, and if this was actually a group cancel. */
- if ((object->type == TP_OBJECT_TYPE_SIMPLE || !object->shutdown) &&
- cancel_pending && object->group_cancel_callback)
+ if (!object->shutdown)
{
- TRACE( "executing group cancel callback %p(%p, %p)\n",
- object->group_cancel_callback, object->userdata, userdata );
- object->group_cancel_callback( object->userdata, userdata );
- TRACE( "callback %p returned\n", object->group_cancel_callback );
- }
+ /* Execute group cancellation callback if defined, and if this was actually a group cancel. */
+ if (cancel_pending && object->group_cancel_callback)
+ {
+ TRACE( "executing group cancel callback %p(%p, %p)\n",
+ object->group_cancel_callback, object->userdata, userdata );
+ object->group_cancel_callback( object->userdata, userdata );
+ TRACE( "callback %p returned\n", object->group_cancel_callback );
+ }
- if (object->type != TP_OBJECT_TYPE_SIMPLE && !object->shutdown)
- tp_object_release( object );
+ if (object->type != TP_OBJECT_TYPE_SIMPLE)
+ tp_object_release( object );
+ }
object->shutdown = TRUE;
tp_object_release( object );
@@ -2888,6 +2880,8 @@ 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, FALSE );
+ tp_object_release( object );
return STATUS_SUCCESS;
}
--
2.9.0
More information about the wine-patches
mailing list