ntdll: Do not call group cancel callback for finished simple callbacks. (v2)
Sebastian Lackner
sebastian at fds-team.de
Sat Aug 20 15:38:43 CDT 2016
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---
Replaces patch 6/7 of my previous series ( http://source.winehq.org/patches/data/125800 ).
The tests are completely unchanged (and will fail to apply on the testbot).
Changes in v2:
* Keep the special handling for simple callbacks in tp_object_initialize,
at least for now. There is still a small risk for race-conditions, and
I would like to add some more tests before doing such a change.
dlls/ntdll/tests/threadpool.c | 20 ++++++++++++++++++++
dlls/ntdll/threadpool.c | 33 +++++++++++++++++++--------------
2 files changed, 39 insertions(+), 14 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..04790aa 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -1885,11 +1885,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
}
if (is_simple_callback)
- {
- tp_object_prepare_shutdown( object );
- object->shutdown = TRUE;
tp_object_release( object );
- }
}
/***********************************************************************
@@ -2185,6 +2181,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 +2601,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 );
--
2.9.0
More information about the wine-patches
mailing list