mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-09-13 09:17:20 -07:00
Rebase against 90173ce448e5afe55627c2cbece28fb4f6bae99d.
[ntdll-ThreadpoolCleanupGroup] Removed patches to fix multiple bugs related to threadpool cleanup groups and cancel callbacks (accepted upstream).
This commit is contained in:
parent
034992d90e
commit
d86ab36369
@ -1,4 +1,4 @@
|
||||
From 446107bd1bda89cfdb656dd1f0e06dcb328c00ed Mon Sep 17 00:00:00 2001
|
||||
From 0d41f28599a8b37e38a09a2d41ded554b7f05baa Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 15 Jan 2016 13:01:15 +0100
|
||||
Subject: kernelbase: Add dll and add stub for QuirkIsEnabled.
|
||||
@ -22,7 +22,7 @@ index b9caed0..2beb34b 100644
|
||||
+C_SRCS = \
|
||||
+ misc.c
|
||||
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
|
||||
index 23ca440..19cf953 100644
|
||||
index bef97a0..cd33ef8 100644
|
||||
--- a/dlls/kernelbase/kernelbase.spec
|
||||
+++ b/dlls/kernelbase/kernelbase.spec
|
||||
@@ -1,3 +1,6 @@
|
||||
@ -250,7 +250,7 @@ index 23ca440..19cf953 100644
|
||||
@ stdcall DebugBreak() kernel32.DebugBreak
|
||||
@ stdcall DecodePointer(ptr) kernel32.DecodePointer
|
||||
+@ stub DecodeRemotePointer
|
||||
@ stub DecodeSystemPointer
|
||||
@ stdcall DecodeSystemPointer(ptr) kernel32.DecodeSystemPointer
|
||||
@ stdcall DefineDosDeviceW(long wstr wstr) kernel32.DefineDosDeviceW
|
||||
+@ stdcall DelayLoadFailureHook(str str) kernel32.DelayLoadFailureHook
|
||||
+@ stub DelayLoadFailureHookLookup
|
||||
@ -294,7 +294,7 @@ index 23ca440..19cf953 100644
|
||||
+@ stub EmptyWorkingSet
|
||||
@ stdcall EncodePointer(ptr) kernel32.EncodePointer
|
||||
+@ stub EncodeRemotePointer
|
||||
@ stub EncodeSystemPointer
|
||||
@ stdcall EncodeSystemPointer(ptr) kernel32.EncodeSystemPointer
|
||||
+@ stub EnterCriticalPolicySectionInternal
|
||||
@ stdcall EnterCriticalSection(ptr) kernel32.EnterCriticalSection
|
||||
+@ stub EnterSynchronizationBarrier
|
||||
@ -1770,10 +1770,10 @@ index 6b6ead2..7c2a9d1 100644
|
||||
422 stdcall -noname SHGlobalCounterCreateNamedA(str long)
|
||||
423 stdcall -noname SHGlobalCounterCreateNamedW(wstr long)
|
||||
diff --git a/tools/make_specfiles b/tools/make_specfiles
|
||||
index d658f30..c1a0f15 100755
|
||||
index 947cde7..a102a15 100755
|
||||
--- a/tools/make_specfiles
|
||||
+++ b/tools/make_specfiles
|
||||
@@ -195,6 +195,7 @@ my @dll_groups =
|
||||
@@ -196,6 +196,7 @@ my @dll_groups =
|
||||
[
|
||||
"kernel32",
|
||||
"advapi32",
|
||||
|
@ -1,4 +1,4 @@
|
||||
From 88367d179496bb178f97591000ef5e56e58a9322 Mon Sep 17 00:00:00 2001
|
||||
From 5989f92d5a873732acb8cb9af4011ce7e145bbb3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 23 Jan 2016 21:13:02 +0100
|
||||
Subject: ext-ms-win-kernel32-package-current-l1-1-0: Add dll.
|
||||
@ -13,10 +13,10 @@ Subject: ext-ms-win-kernel32-package-current-l1-1-0: Add dll.
|
||||
create mode 100644 dlls/ext-ms-win-kernel32-package-current-l1-1-0/ext-ms-win-kernel32-package-current-l1-1-0.spec
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index bb63b0d..e7c55db 100644
|
||||
index d2abe1d..dc1b078 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -2939,6 +2939,7 @@ WINE_CONFIG_DLL(explorerframe,,[clean])
|
||||
@@ -2958,6 +2958,7 @@ WINE_CONFIG_DLL(explorerframe,,[clean])
|
||||
WINE_CONFIG_TEST(dlls/explorerframe/tests)
|
||||
WINE_CONFIG_DLL(ext-ms-win-appmodel-usercontext-l1-1-0)
|
||||
WINE_CONFIG_DLL(ext-ms-win-gdi-devcaps-l1-1-0)
|
||||
@ -40,17 +40,17 @@ index 0000000..2156c27
|
||||
+@ stdcall GetCurrentPackageId(ptr ptr) kernel32.GetCurrentPackageId
|
||||
+@ stub GetCurrentPackageInfo
|
||||
diff --git a/tools/make_specfiles b/tools/make_specfiles
|
||||
index b364446..5b2418b 100755
|
||||
index 1337fca..756ae00 100755
|
||||
--- a/tools/make_specfiles
|
||||
+++ b/tools/make_specfiles
|
||||
@@ -214,6 +214,7 @@ my @dll_groups =
|
||||
"api-ms-win-core-wow64-l1-1-0",
|
||||
@@ -180,6 +180,7 @@ my @dll_groups =
|
||||
"api-ms-win-core-xstate-l2-1-0",
|
||||
"api-ms-win-core-errorhandling-l1-1-2",
|
||||
"api-ms-win-core-util-l1-1-0",
|
||||
+ "ext-ms-win-kernel32-package-current-l1-1-0",
|
||||
],
|
||||
[
|
||||
"kernel32",
|
||||
--
|
||||
2.6.4
|
||||
2.9.0
|
||||
|
||||
|
@ -1,3 +1,2 @@
|
||||
Fixes: [40325] Implement GdipCreateMetafileFromStream
|
||||
Fixes: [27415] Implement GdipGetMetafileHeaderFromMetafile
|
||||
Depends: oleaut32-OLEPictureImpl_SaveAsFile
|
||||
|
@ -1,134 +0,0 @@
|
||||
From a6213f025a63ad3b2a086c028dae1ff30892af5a Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 20 Aug 2016 21:18:33 +0200
|
||||
Subject: ntdll/tests: Use longer waits to reduce risk of random failures on
|
||||
the testbot.
|
||||
|
||||
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
|
||||
---
|
||||
dlls/ntdll/tests/threadpool.c | 32 +++++++++++++++++---------------
|
||||
1 file changed, 17 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
|
||||
index 1d8b1f9..9b4b522 100644
|
||||
--- a/dlls/ntdll/tests/threadpool.c
|
||||
+++ b/dlls/ntdll/tests/threadpool.c
|
||||
@@ -579,14 +579,14 @@ static void test_tp_simple(void)
|
||||
static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
|
||||
{
|
||||
trace("Running work callback\n");
|
||||
- Sleep(10);
|
||||
+ Sleep(100);
|
||||
InterlockedIncrement((LONG *)userdata);
|
||||
}
|
||||
|
||||
static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
|
||||
{
|
||||
trace("Running work2 callback\n");
|
||||
- Sleep(10);
|
||||
+ Sleep(100);
|
||||
InterlockedExchangeAdd((LONG *)userdata, 0x10000);
|
||||
}
|
||||
|
||||
@@ -599,11 +599,12 @@ static void test_tp_work(void)
|
||||
LONG userdata;
|
||||
int i;
|
||||
|
||||
- /* allocate new threadpool */
|
||||
+ /* allocate new threadpool with only one thread */
|
||||
pool = NULL;
|
||||
status = pTpAllocPool(&pool, NULL);
|
||||
ok(!status, "TpAllocPool failed with status %x\n", status);
|
||||
ok(pool != NULL, "expected pool != NULL\n");
|
||||
+ pTpSetPoolMaxThreads(pool, 1);
|
||||
|
||||
/* allocate new work item */
|
||||
work = NULL;
|
||||
@@ -614,12 +615,12 @@ static void test_tp_work(void)
|
||||
ok(!status, "TpAllocWork failed with status %x\n", status);
|
||||
ok(work != NULL, "expected work != NULL\n");
|
||||
|
||||
- /* post 10 identical work items at once */
|
||||
+ /* post 5 identical work items at once */
|
||||
userdata = 0;
|
||||
- for (i = 0; i < 10; i++)
|
||||
+ for (i = 0; i < 5; i++)
|
||||
pTpPostWork(work);
|
||||
pTpWaitForWork(work, FALSE);
|
||||
- ok(userdata == 10, "expected userdata = 10, got %u\n", userdata);
|
||||
+ ok(userdata == 5, "expected userdata = 5, got %u\n", userdata);
|
||||
|
||||
/* add more tasks and cancel them immediately */
|
||||
userdata = 0;
|
||||
@@ -643,13 +644,11 @@ static void test_tp_work_scheduler(void)
|
||||
LONG userdata;
|
||||
int i;
|
||||
|
||||
- /* allocate new threadpool */
|
||||
+ /* allocate new threadpool with only one thread */
|
||||
pool = NULL;
|
||||
status = pTpAllocPool(&pool, NULL);
|
||||
ok(!status, "TpAllocPool failed with status %x\n", status);
|
||||
ok(pool != NULL, "expected pool != NULL\n");
|
||||
-
|
||||
- /* we limit the pool to a single thread */
|
||||
pTpSetPoolMaxThreads(pool, 1);
|
||||
|
||||
/* create a cleanup group */
|
||||
@@ -683,7 +682,7 @@ static void test_tp_work_scheduler(void)
|
||||
pTpPostWork(work);
|
||||
for (i = 0; i < 10; i++)
|
||||
pTpPostWork(work2);
|
||||
- Sleep(30);
|
||||
+ Sleep(500);
|
||||
pTpWaitForWork(work, TRUE);
|
||||
pTpWaitForWork(work2, TRUE);
|
||||
ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %u\n", userdata & 0xffff);
|
||||
@@ -691,14 +690,14 @@ static void test_tp_work_scheduler(void)
|
||||
|
||||
/* test TpReleaseCleanupGroupMembers on a work item */
|
||||
userdata = 0;
|
||||
- for (i = 0; i < 100; i++)
|
||||
- pTpPostWork(work);
|
||||
for (i = 0; i < 10; i++)
|
||||
+ pTpPostWork(work);
|
||||
+ for (i = 0; i < 3; i++)
|
||||
pTpPostWork(work2);
|
||||
pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
|
||||
pTpWaitForWork(work, TRUE);
|
||||
- ok((userdata & 0xffff) < 100, "expected userdata & 0xffff < 100, got %u\n", userdata & 0xffff);
|
||||
- ok((userdata >> 16) == 10, "expected userdata >> 16 == 10, got %u\n", userdata >> 16);
|
||||
+ ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %u\n", userdata & 0xffff);
|
||||
+ ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %u\n", userdata >> 16);
|
||||
|
||||
/* cleanup */
|
||||
pTpReleaseWork(work);
|
||||
@@ -720,6 +719,7 @@ static void CALLBACK group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userd
|
||||
ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */,
|
||||
"expected STATUS_TOO_MANY_THREADS, got %08x\n", status);
|
||||
|
||||
+ ReleaseSemaphore(semaphores[1], 1, NULL);
|
||||
result = WaitForSingleObject(semaphores[0], 1000);
|
||||
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
ReleaseSemaphore(semaphores[1], 1, NULL);
|
||||
@@ -781,6 +781,8 @@ static void test_tp_group_cancel(void)
|
||||
environment.Pool = pool;
|
||||
status = pTpSimpleTryPost(group_cancel_cb, semaphores, &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);
|
||||
|
||||
memset(&environment, 0, sizeof(environment));
|
||||
environment.Version = 1;
|
||||
@@ -816,7 +818,7 @@ static void test_tp_group_cancel(void)
|
||||
/* check if we get multiple cancellation callbacks */
|
||||
group_cancel_tid = 0xdeadbeef;
|
||||
pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2);
|
||||
- ok(userdata <= 8, "expected userdata <= 8, got %u\n", userdata);
|
||||
+ ok(userdata <= 5, "expected userdata <= 5, got %u\n", userdata);
|
||||
ok(userdata2 == 1, "expected only one cancellation callback, got %u\n", userdata2);
|
||||
ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n",
|
||||
GetCurrentThreadId(), group_cancel_tid);
|
||||
--
|
||||
2.9.0
|
||||
|
@ -1,142 +0,0 @@
|
||||
From 696ecf266d29fb3120a1348a47fe55e65da2f0d6 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 20 Aug 2016 21:22:29 +0200
|
||||
Subject: ntdll: Allow to release threadpool objects while waiting for group.
|
||||
|
||||
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
|
||||
---
|
||||
dlls/ntdll/threadpool.c | 51 +++++++++++++++++++++++++------------------------
|
||||
1 file changed, 26 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
|
||||
index 5d5b49d..eea5a88 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 );
|
||||
}
|
||||
|
||||
--
|
||||
2.9.0
|
||||
|
@ -1,148 +0,0 @@
|
||||
From 8eb37c4da70b875e1daf4976ec8624c26a2266db Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 20 Aug 2016 21:22:54 +0200
|
||||
Subject: ntdll/tests: Add tests for releasing threadpool objects during
|
||||
TpReleaseCleanupGroupMembers.
|
||||
|
||||
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
|
||||
---
|
||||
dlls/ntdll/tests/threadpool.c | 109 +++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 108 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
|
||||
index 9b4b522..7672d63 100644
|
||||
--- a/dlls/ntdll/tests/threadpool.c
|
||||
+++ b/dlls/ntdll/tests/threadpool.c
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Unit test suite for thread pool functions
|
||||
*
|
||||
- * Copyright 2015 Sebastian Lackner
|
||||
+ * Copyright 2015-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
|
||||
@@ -705,6 +705,112 @@ static void test_tp_work_scheduler(void)
|
||||
pTpReleasePool(pool);
|
||||
}
|
||||
|
||||
+static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
|
||||
+{
|
||||
+ HANDLE semaphore = userdata;
|
||||
+ trace("Running work release callback\n");
|
||||
+ ReleaseSemaphore(semaphore, 1, NULL);
|
||||
+ Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
|
||||
+ pTpReleaseWork(work);
|
||||
+}
|
||||
+
|
||||
+static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
|
||||
+{
|
||||
+ HANDLE semaphore = userdata;
|
||||
+ trace("Running timer release callback\n");
|
||||
+ ReleaseSemaphore(semaphore, 1, NULL);
|
||||
+ Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
|
||||
+ pTpReleaseTimer(timer);
|
||||
+}
|
||||
+
|
||||
+static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
|
||||
+ TP_WAIT *wait, TP_WAIT_RESULT result)
|
||||
+{
|
||||
+ HANDLE semaphore = userdata;
|
||||
+ trace("Running wait release callback\n");
|
||||
+ ReleaseSemaphore(semaphore, 1, NULL);
|
||||
+ Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
|
||||
+ pTpReleaseWait(wait);
|
||||
+}
|
||||
+
|
||||
+static void test_tp_group_wait(void)
|
||||
+{
|
||||
+ TP_CALLBACK_ENVIRON environment;
|
||||
+ TP_CLEANUP_GROUP *group;
|
||||
+ LARGE_INTEGER when;
|
||||
+ HANDLE semaphore;
|
||||
+ NTSTATUS status;
|
||||
+ TP_TIMER *timer;
|
||||
+ TP_WAIT *wait;
|
||||
+ TP_WORK *work;
|
||||
+ TP_POOL *pool;
|
||||
+ DWORD result;
|
||||
+
|
||||
+ semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
|
||||
+ ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
|
||||
+
|
||||
+ /* allocate new threadpool */
|
||||
+ pool = NULL;
|
||||
+ status = pTpAllocPool(&pool, NULL);
|
||||
+ ok(!status, "TpAllocPool failed with status %x\n", status);
|
||||
+ ok(pool != NULL, "expected pool != NULL\n");
|
||||
+
|
||||
+ /* allocate a cleanup group */
|
||||
+ group = NULL;
|
||||
+ status = pTpAllocCleanupGroup(&group);
|
||||
+ ok(!status, "TpAllocCleanupGroup failed with status %x\n", status);
|
||||
+ ok(group != NULL, "expected pool != NULL\n");
|
||||
+
|
||||
+ /* release work object during TpReleaseCleanupGroupMembers */
|
||||
+ work = NULL;
|
||||
+ memset(&environment, 0, sizeof(environment));
|
||||
+ environment.Version = 1;
|
||||
+ environment.Pool = pool;
|
||||
+ environment.CleanupGroup = group;
|
||||
+ status = pTpAllocWork(&work, work_release_cb, semaphore, &environment);
|
||||
+ ok(!status, "TpAllocWork failed with status %x\n", status);
|
||||
+ ok(work != NULL, "expected work != NULL\n");
|
||||
+ pTpPostWork(work);
|
||||
+ result = WaitForSingleObject(semaphore, 1000);
|
||||
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
|
||||
+
|
||||
+ /* release timer object during TpReleaseCleanupGroupMembers */
|
||||
+ timer = NULL;
|
||||
+ memset(&environment, 0, sizeof(environment));
|
||||
+ environment.Version = 1;
|
||||
+ environment.Pool = pool;
|
||||
+ environment.CleanupGroup = group;
|
||||
+ status = pTpAllocTimer(&timer, timer_release_cb, semaphore, &environment);
|
||||
+ ok(!status, "TpAllocTimer failed with status %x\n", status);
|
||||
+ ok(timer != NULL, "expected timer != NULL\n");
|
||||
+ when.QuadPart = 0;
|
||||
+ pTpSetTimer(timer, &when, 0, 0);
|
||||
+ result = WaitForSingleObject(semaphore, 1000);
|
||||
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
|
||||
+
|
||||
+ /* release wait object during TpReleaseCleanupGroupMembers */
|
||||
+ wait = NULL;
|
||||
+ memset(&environment, 0, sizeof(environment));
|
||||
+ environment.Version = 1;
|
||||
+ environment.Pool = pool;
|
||||
+ environment.CleanupGroup = group;
|
||||
+ status = pTpAllocWait(&wait, wait_release_cb, semaphore, &environment);
|
||||
+ ok(!status, "TpAllocWait failed with status %x\n", status);
|
||||
+ ok(wait != NULL, "expected wait != NULL\n");
|
||||
+ when.QuadPart = 0;
|
||||
+ pTpSetWait(wait, INVALID_HANDLE_VALUE, &when);
|
||||
+ result = WaitForSingleObject(semaphore, 1000);
|
||||
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
|
||||
+
|
||||
+ /* cleanup */
|
||||
+ pTpReleaseCleanupGroup(group);
|
||||
+ pTpReleasePool(pool);
|
||||
+ CloseHandle(semaphore);
|
||||
+}
|
||||
+
|
||||
static DWORD group_cancel_tid;
|
||||
|
||||
static void CALLBACK group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
|
||||
@@ -1679,6 +1785,7 @@ START_TEST(threadpool)
|
||||
test_tp_simple();
|
||||
test_tp_work();
|
||||
test_tp_work_scheduler();
|
||||
+ test_tp_group_wait();
|
||||
test_tp_group_cancel();
|
||||
test_tp_instance();
|
||||
test_tp_disassociate();
|
||||
--
|
||||
2.9.0
|
||||
|
@ -1,151 +0,0 @@
|
||||
From 5ed40666bb3c8587a57e269e571f64cab27c20d4 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 20 Aug 2016 21:23:24 +0200
|
||||
Subject: ntdll: Call group cancel callback with the correct arguments.
|
||||
|
||||
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
|
||||
---
|
||||
dlls/ntdll/tests/threadpool.c | 54 ++++++++++++++++++++++++++++++++++++-------
|
||||
dlls/ntdll/threadpool.c | 7 +++---
|
||||
2 files changed, 50 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
|
||||
index 7672d63..f59a15c 100644
|
||||
--- a/dlls/ntdll/tests/threadpool.c
|
||||
+++ b/dlls/ntdll/tests/threadpool.c
|
||||
@@ -813,21 +813,25 @@ static void test_tp_group_wait(void)
|
||||
|
||||
static DWORD group_cancel_tid;
|
||||
|
||||
-static void CALLBACK group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
|
||||
+static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
|
||||
{
|
||||
HANDLE *semaphores = userdata;
|
||||
NTSTATUS status;
|
||||
DWORD result;
|
||||
+ int i;
|
||||
|
||||
- trace("Running group cancel callback\n");
|
||||
+ trace("Running simple 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);
|
||||
|
||||
ReleaseSemaphore(semaphores[1], 1, NULL);
|
||||
- result = WaitForSingleObject(semaphores[0], 1000);
|
||||
- ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ {
|
||||
+ result = WaitForSingleObject(semaphores[0], 1000);
|
||||
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+ }
|
||||
ReleaseSemaphore(semaphores[1], 1, NULL);
|
||||
}
|
||||
|
||||
@@ -836,6 +840,7 @@ static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdat
|
||||
HANDLE *semaphores = userdata;
|
||||
trace("Running group cancel cleanup release callback\n");
|
||||
group_cancel_tid = GetCurrentThreadId();
|
||||
+ ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object);
|
||||
ReleaseSemaphore(semaphores[0], 1, NULL);
|
||||
}
|
||||
|
||||
@@ -846,7 +851,23 @@ static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userd
|
||||
InterlockedIncrement((LONG *)userdata);
|
||||
}
|
||||
|
||||
-static void CALLBACK unexpected_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
|
||||
+static void CALLBACK unexpected_simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
|
||||
+{
|
||||
+ ok(0, "Unexpected callback\n");
|
||||
+}
|
||||
+
|
||||
+static void CALLBACK unexpected_work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
|
||||
+{
|
||||
+ ok(0, "Unexpected callback\n");
|
||||
+}
|
||||
+
|
||||
+static void CALLBACK unexpected_timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
|
||||
+{
|
||||
+ ok(0, "Unexpected callback\n");
|
||||
+}
|
||||
+
|
||||
+static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
|
||||
+ TP_WAIT *wait, TP_WAIT_RESULT result)
|
||||
{
|
||||
ok(0, "Unexpected callback\n");
|
||||
}
|
||||
@@ -858,12 +879,14 @@ static void test_tp_group_cancel(void)
|
||||
LONG userdata, userdata2;
|
||||
HANDLE semaphores[2];
|
||||
NTSTATUS status;
|
||||
+ TP_TIMER *timer;
|
||||
+ TP_WAIT *wait;
|
||||
TP_WORK *work;
|
||||
TP_POOL *pool;
|
||||
DWORD result;
|
||||
int i;
|
||||
|
||||
- semaphores[0] = CreateSemaphoreA(NULL, 0, 1, NULL);
|
||||
+ semaphores[0] = CreateSemaphoreA(NULL, 0, 4, NULL);
|
||||
ok(semaphores[0] != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
|
||||
semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL);
|
||||
ok(semaphores[1] != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
|
||||
@@ -885,7 +908,7 @@ static void test_tp_group_cancel(void)
|
||||
memset(&environment, 0, sizeof(environment));
|
||||
environment.Version = 1;
|
||||
environment.Pool = pool;
|
||||
- status = pTpSimpleTryPost(group_cancel_cb, semaphores, &environment);
|
||||
+ status = pTpSimpleTryPost(simple_group_cancel_cb, semaphores, &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);
|
||||
@@ -895,9 +918,24 @@ static void test_tp_group_cancel(void)
|
||||
environment.Pool = pool;
|
||||
environment.CleanupGroup = group;
|
||||
environment.CleanupGroupCancelCallback = group_cancel_cleanup_release_cb;
|
||||
- status = pTpSimpleTryPost(unexpected_cb, NULL, &environment);
|
||||
+ status = pTpSimpleTryPost(unexpected_simple_cb, (void *)0xdeadbeef, &environment);
|
||||
ok(!status, "TpSimpleTryPost failed with status %x\n", status);
|
||||
|
||||
+ work = NULL;
|
||||
+ status = pTpAllocWork(&work, unexpected_work_cb, (void *)0xdeadbeef, &environment);
|
||||
+ ok(!status, "TpAllocWork failed with status %x\n", status);
|
||||
+ ok(work != NULL, "expected work != NULL\n");
|
||||
+
|
||||
+ timer = NULL;
|
||||
+ status = pTpAllocTimer(&timer, unexpected_timer_cb, (void *)0xdeadbeef, &environment);
|
||||
+ ok(!status, "TpAllocTimer failed with status %x\n", status);
|
||||
+ ok(timer != NULL, "expected timer != NULL\n");
|
||||
+
|
||||
+ wait = NULL;
|
||||
+ status = pTpAllocWait(&wait, unexpected_wait_cb, (void *)0xdeadbeef, &environment);
|
||||
+ ok(!status, "TpAllocWait failed with status %x\n", status);
|
||||
+ ok(wait != NULL, "expected wait != NULL\n");
|
||||
+
|
||||
group_cancel_tid = 0xdeadbeef;
|
||||
pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
|
||||
result = WaitForSingleObject(semaphores[1], 1000);
|
||||
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
|
||||
index eea5a88..61f6ea0 100644
|
||||
--- a/dlls/ntdll/threadpool.c
|
||||
+++ b/dlls/ntdll/threadpool.c
|
||||
@@ -1966,10 +1966,11 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance
|
||||
RtlLeaveCriticalSection( &pool->cs );
|
||||
|
||||
/* Execute group cancellation callback if defined, and if this was actually a group cancel. */
|
||||
- if (pending_callbacks && group_cancel && object->group_cancel_callback)
|
||||
+ if (group_cancel && object->group_cancel_callback)
|
||||
{
|
||||
- TRACE( "executing group cancel callback %p(%p, %p)\n", object->group_cancel_callback, object, userdata );
|
||||
- object->group_cancel_callback( object, userdata );
|
||||
+ 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 );
|
||||
}
|
||||
|
||||
--
|
||||
2.9.0
|
||||
|
@ -1,193 +0,0 @@
|
||||
From 0a7918f7b5703de00508a54baf82a6423e0a04f5 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 20 Aug 2016 21:23:48 +0200
|
||||
Subject: ntdll: Group cancel callbacks should be executed after waiting for
|
||||
pending callbacks.
|
||||
|
||||
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
|
||||
---
|
||||
dlls/ntdll/tests/threadpool.c | 65 +++++++++++++++++++++++++++++++++++++++++++
|
||||
dlls/ntdll/threadpool.c | 29 +++++++++----------
|
||||
2 files changed, 80 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
|
||||
index f59a15c..7eccb23 100644
|
||||
--- a/dlls/ntdll/tests/threadpool.c
|
||||
+++ b/dlls/ntdll/tests/threadpool.c
|
||||
@@ -835,6 +835,18 @@ static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void
|
||||
ReleaseSemaphore(semaphores[1], 1, NULL);
|
||||
}
|
||||
|
||||
+static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
|
||||
+{
|
||||
+ HANDLE *semaphores = userdata;
|
||||
+ DWORD result;
|
||||
+
|
||||
+ trace("Running work group cancel callback\n");
|
||||
+
|
||||
+ ReleaseSemaphore(semaphores[1], 1, NULL);
|
||||
+ result = WaitForSingleObject(semaphores[0], 200);
|
||||
+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
|
||||
+}
|
||||
+
|
||||
static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
|
||||
{
|
||||
HANDLE *semaphores = userdata;
|
||||
@@ -844,6 +856,15 @@ static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdat
|
||||
ReleaseSemaphore(semaphores[0], 1, NULL);
|
||||
}
|
||||
|
||||
+static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata)
|
||||
+{
|
||||
+ HANDLE *semaphores = userdata;
|
||||
+ trace("Running group cancel cleanup release2 callback\n");
|
||||
+ group_cancel_tid = GetCurrentThreadId();
|
||||
+ ok(object == userdata, "expected %p, got %p\n", userdata, object);
|
||||
+ ReleaseSemaphore(semaphores[0], 1, NULL);
|
||||
+}
|
||||
+
|
||||
static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata)
|
||||
{
|
||||
trace("Running group cancel cleanup increment callback\n");
|
||||
@@ -872,6 +893,11 @@ static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *us
|
||||
ok(0, "Unexpected callback\n");
|
||||
}
|
||||
|
||||
+static void CALLBACK unexpected_group_cancel_cleanup_cb(void *object, void *userdata)
|
||||
+{
|
||||
+ ok(0, "Unexpected callback\n");
|
||||
+}
|
||||
+
|
||||
static void test_tp_group_cancel(void)
|
||||
{
|
||||
TP_CALLBACK_ENVIRON environment;
|
||||
@@ -943,6 +969,45 @@ static void test_tp_group_cancel(void)
|
||||
ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n",
|
||||
GetCurrentThreadId(), group_cancel_tid);
|
||||
|
||||
+ /* test if cancellation callbacks are executed before or after wait */
|
||||
+ work = NULL;
|
||||
+ memset(&environment, 0, sizeof(environment));
|
||||
+ environment.Version = 1;
|
||||
+ environment.Pool = pool;
|
||||
+ environment.CleanupGroup = group;
|
||||
+ environment.CleanupGroupCancelCallback = group_cancel_cleanup_release2_cb;
|
||||
+ status = pTpAllocWork(&work, work_group_cancel_cb, semaphores, &environment);
|
||||
+ ok(!status, "TpAllocWork failed with status %x\n", status);
|
||||
+ ok(work != NULL, "expected work != NULL\n");
|
||||
+ pTpPostWork(work);
|
||||
+ pTpPostWork(work);
|
||||
+
|
||||
+ result = WaitForSingleObject(semaphores[1], 1000);
|
||||
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+
|
||||
+ group_cancel_tid = 0xdeadbeef;
|
||||
+ pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
|
||||
+ result = WaitForSingleObject(semaphores[0], 1000);
|
||||
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+ ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n",
|
||||
+ GetCurrentThreadId(), group_cancel_tid);
|
||||
+
|
||||
+ /* group cancel callback is not executed if object is destroyed while waiting */
|
||||
+ work = NULL;
|
||||
+ memset(&environment, 0, sizeof(environment));
|
||||
+ environment.Version = 1;
|
||||
+ environment.Pool = pool;
|
||||
+ environment.CleanupGroup = group;
|
||||
+ environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb;
|
||||
+ status = pTpAllocWork(&work, work_release_cb, semaphores[1], &environment);
|
||||
+ ok(!status, "TpAllocWork failed with status %x\n", status);
|
||||
+ ok(work != NULL, "expected work != NULL\n");
|
||||
+ pTpPostWork(work);
|
||||
+
|
||||
+ result = WaitForSingleObject(semaphores[1], 1000);
|
||||
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
|
||||
+ pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
|
||||
+
|
||||
/* 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 61f6ea0..a572869 100644
|
||||
--- a/dlls/ntdll/threadpool.c
|
||||
+++ b/dlls/ntdll/threadpool.c
|
||||
@@ -1948,7 +1948,7 @@ static void tp_object_submit( struct threadpool_object *object, BOOL signaled )
|
||||
*
|
||||
* Cancels all currently pending callbacks for a specific object.
|
||||
*/
|
||||
-static void tp_object_cancel( struct threadpool_object *object, BOOL group_cancel, PVOID userdata )
|
||||
+static void tp_object_cancel( struct threadpool_object *object )
|
||||
{
|
||||
struct threadpool *pool = object->pool;
|
||||
LONG pending_callbacks = 0;
|
||||
@@ -1965,15 +1965,6 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance
|
||||
}
|
||||
RtlLeaveCriticalSection( &pool->cs );
|
||||
|
||||
- /* Execute group cancellation callback if defined, and if this was actually a group cancel. */
|
||||
- if (group_cancel && 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 );
|
||||
- }
|
||||
-
|
||||
while (pending_callbacks--)
|
||||
tp_object_release( object );
|
||||
}
|
||||
@@ -2598,7 +2589,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p
|
||||
{
|
||||
LIST_FOR_EACH_ENTRY( object, &members, struct threadpool_object, group_entry )
|
||||
{
|
||||
- tp_object_cancel( object, TRUE, userdata );
|
||||
+ tp_object_cancel( object );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2607,6 +2598,16 @@ 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)
|
||||
+ {
|
||||
+ 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 );
|
||||
|
||||
@@ -2900,7 +2901,7 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending )
|
||||
TRACE( "%p %d\n", timer, cancel_pending );
|
||||
|
||||
if (cancel_pending)
|
||||
- tp_object_cancel( this, FALSE, NULL );
|
||||
+ tp_object_cancel( this );
|
||||
tp_object_wait( this, FALSE );
|
||||
}
|
||||
|
||||
@@ -2914,7 +2915,7 @@ VOID WINAPI TpWaitForWait( TP_WAIT *wait, BOOL cancel_pending )
|
||||
TRACE( "%p %d\n", wait, cancel_pending );
|
||||
|
||||
if (cancel_pending)
|
||||
- tp_object_cancel( this, FALSE, NULL );
|
||||
+ tp_object_cancel( this );
|
||||
tp_object_wait( this, FALSE );
|
||||
}
|
||||
|
||||
@@ -2928,6 +2929,6 @@ VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending )
|
||||
TRACE( "%p %u\n", work, cancel_pending );
|
||||
|
||||
if (cancel_pending)
|
||||
- tp_object_cancel( this, FALSE, NULL );
|
||||
+ tp_object_cancel( this );
|
||||
tp_object_wait( this, FALSE );
|
||||
}
|
||||
--
|
||||
2.9.0
|
||||
|
@ -1,114 +0,0 @@
|
||||
From 0415a5cdbebd81532008f059a163cd18da2ddadb Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 20 Aug 2016 22:38:43 +0200
|
||||
Subject: ntdll: Do not call group cancel callback for finished simple
|
||||
callbacks. (v2)
|
||||
|
||||
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
|
||||
---
|
||||
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
|
||||
|
@ -1,76 +0,0 @@
|
||||
From 6746c0e13d0536a3463ac05c4c6ca5124f3ee4cd Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 20 Aug 2016 21:24:52 +0200
|
||||
Subject: services: Remove synchronization for
|
||||
CloseThreadpoolCleanupGroupMembers.
|
||||
|
||||
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
|
||||
---
|
||||
programs/services/rpc.c | 28 ++++++++--------------------
|
||||
1 file changed, 8 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
|
||||
index 688e4a0..bd6af95 100644
|
||||
--- a/programs/services/rpc.c
|
||||
+++ b/programs/services/rpc.c
|
||||
@@ -85,30 +85,22 @@ struct sc_lock
|
||||
struct scmdatabase *db;
|
||||
};
|
||||
|
||||
-static CRITICAL_SECTION shutdown_cs;
|
||||
-static CRITICAL_SECTION_DEBUG critsect_debug =
|
||||
-{
|
||||
- 0, 0, &shutdown_cs,
|
||||
- { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
|
||||
- 0, 0, { (DWORD_PTR)(__FILE__ ": shutdown_cs") }
|
||||
-};
|
||||
-static CRITICAL_SECTION shutdown_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
|
||||
-static BOOL service_shutdown;
|
||||
-
|
||||
static PTP_CLEANUP_GROUP cleanup_group;
|
||||
HANDLE exit_event;
|
||||
|
||||
+static void CALLBACK group_cancel_callback(void *object, void *userdata)
|
||||
+{
|
||||
+ struct process_entry *process = object;
|
||||
+ release_process(process);
|
||||
+}
|
||||
+
|
||||
static void CALLBACK terminate_callback(TP_CALLBACK_INSTANCE *instance, void *context,
|
||||
TP_WAIT *wait, TP_WAIT_RESULT result)
|
||||
{
|
||||
struct process_entry *process = context;
|
||||
if (result == WAIT_TIMEOUT) process_terminate(process);
|
||||
release_process(process);
|
||||
-
|
||||
- /* synchronize with CloseThreadpoolCleanupGroupMembers */
|
||||
- EnterCriticalSection(&shutdown_cs);
|
||||
- if (!service_shutdown) CloseThreadpoolWait(wait);
|
||||
- LeaveCriticalSection(&shutdown_cs);
|
||||
+ CloseThreadpoolWait(wait);
|
||||
}
|
||||
|
||||
static void terminate_after_timeout(struct process_entry *process, DWORD timeout)
|
||||
@@ -121,6 +113,7 @@ static void terminate_after_timeout(struct process_entry *process, DWORD timeout
|
||||
memset(&environment, 0, sizeof(environment));
|
||||
environment.Version = 1;
|
||||
environment.CleanupGroup = cleanup_group;
|
||||
+ environment.CleanupGroupCancelCallback = group_cancel_callback;
|
||||
|
||||
timestamp.QuadPart = (ULONGLONG)timeout * -10000;
|
||||
ft.dwLowDateTime = timestamp.u.LowPart;
|
||||
@@ -1914,11 +1907,6 @@ void RPC_Stop(void)
|
||||
RpcMgmtStopServerListening(NULL);
|
||||
RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
|
||||
|
||||
- /* synchronize with CloseThreadpoolWait */
|
||||
- EnterCriticalSection(&shutdown_cs);
|
||||
- service_shutdown = TRUE;
|
||||
- LeaveCriticalSection(&shutdown_cs);
|
||||
-
|
||||
CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
|
||||
CloseThreadpoolCleanupGroup(cleanup_group);
|
||||
CloseHandle(exit_event);
|
||||
--
|
||||
2.9.0
|
||||
|
@ -1 +0,0 @@
|
||||
Fixes: Fix multiple bugs related to threadpool cleanup groups and cancel callbacks
|
@ -1,419 +0,0 @@
|
||||
From 1da1bc40cd02cab32f45b0f043bdf37add0bac7a Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Timoshkov <dmitry@baikal.ru>
|
||||
Date: Mon, 21 Mar 2016 14:34:04 +0800
|
||||
Subject: gdiplus: Reimplement metafile loading using gdi32 instead of
|
||||
IPicture. (v2)
|
||||
|
||||
---
|
||||
dlls/gdiplus/Makefile.in | 2 +-
|
||||
dlls/gdiplus/gdiplus_private.h | 1 -
|
||||
dlls/gdiplus/graphics.c | 18 +---
|
||||
dlls/gdiplus/image.c | 205 +++++++++++++++++++++--------------------
|
||||
dlls/gdiplus/metafile.c | 1 -
|
||||
dlls/gdiplus/tests/image.c | 10 +-
|
||||
6 files changed, 113 insertions(+), 124 deletions(-)
|
||||
|
||||
diff --git a/dlls/gdiplus/Makefile.in b/dlls/gdiplus/Makefile.in
|
||||
index 6495eb7..ac12bd1 100644
|
||||
--- a/dlls/gdiplus/Makefile.in
|
||||
+++ b/dlls/gdiplus/Makefile.in
|
||||
@@ -1,6 +1,6 @@
|
||||
MODULE = gdiplus.dll
|
||||
IMPORTLIB = gdiplus
|
||||
-IMPORTS = uuid shlwapi oleaut32 ole32 user32 gdi32
|
||||
+IMPORTS = uuid shlwapi ole32 user32 gdi32
|
||||
DELAYIMPORTS = windowscodecs
|
||||
|
||||
C_SRCS = \
|
||||
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
|
||||
index 4ad49ca..4658fee 100644
|
||||
--- a/dlls/gdiplus/gdiplus_private.h
|
||||
+++ b/dlls/gdiplus/gdiplus_private.h
|
||||
@@ -333,7 +333,6 @@ struct GpAdjustableArrowCap{
|
||||
};
|
||||
|
||||
struct GpImage{
|
||||
- IPicture *picture;
|
||||
IWICBitmapDecoder *decoder;
|
||||
ImageType type;
|
||||
GUID format;
|
||||
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
|
||||
index 370fa88..a045c61 100644
|
||||
--- a/dlls/gdiplus/graphics.c
|
||||
+++ b/dlls/gdiplus/graphics.c
|
||||
@@ -2904,23 +2904,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
||||
srcheight = units_to_pixels(srcheight, srcUnit, image->yres);
|
||||
TRACE("src pixels: %f,%f %fx%f\n", srcx, srcy, srcwidth, srcheight);
|
||||
|
||||
- if (image->picture)
|
||||
- {
|
||||
- if (!graphics->hdc)
|
||||
- {
|
||||
- FIXME("graphics object has no HDC\n");
|
||||
- }
|
||||
-
|
||||
- if(IPicture_Render(image->picture, graphics->hdc,
|
||||
- pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
|
||||
- srcx, srcy, srcwidth, srcheight, NULL) != S_OK)
|
||||
- {
|
||||
- if(callback)
|
||||
- callback(callbackData);
|
||||
- return GenericError;
|
||||
- }
|
||||
- }
|
||||
- else if (image->type == ImageTypeBitmap)
|
||||
+ if (image->type == ImageTypeBitmap)
|
||||
{
|
||||
GpBitmap* bitmap = (GpBitmap*)image;
|
||||
BOOL do_resampling = FALSE;
|
||||
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
|
||||
index c3f6a5e..bee40b9 100644
|
||||
--- a/dlls/gdiplus/image.c
|
||||
+++ b/dlls/gdiplus/image.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Google (Evan Stade)
|
||||
- * Copyright (C) 2012 Dmitry Timoshkov
|
||||
+ * Copyright (C) 2012,2016 Dmitry Timoshkov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -124,34 +124,6 @@ static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteT
|
||||
return palette;
|
||||
}
|
||||
|
||||
-static INT ipicture_pixel_height(IPicture *pic)
|
||||
-{
|
||||
- HDC hdcref;
|
||||
- OLE_YSIZE_HIMETRIC y;
|
||||
-
|
||||
- IPicture_get_Height(pic, &y);
|
||||
-
|
||||
- hdcref = CreateCompatibleDC(0);
|
||||
- y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
|
||||
- DeleteDC(hdcref);
|
||||
-
|
||||
- return y;
|
||||
-}
|
||||
-
|
||||
-static INT ipicture_pixel_width(IPicture *pic)
|
||||
-{
|
||||
- HDC hdcref;
|
||||
- OLE_XSIZE_HIMETRIC x;
|
||||
-
|
||||
- IPicture_get_Width(pic, &x);
|
||||
-
|
||||
- hdcref = CreateCompatibleDC(0);
|
||||
- x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
|
||||
- DeleteDC(hdcref);
|
||||
-
|
||||
- return x;
|
||||
-}
|
||||
-
|
||||
GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
|
||||
RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
|
||||
{
|
||||
@@ -1309,45 +1281,12 @@ GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
|
||||
|
||||
GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
|
||||
{
|
||||
- GpStatus stat = GenericError;
|
||||
-
|
||||
TRACE("%p, %p\n", image, cloneImage);
|
||||
|
||||
if (!image || !cloneImage)
|
||||
return InvalidParameter;
|
||||
|
||||
- if (image->picture)
|
||||
- {
|
||||
- IStream* stream;
|
||||
- HRESULT hr;
|
||||
- INT size;
|
||||
- LARGE_INTEGER move;
|
||||
-
|
||||
- hr = CreateStreamOnHGlobal(0, TRUE, &stream);
|
||||
- if (FAILED(hr))
|
||||
- return GenericError;
|
||||
-
|
||||
- hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
|
||||
- if(FAILED(hr))
|
||||
- {
|
||||
- WARN("Failed to save image on stream\n");
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- /* Set seek pointer back to the beginning of the picture */
|
||||
- move.QuadPart = 0;
|
||||
- hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
|
||||
- if (FAILED(hr))
|
||||
- goto out;
|
||||
-
|
||||
- stat = GdipLoadImageFromStream(stream, cloneImage);
|
||||
- if (stat != Ok) WARN("Failed to load image from stream\n");
|
||||
-
|
||||
- out:
|
||||
- IStream_Release(stream);
|
||||
- return stat;
|
||||
- }
|
||||
- else if (image->type == ImageTypeBitmap)
|
||||
+ if (image->type == ImageTypeBitmap)
|
||||
{
|
||||
GpBitmap *bitmap = (GpBitmap *)image;
|
||||
|
||||
@@ -1884,7 +1823,6 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
|
||||
(*bitmap)->width = width;
|
||||
(*bitmap)->height = height;
|
||||
(*bitmap)->format = format;
|
||||
- (*bitmap)->image.picture = NULL;
|
||||
(*bitmap)->image.decoder = NULL;
|
||||
(*bitmap)->hbitmap = hbitmap;
|
||||
(*bitmap)->hdc = NULL;
|
||||
@@ -2152,8 +2090,6 @@ static GpStatus free_image_data(GpImage *image)
|
||||
WARN("invalid image: %p\n", image);
|
||||
return ObjectBusy;
|
||||
}
|
||||
- if (image->picture)
|
||||
- IPicture_Release(image->picture);
|
||||
if (image->decoder)
|
||||
IWICBitmapDecoder_Release(image->decoder);
|
||||
heap_free(image->palette);
|
||||
@@ -2219,12 +2155,6 @@ GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
|
||||
srcRect->Height = (REAL) ((GpBitmap*)image)->height;
|
||||
*srcUnit = UnitPixel;
|
||||
}
|
||||
- else{
|
||||
- srcRect->X = srcRect->Y = 0.0;
|
||||
- srcRect->Width = ipicture_pixel_width(image->picture);
|
||||
- srcRect->Height = ipicture_pixel_height(image->picture);
|
||||
- *srcUnit = UnitPixel;
|
||||
- }
|
||||
|
||||
TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
|
||||
srcRect->Width, srcRect->Height, *srcUnit);
|
||||
@@ -2248,10 +2178,6 @@ GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
|
||||
*height = ((GpBitmap*)image)->height;
|
||||
*width = ((GpBitmap*)image)->width;
|
||||
}
|
||||
- else{
|
||||
- *height = ipicture_pixel_height(image->picture);
|
||||
- *width = ipicture_pixel_width(image->picture);
|
||||
- }
|
||||
|
||||
TRACE("returning (%f, %f)\n", *height, *width);
|
||||
return Ok;
|
||||
@@ -2306,8 +2232,6 @@ GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
|
||||
*height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
|
||||
else if(image->type == ImageTypeBitmap)
|
||||
*height = ((GpBitmap*)image)->height;
|
||||
- else
|
||||
- *height = ipicture_pixel_height(image->picture);
|
||||
|
||||
TRACE("returning %d\n", *height);
|
||||
|
||||
@@ -2406,8 +2330,6 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
|
||||
*width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
|
||||
else if(image->type == ImageTypeBitmap)
|
||||
*width = ((GpBitmap*)image)->width;
|
||||
- else
|
||||
- *width = ipicture_pixel_width(image->picture);
|
||||
|
||||
TRACE("returning %d\n", *width);
|
||||
|
||||
@@ -4037,33 +3959,118 @@ static GpStatus decode_image_tiff(IStream* stream, GpImage **image)
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatTiff, NULL, image);
|
||||
}
|
||||
|
||||
-static GpStatus decode_image_olepicture_metafile(IStream* stream, GpImage **image)
|
||||
+static GpStatus load_wmf(IStream *stream, GpMetafile **metafile)
|
||||
+{
|
||||
+ GpStatus status = GenericError;
|
||||
+ HRESULT hr;
|
||||
+ UINT size;
|
||||
+ LARGE_INTEGER pos;
|
||||
+ WmfPlaceableFileHeader pfh;
|
||||
+ BOOL is_placeable = FALSE;
|
||||
+ METAHEADER mh;
|
||||
+ HMETAFILE hmf;
|
||||
+ void *buf;
|
||||
+
|
||||
+ pos.QuadPart = 0;
|
||||
+ IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
|
||||
+
|
||||
+ hr = IStream_Read(stream, &mh, sizeof(mh), &size);
|
||||
+ if (hr != S_OK || size != sizeof(mh))
|
||||
+ return GenericError;
|
||||
+
|
||||
+ if (mh.mtType == 0xcdd7 && mh.mtHeaderSize == 0x9ac6)
|
||||
+ {
|
||||
+ is_placeable = TRUE;
|
||||
+
|
||||
+ pos.QuadPart = 0;
|
||||
+ IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
|
||||
+
|
||||
+ hr = IStream_Read(stream, &pfh, sizeof(pfh), &size);
|
||||
+ if (hr != S_OK || size != sizeof(pfh))
|
||||
+ return GenericError;
|
||||
+
|
||||
+ hr = IStream_Read(stream, &mh, sizeof(mh), &size);
|
||||
+ if (hr != S_OK || size != sizeof(mh))
|
||||
+ return GenericError;
|
||||
+ }
|
||||
+
|
||||
+ pos.QuadPart = is_placeable ? sizeof(pfh) : 0;
|
||||
+ IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
|
||||
+
|
||||
+ buf = heap_alloc(mh.mtSize * 2);
|
||||
+ if (!buf) return OutOfMemory;
|
||||
+
|
||||
+ hr = IStream_Read(stream, buf, mh.mtSize * 2, &size);
|
||||
+ if (hr == S_OK && size == mh.mtSize * 2)
|
||||
+ {
|
||||
+ hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf);
|
||||
+ if (hmf)
|
||||
+ {
|
||||
+ status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile);
|
||||
+ if (status != Ok)
|
||||
+ DeleteMetaFile(hmf);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ heap_free(buf);
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+static GpStatus load_emf(IStream *stream, GpMetafile **metafile)
|
||||
{
|
||||
- IPicture *pic;
|
||||
+ GpStatus status = GenericError;
|
||||
+ HRESULT hr;
|
||||
+ UINT size;
|
||||
+ LARGE_INTEGER pos;
|
||||
+ ENHMETAHEADER emh;
|
||||
+ HENHMETAFILE hemf;
|
||||
+ void *buf;
|
||||
+
|
||||
+ pos.QuadPart = 0;
|
||||
+ IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
|
||||
+
|
||||
+ hr = IStream_Read(stream, &emh, sizeof(emh), &size);
|
||||
+ if (hr != S_OK || size != sizeof(emh) || emh.dSignature != ENHMETA_SIGNATURE)
|
||||
+ return GenericError;
|
||||
+
|
||||
+ pos.QuadPart = 0;
|
||||
+ IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
|
||||
+
|
||||
+ buf = heap_alloc(emh.nBytes);
|
||||
+ if (!buf) return OutOfMemory;
|
||||
+
|
||||
+ hr = IStream_Read(stream, buf, emh.nBytes, &size);
|
||||
+ if (hr == S_OK && size == emh.nBytes)
|
||||
+ {
|
||||
+ hemf = SetEnhMetaFileBits(emh.nBytes, buf);
|
||||
+ if (hemf)
|
||||
+ {
|
||||
+ status = GdipCreateMetafileFromEmf(hemf, FALSE, metafile);
|
||||
+ if (status != Ok)
|
||||
+ DeleteEnhMetaFile(hemf);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ heap_free(buf);
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+static GpStatus decode_image_metafile(IStream *stream, GpImage **image)
|
||||
+{
|
||||
+ GpMetafile *metafile;
|
||||
|
||||
TRACE("%p %p\n", stream, image);
|
||||
|
||||
if(!stream || !image)
|
||||
return InvalidParameter;
|
||||
|
||||
- if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
|
||||
- (LPVOID*) &pic) != S_OK){
|
||||
- TRACE("Could not load picture\n");
|
||||
+ if (load_emf(stream, &metafile) != Ok && load_wmf(stream, &metafile) != Ok)
|
||||
+ {
|
||||
+ TRACE("Could not load metafile\n");
|
||||
return GenericError;
|
||||
}
|
||||
|
||||
- /* FIXME: missing initialization code */
|
||||
- *image = heap_alloc_zero(sizeof(GpMetafile));
|
||||
- if(!*image) return OutOfMemory;
|
||||
- (*image)->type = ImageTypeMetafile;
|
||||
- (*image)->decoder = NULL;
|
||||
- (*image)->picture = pic;
|
||||
- (*image)->flags = ImageFlagsNone;
|
||||
- (*image)->frame_count = 1;
|
||||
- (*image)->current_frame = 0;
|
||||
- (*image)->palette = NULL;
|
||||
- list_init(&(*(GpMetafile**)image)->containers);
|
||||
-
|
||||
+ *image = (GpImage *)metafile;
|
||||
TRACE("<-- %p\n", *image);
|
||||
|
||||
return Ok;
|
||||
@@ -4721,7 +4728,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
||||
/* SigMask */ emf_sig_mask,
|
||||
},
|
||||
NULL,
|
||||
- decode_image_olepicture_metafile,
|
||||
+ decode_image_metafile,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
@@ -4741,7 +4748,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
||||
/* SigMask */ wmf_sig_mask,
|
||||
},
|
||||
NULL,
|
||||
- decode_image_olepicture_metafile,
|
||||
+ decode_image_metafile,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
|
||||
index a854e55..8b93e81 100644
|
||||
--- a/dlls/gdiplus/metafile.c
|
||||
+++ b/dlls/gdiplus/metafile.c
|
||||
@@ -317,7 +317,6 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF
|
||||
}
|
||||
|
||||
(*metafile)->image.type = ImageTypeMetafile;
|
||||
- (*metafile)->image.picture = NULL;
|
||||
(*metafile)->image.flags = ImageFlagsNone;
|
||||
(*metafile)->image.palette = NULL;
|
||||
(*metafile)->image.xres = dpix;
|
||||
diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c
|
||||
index ad84feb..cabd2fce 100644
|
||||
--- a/dlls/gdiplus/tests/image.c
|
||||
+++ b/dlls/gdiplus/tests/image.c
|
||||
@@ -1446,19 +1446,19 @@ static void test_loadwmf(void)
|
||||
|
||||
stat = GdipGetImageBounds(img, &bounds, &unit);
|
||||
expect(Ok, stat);
|
||||
- todo_wine expect(UnitPixel, unit);
|
||||
+ expect(UnitPixel, unit);
|
||||
expectf(0.0, bounds.X);
|
||||
expectf(0.0, bounds.Y);
|
||||
- todo_wine expectf(320.0, bounds.Width);
|
||||
- todo_wine expectf(320.0, bounds.Height);
|
||||
+ expectf(320.0, bounds.Width);
|
||||
+ expectf(320.0, bounds.Height);
|
||||
|
||||
stat = GdipGetImageHorizontalResolution(img, &res);
|
||||
expect(Ok, stat);
|
||||
- todo_wine expectf(1440.0, res);
|
||||
+ expectf(1440.0, res);
|
||||
|
||||
stat = GdipGetImageVerticalResolution(img, &res);
|
||||
expect(Ok, stat);
|
||||
- todo_wine expectf(1440.0, res);
|
||||
+ expectf(1440.0, res);
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
stat = GdipGetMetafileHeaderFromMetafile((GpMetafile*)img, &header);
|
||||
--
|
||||
2.9.0
|
||||
|
@ -52,13 +52,13 @@ usage()
|
||||
# Get the upstream commit sha
|
||||
upstream_commit()
|
||||
{
|
||||
echo "a83d5d3b83042d2305de0595c0d03e4e7bf1e29e"
|
||||
echo "90173ce448e5afe55627c2cbece28fb4f6bae99d"
|
||||
}
|
||||
|
||||
# Show version information
|
||||
version()
|
||||
{
|
||||
echo "Wine Staging 1.9.17"
|
||||
echo "Wine Staging 1.9.18 (unreleased)"
|
||||
echo "Copyright (C) 2014-2016 the Wine Staging project authors."
|
||||
echo ""
|
||||
echo "Patchset to be applied on upstream Wine:"
|
||||
@ -238,7 +238,6 @@ patch_enable_all ()
|
||||
enable_ntdll_SystemRoot_Symlink="$1"
|
||||
enable_ntdll_ThreadTime="$1"
|
||||
enable_ntdll_Threading="$1"
|
||||
enable_ntdll_ThreadpoolCleanupGroup="$1"
|
||||
enable_ntdll_User_Shared_Data="$1"
|
||||
enable_ntdll_WRITECOPY="$1"
|
||||
enable_ntdll_Wait_User_APC="$1"
|
||||
@ -888,9 +887,6 @@ patch_enable ()
|
||||
ntdll-Threading)
|
||||
enable_ntdll_Threading="$2"
|
||||
;;
|
||||
ntdll-ThreadpoolCleanupGroup)
|
||||
enable_ntdll_ThreadpoolCleanupGroup="$2"
|
||||
;;
|
||||
ntdll-User_Shared_Data)
|
||||
enable_ntdll_User_Shared_Data="$2"
|
||||
;;
|
||||
@ -2095,6 +2091,13 @@ if test "$enable_server_Stored_ACLs" -eq 1; then
|
||||
enable_server_File_Permissions=1
|
||||
fi
|
||||
|
||||
if test "$enable_oleaut32_OLEPictureImpl_SaveAsFile" -eq 1; then
|
||||
if test "$enable_oleaut32_Load_Save_EMF" -gt 1; then
|
||||
abort "Patchset oleaut32-Load_Save_EMF disabled, but oleaut32-OLEPictureImpl_SaveAsFile depends on that."
|
||||
fi
|
||||
enable_oleaut32_Load_Save_EMF=1
|
||||
fi
|
||||
|
||||
if test "$enable_nvencodeapi_Video_Encoder" -eq 1; then
|
||||
if test "$enable_nvcuvid_CUDA_Video_Support" -gt 1; then
|
||||
abort "Patchset nvcuvid-CUDA_Video_Support disabled, but nvencodeapi-Video_Encoder depends on that."
|
||||
@ -2234,20 +2237,6 @@ if test "$enable_imagehlp_ImageLoad" -eq 1; then
|
||||
enable_imagehlp_Cleanup=1
|
||||
fi
|
||||
|
||||
if test "$enable_gdiplus_GdipCreateMetafileFromStream" -eq 1; then
|
||||
if test "$enable_oleaut32_OLEPictureImpl_SaveAsFile" -gt 1; then
|
||||
abort "Patchset oleaut32-OLEPictureImpl_SaveAsFile disabled, but gdiplus-GdipCreateMetafileFromStream depends on that."
|
||||
fi
|
||||
enable_oleaut32_OLEPictureImpl_SaveAsFile=1
|
||||
fi
|
||||
|
||||
if test "$enable_oleaut32_OLEPictureImpl_SaveAsFile" -eq 1; then
|
||||
if test "$enable_oleaut32_Load_Save_EMF" -gt 1; then
|
||||
abort "Patchset oleaut32-Load_Save_EMF disabled, but oleaut32-OLEPictureImpl_SaveAsFile depends on that."
|
||||
fi
|
||||
enable_oleaut32_Load_Save_EMF=1
|
||||
fi
|
||||
|
||||
if test "$enable_dxva2_Video_Decoder" -eq 1; then
|
||||
if test "$enable_winecfg_Staging" -gt 1; then
|
||||
abort "Patchset winecfg-Staging disabled, but dxva2-Video_Decoder depends on that."
|
||||
@ -3716,51 +3705,8 @@ if test "$enable_gdi32_Symbol_Truetype_Font" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset oleaut32-Load_Save_EMF
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#40523] Implement support for loading and saving EMF to IPicture interface
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/oleaut32/olepicture.c, dlls/oleaut32/tests/olepicture.c
|
||||
# |
|
||||
if test "$enable_oleaut32_Load_Save_EMF" -eq 1; then
|
||||
patch_apply oleaut32-Load_Save_EMF/0001-oleaut32-tests-Add-some-tests-for-loading-and-saving.patch
|
||||
patch_apply oleaut32-Load_Save_EMF/0002-oleaut32-Add-support-for-loading-and-saving-EMF-to-I.patch
|
||||
(
|
||||
echo '+ { "Dmitry Timoshkov", "oleaut32/tests: Add some tests for loading and saving EMF using IPicture interface.", 1 },';
|
||||
echo '+ { "Dmitry Timoshkov", "oleaut32: Add support for loading and saving EMF to IPicture interface.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset oleaut32-OLEPictureImpl_SaveAsFile
|
||||
# |
|
||||
# | This patchset has the following (direct or indirect) dependencies:
|
||||
# | * oleaut32-Load_Save_EMF
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#8532] Implement a better stub for IPicture::SaveAsFile
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/gdiplus/Makefile.in, dlls/gdiplus/gdiplus_private.h, dlls/gdiplus/graphics.c, dlls/gdiplus/image.c,
|
||||
# | dlls/gdiplus/metafile.c, dlls/gdiplus/tests/image.c, dlls/oleaut32/olepicture.c, dlls/oleaut32/tests/olepicture.c
|
||||
# |
|
||||
if test "$enable_oleaut32_OLEPictureImpl_SaveAsFile" -eq 1; then
|
||||
patch_apply oleaut32-OLEPictureImpl_SaveAsFile/0001-gdiplus-Reimplement-metafile-loading-using-gdi32-ins.patch
|
||||
patch_apply oleaut32-OLEPictureImpl_SaveAsFile/0002-oleaut32-Implement-a-better-stub-for-IPicture-SaveAs.patch
|
||||
patch_apply oleaut32-OLEPictureImpl_SaveAsFile/0003-oleaut32-Implement-SaveAsFile-for-PICTYPE_ENHMETAFIL.patch
|
||||
(
|
||||
echo '+ { "Dmitry Timoshkov", "gdiplus: Reimplement metafile loading using gdi32 instead of IPicture.", 2 },';
|
||||
echo '+ { "Dmitry Timoshkov", "oleaut32: Implement a better stub for IPicture::SaveAsFile.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "oleaut32: Implement SaveAsFile for PICTYPE_ENHMETAFILE.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset gdiplus-GdipCreateMetafileFromStream
|
||||
# |
|
||||
# | This patchset has the following (direct or indirect) dependencies:
|
||||
# | * oleaut32-Load_Save_EMF, oleaut32-OLEPictureImpl_SaveAsFile
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#40325] Implement GdipCreateMetafileFromStream
|
||||
# | * [#27415] Implement GdipGetMetafileHeaderFromMetafile
|
||||
@ -5230,30 +5176,6 @@ if test "$enable_ntdll_Threading" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-ThreadpoolCleanupGroup
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/ntdll/tests/threadpool.c, dlls/ntdll/threadpool.c, programs/services/rpc.c
|
||||
# |
|
||||
if test "$enable_ntdll_ThreadpoolCleanupGroup" -eq 1; then
|
||||
patch_apply ntdll-ThreadpoolCleanupGroup/0001-ntdll-tests-Use-longer-waits-to-reduce-risk-of-rando.patch
|
||||
patch_apply ntdll-ThreadpoolCleanupGroup/0002-ntdll-Allow-to-release-threadpool-objects-while-wait.patch
|
||||
patch_apply ntdll-ThreadpoolCleanupGroup/0003-ntdll-tests-Add-tests-for-releasing-threadpool-objec.patch
|
||||
patch_apply ntdll-ThreadpoolCleanupGroup/0004-ntdll-Call-group-cancel-callback-with-the-correct-ar.patch
|
||||
patch_apply ntdll-ThreadpoolCleanupGroup/0005-ntdll-Group-cancel-callbacks-should-be-executed-afte.patch
|
||||
patch_apply ntdll-ThreadpoolCleanupGroup/0006-ntdll-Do-not-call-group-cancel-callback-for-finished.patch
|
||||
patch_apply ntdll-ThreadpoolCleanupGroup/0007-services-Remove-synchronization-for-CloseThreadpoolC.patch
|
||||
(
|
||||
echo '+ { "Sebastian Lackner", "ntdll/tests: Use longer waits to reduce risk of random failures on the testbot.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ntdll: Allow to release threadpool objects while waiting for group.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for releasing threadpool objects during TpReleaseCleanupGroupMembers.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ntdll: Call group cancel callback with the correct arguments.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ntdll: Group cancel callbacks should be executed after waiting for pending callbacks.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "ntdll: Do not call group cancel callback for finished simple callbacks.", 2 },';
|
||||
echo '+ { "Sebastian Lackner", "services: Remove synchronization for CloseThreadpoolCleanupGroupMembers.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset ntdll-User_Shared_Data
|
||||
# |
|
||||
# | Modified files:
|
||||
@ -5594,6 +5516,43 @@ if test "$enable_oleaut32_CreateTypeLib" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset oleaut32-Load_Save_EMF
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#40523] Implement support for loading and saving EMF to IPicture interface
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/oleaut32/olepicture.c, dlls/oleaut32/tests/olepicture.c
|
||||
# |
|
||||
if test "$enable_oleaut32_Load_Save_EMF" -eq 1; then
|
||||
patch_apply oleaut32-Load_Save_EMF/0001-oleaut32-tests-Add-some-tests-for-loading-and-saving.patch
|
||||
patch_apply oleaut32-Load_Save_EMF/0002-oleaut32-Add-support-for-loading-and-saving-EMF-to-I.patch
|
||||
(
|
||||
echo '+ { "Dmitry Timoshkov", "oleaut32/tests: Add some tests for loading and saving EMF using IPicture interface.", 1 },';
|
||||
echo '+ { "Dmitry Timoshkov", "oleaut32: Add support for loading and saving EMF to IPicture interface.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset oleaut32-OLEPictureImpl_SaveAsFile
|
||||
# |
|
||||
# | This patchset has the following (direct or indirect) dependencies:
|
||||
# | * oleaut32-Load_Save_EMF
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#8532] Implement a better stub for IPicture::SaveAsFile
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/oleaut32/olepicture.c, dlls/oleaut32/tests/olepicture.c
|
||||
# |
|
||||
if test "$enable_oleaut32_OLEPictureImpl_SaveAsFile" -eq 1; then
|
||||
patch_apply oleaut32-OLEPictureImpl_SaveAsFile/0002-oleaut32-Implement-a-better-stub-for-IPicture-SaveAs.patch
|
||||
patch_apply oleaut32-OLEPictureImpl_SaveAsFile/0003-oleaut32-Implement-SaveAsFile-for-PICTYPE_ENHMETAFIL.patch
|
||||
(
|
||||
echo '+ { "Dmitry Timoshkov", "oleaut32: Implement a better stub for IPicture::SaveAsFile.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "oleaut32: Implement SaveAsFile for PICTYPE_ENHMETAFILE.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset oleaut32-OleLoadPicture
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
|
@ -1 +1 @@
|
||||
Wine Staging 1.9.17
|
||||
Wine Staging 1.9.18 (unreleased)
|
||||
|
Loading…
Reference in New Issue
Block a user