diff --git a/README.md b/README.md index 1e257d96..cb9515e8 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ for more details.* * Implement stubs for ntoskrnl.Ex{Acquire,Release}FastMutexUnsafe * Implement stubs for ntoskrnl.ObReferenceObjectByPointer and ntoskrnl.ObDereferenceObject * ~~Implement threadpool timers~~ ([Wine Bug #37306](https://bugs.winehq.org/show_bug.cgi?id=37306)) -* Implement threadpool wait objects +* ~~Implement threadpool wait objects~~ * ~~Implement threadpool work items~~ ([Wine Bug #32531](https://bugs.winehq.org/show_bug.cgi?id=32531)) * Improve ReadDataAvailable handling in FilePipeLocalInformation class * Improve stub for AEV_GetVolumeRange ([Wine Bug #35658](https://bugs.winehq.org/show_bug.cgi?id=35658)) diff --git a/debian/changelog b/debian/changelog index f9d21b1b..a4e0c316 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,8 +3,7 @@ wine-staging (1.7.47) UNRELEASED; urgency=low upstream). * Removed patch to initialize *end with NULL on failure in msvcrt.strtod (accepted upstream). - * Partially removed patchset for new Threadpool implementation (accepted - upstream). + * Removed patchset for new Threadpool implementation (accepted upstream). -- Sebastian Lackner Mon, 29 Jun 2015 19:39:04 +0200 wine-staging (1.7.46) unstable; urgency=low diff --git a/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpAllocWait-and-TpReleaseWait.patch b/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpAllocWait-and-TpReleaseWait.patch deleted file mode 100644 index b11436d7..00000000 --- a/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpAllocWait-and-TpReleaseWait.patch +++ /dev/null @@ -1,146 +0,0 @@ -From f4397c4e7c279c41b12b03dfa1b368044de436f7 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 4 Jul 2015 04:11:31 +0200 -Subject: ntdll: Implement TpAllocWait and TpReleaseWait. - ---- - dlls/ntdll/ntdll.spec | 2 ++ - dlls/ntdll/threadpool.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 68 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index ce9d1bb..78814cd 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -973,6 +973,7 @@ - @ stdcall TpAllocCleanupGroup(ptr) - @ stdcall TpAllocPool(ptr ptr) - @ stdcall TpAllocTimer(ptr ptr ptr ptr) -+@ stdcall TpAllocWait(ptr ptr ptr ptr) - @ stdcall TpAllocWork(ptr ptr ptr ptr) - @ stdcall TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr) - @ stdcall TpCallbackMayRunLong(ptr) -@@ -987,6 +988,7 @@ - @ stdcall TpReleaseCleanupGroupMembers(ptr long ptr) - @ stdcall TpReleasePool(ptr) - @ stdcall TpReleaseTimer(ptr) -+@ stdcall TpReleaseWait(ptr) - @ stdcall TpReleaseWork(ptr) - @ stdcall TpSetPoolMaxThreads(ptr long) - @ stdcall TpSetPoolMinThreads(ptr long) -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index ef502ba..b9aece4 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -159,7 +159,8 @@ enum threadpool_objtype - { - TP_OBJECT_TYPE_SIMPLE, - TP_OBJECT_TYPE_WORK, -- TP_OBJECT_TYPE_TIMER -+ TP_OBJECT_TYPE_TIMER, -+ TP_OBJECT_TYPE_WAIT - }; - - /* internal threadpool object representation */ -@@ -209,6 +210,10 @@ struct threadpool_object - LONG period; - LONG window_length; - } timer; -+ struct -+ { -+ PTP_WAIT_CALLBACK callback; -+ } wait; - } u; - }; - -@@ -286,6 +291,13 @@ static inline struct threadpool_object *impl_from_TP_TIMER( TP_TIMER *timer ) - return object; - } - -+static inline struct threadpool_object *impl_from_TP_WAIT( TP_WAIT *wait ) -+{ -+ struct threadpool_object *object = (struct threadpool_object *)wait; -+ assert( object->type == TP_OBJECT_TYPE_WAIT ); -+ return object; -+} -+ - static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group ) - { - return (struct threadpool_group *)group; -@@ -1907,6 +1919,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) - break; - } - -+ case TP_OBJECT_TYPE_WAIT: -+ { -+ TRACE( "executing wait callback %p(%p, %p, %p, %u)\n", -+ object->u.wait.callback, callback_instance, object->userdata, object, WAIT_OBJECT_0 ); -+ object->u.wait.callback( callback_instance, object->userdata, (TP_WAIT *)object, WAIT_OBJECT_0 ); -+ TRACE( "callback %p returned\n", object->u.wait.callback ); -+ break; -+ } -+ - default: - assert(0); - break; -@@ -2052,6 +2073,37 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID - } - - /*********************************************************************** -+ * TpAllocWait (NTDLL.@) -+ */ -+NTSTATUS WINAPI TpAllocWait( TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID userdata, -+ TP_CALLBACK_ENVIRON *environment ) -+{ -+ struct threadpool_object *object; -+ struct threadpool *pool; -+ NTSTATUS status; -+ -+ TRACE( "%p %p %p %p\n", out, callback, userdata, environment ); -+ -+ object = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*object) ); -+ if (!object) -+ return STATUS_NO_MEMORY; -+ -+ status = tp_threadpool_lock( &pool, environment ); -+ if (status) -+ { -+ RtlFreeHeap( GetProcessHeap(), 0, object ); -+ return status; -+ } -+ -+ object->type = TP_OBJECT_TYPE_WAIT; -+ object->u.wait.callback = callback; -+ tp_object_initialize( object, pool, userdata, environment ); -+ -+ *out = (TP_WAIT *)object; -+ return STATUS_SUCCESS; -+} -+ -+/*********************************************************************** - * TpAllocWork (NTDLL.@) - */ - NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata, -@@ -2356,6 +2408,19 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer ) - } - - /*********************************************************************** -+ * TpReleaseWait (NTDLL.@) -+ */ -+VOID WINAPI TpReleaseWait( TP_WAIT *wait ) -+{ -+ struct threadpool_object *this = impl_from_TP_WAIT( wait ); -+ -+ TRACE( "%p\n", wait ); -+ -+ tp_object_shutdown( this ); -+ tp_object_release( this ); -+} -+ -+/*********************************************************************** - * TpReleaseWork (NTDLL.@) - */ - VOID WINAPI TpReleaseWork( TP_WORK *work ) --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0002-ntdll-Implement-threadpool-wait-queues.patch b/patches/ntdll-Vista_Threadpool/0002-ntdll-Implement-threadpool-wait-queues.patch deleted file mode 100644 index b4c0952b..00000000 --- a/patches/ntdll-Vista_Threadpool/0002-ntdll-Implement-threadpool-wait-queues.patch +++ /dev/null @@ -1,525 +0,0 @@ -From 4371c3cd5674720b230ec584199b7d5cbb67e2fc Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 4 Jul 2015 04:32:31 +0200 -Subject: ntdll: Implement threadpool wait queues. - ---- - dlls/ntdll/ntdll.spec | 2 + - dlls/ntdll/threadpool.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++-- - 2 files changed, 361 insertions(+), 8 deletions(-) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index 78814cd..75dc647 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -993,8 +993,10 @@ - @ stdcall TpSetPoolMaxThreads(ptr long) - @ stdcall TpSetPoolMinThreads(ptr long) - @ stdcall TpSetTimer(ptr ptr long long) -+@ stdcall TpSetWait(ptr long ptr) - @ stdcall TpSimpleTryPost(ptr ptr ptr) - @ stdcall TpWaitForTimer(ptr long) -+@ stdcall TpWaitForWait(ptr long) - @ stdcall TpWaitForWork(ptr long) - @ stdcall -ret64 VerSetConditionMask(int64 long long) - @ stdcall WinSqmIsOptedIn() -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index b9aece4..f86e965 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -137,6 +137,7 @@ struct timer_queue - */ - - #define THREADPOOL_WORKER_TIMEOUT 5000 -+#define MAXIMUM_WAITQUEUE_OBJECTS (MAXIMUM_WAIT_OBJECTS - 1) - - /* internal threadpool representation */ - struct threadpool -@@ -213,6 +214,13 @@ struct threadpool_object - struct - { - PTP_WAIT_CALLBACK callback; -+ LONG signaled; -+ /* information about the wait, locked via waitqueue.cs */ -+ struct waitqueue_bucket *bucket; -+ BOOL wait_pending; -+ struct list wait_entry; -+ ULONGLONG timeout; -+ HANDLE handle; - } wait; - } u; - }; -@@ -272,6 +280,38 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug = - 0, 0, { (DWORD_PTR)(__FILE__ ": timerqueue.cs") } - }; - -+/* global waitqueue object */ -+static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug; -+ -+static struct -+{ -+ CRITICAL_SECTION cs; -+ LONG num_buckets; -+ struct list buckets; -+} -+waitqueue = -+{ -+ { &waitqueue_debug, -1, 0, 0, 0, 0 }, /* cs */ -+ 0, /* num_buckets */ -+ LIST_INIT( waitqueue.buckets ) /* buckets */ -+}; -+ -+static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug = -+{ -+ 0, 0, &waitqueue.cs, -+ { &waitqueue_debug.ProcessLocksList, &waitqueue_debug.ProcessLocksList }, -+ 0, 0, { (DWORD_PTR)(__FILE__ ": waitqueue.cs") } -+}; -+ -+struct waitqueue_bucket -+{ -+ struct list bucket_entry; -+ LONG objcount; -+ struct list reserved; -+ struct list waiting; -+ HANDLE update_event; -+}; -+ - static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool ) - { - return (struct threadpool *)pool; -@@ -309,7 +349,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 ); -+static void tp_object_submit( struct threadpool_object *object, BOOL success ); - static void tp_object_shutdown( struct threadpool_object *object ); - static BOOL tp_object_release( struct threadpool_object *object ); - static struct threadpool *default_threadpool = NULL; -@@ -1261,7 +1301,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) - /* Queue a new callback in one of the worker threads. */ - list_remove( &timer->u.timer.timer_entry ); - timer->u.timer.timer_pending = FALSE; -- tp_object_submit( timer ); -+ tp_object_submit( timer, FALSE ); - - /* Insert the timer back into the queue, except its marked for shutdown. */ - if (timer->u.timer.period && !timer->shutdown) -@@ -1398,6 +1438,216 @@ static void tp_timerqueue_unlock( struct threadpool_object *timer ) - } - - /*********************************************************************** -+ * waitqueue_thread_proc (internal) -+ */ -+static void CALLBACK waitqueue_thread_proc( void *param ) -+{ -+ struct threadpool_object *objects[MAXIMUM_WAITQUEUE_OBJECTS]; -+ HANDLE handles[MAXIMUM_WAITQUEUE_OBJECTS + 1]; -+ struct waitqueue_bucket *bucket = param; -+ struct threadpool_object *wait, *next; -+ LARGE_INTEGER now, timeout; -+ DWORD num_handles; -+ NTSTATUS status; -+ -+ TRACE( "starting wait queue thread\n" ); -+ -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ -+ for (;;) -+ { -+ NtQuerySystemTime( &now ); -+ timeout.QuadPart = TIMEOUT_INFINITE; -+ num_handles = 0; -+ -+ /* Check for expired waits. */ -+ LIST_FOR_EACH_ENTRY_SAFE( wait, next, &bucket->waiting, struct threadpool_object, u.wait.wait_entry ) -+ { -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ if (wait->u.wait.timeout <= now.QuadPart) -+ { -+ /* Wait expired. */ -+ list_remove( &wait->u.wait.wait_entry ); -+ list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry ); -+ tp_object_submit( wait, FALSE ); -+ } -+ else -+ { -+ if (wait->u.wait.timeout < timeout.QuadPart) -+ timeout.QuadPart = wait->u.wait.timeout; -+ -+ /* Prepare wait, keep a reference to make sure the object doesn't get destroyed. */ -+ assert( num_handles < MAXIMUM_WAITQUEUE_OBJECTS ); -+ interlocked_inc( &wait->refcount ); -+ objects[num_handles] = wait; -+ handles[num_handles] = wait->u.wait.handle; -+ num_handles++; -+ } -+ } -+ -+ if (!bucket->objcount) -+ { -+ /* All wait objects have been destroyed, if no new wait objects are created -+ * within some amount of time, then we can shutdown this thread. */ -+ assert( num_handles == 0 ); -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+ timeout.QuadPart = (ULONGLONG)THREADPOOL_WORKER_TIMEOUT * -10000; -+ status = NtWaitForMultipleObjects( 1, &bucket->update_event, TRUE, FALSE, &timeout ); -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ -+ if (status == STATUS_TIMEOUT && !bucket->objcount) -+ break; -+ } -+ else -+ { -+ /* Wait for the next event. */ -+ handles[num_handles] = bucket->update_event; -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+ status = NtWaitForMultipleObjects( num_handles + 1, handles, TRUE, FALSE, &timeout ); -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ -+ if (status >= STATUS_WAIT_0 && status < STATUS_WAIT_0 + num_handles) -+ { -+ wait = objects[status - STATUS_WAIT_0]; -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ if (wait->u.wait.bucket) -+ { -+ /* Wait object signaled. */ -+ assert( wait->u.wait.bucket == bucket ); -+ list_remove( &wait->u.wait.wait_entry ); -+ list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry ); -+ tp_object_submit( wait, TRUE ); -+ } -+ else -+ ERR("wait object %p triggered while object was destroyed\n", wait); -+ } -+ } -+ -+ /* Release locked wait objects (if any). */ -+ while (num_handles) -+ { -+ wait = objects[--num_handles]; -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ tp_object_release( wait ); -+ } -+ } -+ -+ /* Remove this bucket from the list. */ -+ list_remove( &bucket->bucket_entry ); -+ if (!--waitqueue.num_buckets) -+ assert( list_empty( &waitqueue.buckets ) ); -+ -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+ -+ TRACE( "terminating wait queue thread\n" ); -+ -+ assert( bucket->objcount == 0 ); -+ assert( list_empty( &bucket->reserved ) ); -+ assert( list_empty( &bucket->waiting ) ); -+ NtClose( bucket->update_event ); -+ -+ RtlFreeHeap( GetProcessHeap(), 0, bucket ); -+} -+ -+/*********************************************************************** -+ * tp_waitqueue_lock (internal) -+ */ -+static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait ) -+{ -+ struct waitqueue_bucket *bucket; -+ NTSTATUS status; -+ HANDLE thread; -+ assert( wait->type = TP_OBJECT_TYPE_WAIT ); -+ -+ wait->u.wait.signaled = 0; -+ wait->u.wait.bucket = NULL; -+ wait->u.wait.wait_pending = FALSE; -+ wait->u.wait.timeout = 0; -+ wait->u.wait.handle = INVALID_HANDLE_VALUE; -+ -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ -+ /* Try to assign to existing bucket if possible. */ -+ LIST_FOR_EACH_ENTRY( bucket, &waitqueue.buckets, struct waitqueue_bucket, bucket_entry ) -+ { -+ if (bucket->objcount < MAXIMUM_WAITQUEUE_OBJECTS) -+ { -+ list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry ); -+ wait->u.wait.bucket = bucket; -+ bucket->objcount++; -+ -+ status = STATUS_SUCCESS; -+ goto out; -+ } -+ } -+ -+ /* Create a new bucket and corresponding worker thread. */ -+ bucket = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*bucket) ); -+ if (!bucket) -+ { -+ status = STATUS_NO_MEMORY; -+ goto out; -+ } -+ -+ bucket->objcount = 0; -+ list_init( &bucket->reserved ); -+ list_init( &bucket->waiting ); -+ -+ status = NtCreateEvent( &bucket->update_event, EVENT_ALL_ACCESS, -+ NULL, SynchronizationEvent, FALSE ); -+ if (status) -+ { -+ RtlFreeHeap( GetProcessHeap(), 0, bucket ); -+ goto out; -+ } -+ -+ status = RtlCreateUserThread( GetCurrentProcess(), NULL, FALSE, NULL, 0, 0, -+ waitqueue_thread_proc, bucket, &thread, NULL ); -+ if (status == STATUS_SUCCESS) -+ { -+ list_add_tail( &waitqueue.buckets, &bucket->bucket_entry ); -+ waitqueue.num_buckets++; -+ -+ list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry ); -+ wait->u.wait.bucket = bucket; -+ bucket->objcount++; -+ -+ NtClose( thread ); -+ } -+ else -+ { -+ NtClose( bucket->update_event ); -+ RtlFreeHeap( GetProcessHeap(), 0, bucket ); -+ } -+ -+out: -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+ return status; -+} -+ -+/*********************************************************************** -+ * tp_waitqueue_unlock (internal) -+ */ -+static void tp_waitqueue_unlock( struct threadpool_object *wait ) -+{ -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ if (wait->u.wait.bucket) -+ { -+ struct waitqueue_bucket *bucket = wait->u.wait.bucket; -+ assert( bucket->objcount > 0 ); -+ -+ list_remove( &wait->u.wait.wait_entry ); -+ wait->u.wait.bucket = NULL; -+ bucket->objcount--; -+ -+ NtSetEvent( bucket->update_event, NULL ); -+ } -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+} -+ -+/*********************************************************************** - * tp_threadpool_alloc (internal) - * - * Allocates a new threadpool object. -@@ -1666,7 +1916,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - * will be set, and tp_object_submit would fail with an assertion. */ - - if (is_simple_callback) -- tp_object_submit( object ); -+ tp_object_submit( object, FALSE ); - - if (object->group) - { -@@ -1692,7 +1942,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - * Submits a threadpool object to the associcated threadpool. This - * function has to be VOID because TpPostWork can never fail on Windows. - */ --static void tp_object_submit( struct threadpool_object *object ) -+static void tp_object_submit( struct threadpool_object *object, BOOL success ) - { - struct threadpool *pool = object->pool; - NTSTATUS status = STATUS_UNSUCCESSFUL; -@@ -1722,6 +1972,10 @@ static void tp_object_submit( struct threadpool_object *object ) - if (!object->num_pending_callbacks++) - list_add_tail( &pool->pool, &object->pool_entry ); - -+ /* Count how often the object was signaled. */ -+ if (object->type == TP_OBJECT_TYPE_WAIT && success) -+ object->u.wait.signaled++; -+ - /* No new thread started - wake up one existing thread. */ - if (status != STATUS_SUCCESS) - { -@@ -1748,6 +2002,9 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance - pending_callbacks = object->num_pending_callbacks; - object->num_pending_callbacks = 0; - list_remove( &object->pool_entry ); -+ -+ if (object->type == TP_OBJECT_TYPE_WAIT) -+ object->u.wait.signaled = 0; - } - RtlLeaveCriticalSection( &pool->cs ); - -@@ -1797,6 +2054,8 @@ static void tp_object_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; - } -@@ -1851,6 +2110,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - TP_CALLBACK_INSTANCE *callback_instance; - struct threadpool_instance instance; - struct threadpool *pool = param; -+ TP_WAIT_RESULT wait_result; - LARGE_INTEGER timeout; - struct list *ptr; - NTSTATUS status; -@@ -1871,6 +2131,13 @@ static void CALLBACK threadpool_worker_proc( void *param ) - if (--object->num_pending_callbacks) - list_add_tail( &pool->pool, &object->pool_entry ); - -+ /* For wait objects determine if the operation was successful. */ -+ if (object->type == TP_OBJECT_TYPE_WAIT) -+ { -+ wait_result = object->u.wait.signaled ? WAIT_OBJECT_0 : WAIT_TIMEOUT; -+ if (wait_result == WAIT_OBJECT_0) object->u.wait.signaled--; -+ } -+ - /* Leave critical section and do the actual callback. */ - object->num_associated_callbacks++; - object->num_running_callbacks++; -@@ -1922,8 +2189,8 @@ static void CALLBACK threadpool_worker_proc( void *param ) - case TP_OBJECT_TYPE_WAIT: - { - TRACE( "executing wait callback %p(%p, %p, %p, %u)\n", -- object->u.wait.callback, callback_instance, object->userdata, object, WAIT_OBJECT_0 ); -- object->u.wait.callback( callback_instance, object->userdata, (TP_WAIT *)object, WAIT_OBJECT_0 ); -+ object->u.wait.callback, callback_instance, object->userdata, object, wait_result ); -+ object->u.wait.callback( callback_instance, object->userdata, (TP_WAIT *)object, wait_result ); - TRACE( "callback %p returned\n", object->u.wait.callback ); - break; - } -@@ -2097,6 +2364,15 @@ NTSTATUS WINAPI TpAllocWait( TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID us - - object->type = TP_OBJECT_TYPE_WAIT; - object->u.wait.callback = callback; -+ -+ status = tp_waitqueue_lock( object ); -+ if (status) -+ { -+ tp_threadpool_unlock( pool ); -+ RtlFreeHeap( GetProcessHeap(), 0, object ); -+ return status; -+ } -+ - tp_object_initialize( object, pool, userdata, environment ); - - *out = (TP_WAIT *)object; -@@ -2304,7 +2580,7 @@ VOID WINAPI TpPostWork( TP_WORK *work ) - - TRACE( "%p\n", work ); - -- tp_object_submit( this ); -+ tp_object_submit( this, FALSE ); - } - - /*********************************************************************** -@@ -2558,7 +2834,68 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO - RtlLeaveCriticalSection( &timerqueue.cs ); - - if (submit_timer) -- tp_object_submit( this ); -+ tp_object_submit( this, FALSE ); -+} -+ -+/*********************************************************************** -+ * TpSetWait (KERNEL32.@) -+ */ -+VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout ) -+{ -+ struct threadpool_object *this = impl_from_TP_WAIT( wait ); -+ ULONGLONG timestamp = TIMEOUT_INFINITE; -+ BOOL submit_wait = FALSE; -+ -+ TRACE( "%p %p %p\n", wait, handle, timeout ); -+ -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ -+ assert( this->u.wait.bucket ); -+ this->u.wait.handle = handle; -+ -+ if (handle || this->u.wait.wait_pending) -+ { -+ struct waitqueue_bucket *bucket = this->u.wait.bucket; -+ list_remove( &this->u.wait.wait_entry ); -+ -+ /* Convert relative timeout to absolute timestamp. */ -+ if (handle && timeout) -+ { -+ timestamp = timeout->QuadPart; -+ if ((LONGLONG)timestamp < 0) -+ { -+ LARGE_INTEGER now; -+ NtQuerySystemTime( &now ); -+ timestamp = now.QuadPart - timestamp; -+ } -+ else if (!timestamp) -+ { -+ submit_wait = TRUE; -+ handle = NULL; -+ } -+ } -+ -+ /* Add wait object back into one of the queues. */ -+ if (handle) -+ { -+ list_add_tail( &bucket->waiting, &this->u.wait.wait_entry ); -+ this->u.wait.wait_pending = TRUE; -+ this->u.wait.timeout = timestamp; -+ } -+ else -+ { -+ list_add_tail( &bucket->reserved, &this->u.wait.wait_entry ); -+ this->u.wait.wait_pending = FALSE; -+ } -+ -+ /* Wake up the wait queue thread. */ -+ NtSetEvent( bucket->update_event, NULL ); -+ } -+ -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+ -+ if (submit_wait) -+ tp_object_submit( this, FALSE ); - } - - /*********************************************************************** -@@ -2606,6 +2943,20 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending ) - } - - /*********************************************************************** -+ * TpWaitForWait (KERNEL32.@) -+ */ -+VOID WINAPI TpWaitForWait( TP_WAIT *wait, BOOL cancel_pending ) -+{ -+ struct threadpool_object *this = impl_from_TP_WAIT( wait ); -+ -+ TRACE( "%p %d\n", wait, cancel_pending ); -+ -+ if (cancel_pending) -+ tp_object_cancel( this, FALSE, NULL ); -+ tp_object_wait( this, FALSE ); -+} -+ -+/*********************************************************************** - * TpWaitForWork (NTDLL.@) - */ - VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending ) --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0003-ntdll-tests-Add-basic-tests-for-threadpool-wait-obje.patch b/patches/ntdll-Vista_Threadpool/0003-ntdll-tests-Add-basic-tests-for-threadpool-wait-obje.patch deleted file mode 100644 index e3ded4d3..00000000 --- a/patches/ntdll-Vista_Threadpool/0003-ntdll-tests-Add-basic-tests-for-threadpool-wait-obje.patch +++ /dev/null @@ -1,334 +0,0 @@ -From ef697e2435d35ad1a53fd60209da7a7d4100dcf2 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 4 Jul 2015 04:36:23 +0200 -Subject: ntdll/tests: Add basic tests for threadpool wait objects. - ---- - dlls/ntdll/tests/threadpool.c | 266 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 266 insertions(+) - -diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index 0671202..c808400 100644 ---- a/dlls/ntdll/tests/threadpool.c -+++ b/dlls/ntdll/tests/threadpool.c -@@ -24,11 +24,13 @@ static HMODULE hntdll = 0; - static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **); - static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID); - static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); -+static NTSTATUS (WINAPI *pTpAllocWait)(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); - static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); - static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); - static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); - static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); - static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *); -+static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *); - static VOID (WINAPI *pTpPostWork)(TP_WORK *); - static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); - static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID); -@@ -37,8 +39,10 @@ static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *); - static VOID (WINAPI *pTpReleaseWork)(TP_WORK *); - static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD); - static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG); -+static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *); - static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); - static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL); -+static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL); - static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL); - - #define NTDLL_GET_PROC(func) \ -@@ -61,6 +65,7 @@ static BOOL init_threadpool(void) - NTDLL_GET_PROC(TpAllocCleanupGroup); - NTDLL_GET_PROC(TpAllocPool); - NTDLL_GET_PROC(TpAllocTimer); -+ NTDLL_GET_PROC(TpAllocWait); - NTDLL_GET_PROC(TpAllocWork); - NTDLL_GET_PROC(TpCallbackMayRunLong); - NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); -@@ -71,11 +76,14 @@ static BOOL init_threadpool(void) - NTDLL_GET_PROC(TpReleaseCleanupGroupMembers); - NTDLL_GET_PROC(TpReleasePool); - NTDLL_GET_PROC(TpReleaseTimer); -+ NTDLL_GET_PROC(TpReleaseWait); - NTDLL_GET_PROC(TpReleaseWork); - NTDLL_GET_PROC(TpSetPoolMaxThreads); - NTDLL_GET_PROC(TpSetTimer); -+ NTDLL_GET_PROC(TpSetWait); - NTDLL_GET_PROC(TpSimpleTryPost); - NTDLL_GET_PROC(TpWaitForTimer); -+ NTDLL_GET_PROC(TpWaitForWait); - NTDLL_GET_PROC(TpWaitForWork); - - if (!pTpAllocPool) -@@ -906,6 +914,263 @@ static void test_tp_window_length(void) - CloseHandle(semaphore); - } - -+struct wait_info -+{ -+ HANDLE semaphore; -+ LONG userdata; -+}; -+ -+static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, -+ TP_WAIT *wait, TP_WAIT_RESULT result) -+{ -+ struct wait_info *info = userdata; -+ trace("Running wait callback\n"); -+ -+ if (result == WAIT_OBJECT_0) -+ InterlockedIncrement(&info->userdata); -+ else if (result == WAIT_TIMEOUT) -+ InterlockedExchangeAdd(&info->userdata, 0x10000); -+ else -+ ok(0, "unexpected result %u\n", result); -+ ReleaseSemaphore(info->semaphore, 1, NULL); -+} -+ -+static void test_tp_wait(void) -+{ -+ TP_CALLBACK_ENVIRON environment; -+ TP_WAIT *wait1, *wait2; -+ struct wait_info info; -+ HANDLE semaphores[2]; -+ LARGE_INTEGER when; -+ NTSTATUS status; -+ TP_POOL *pool; -+ DWORD result; -+ -+ semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); -+ ok(semaphores[0] != NULL, "failed to create semaphore\n"); -+ semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); -+ ok(semaphores[1] != NULL, "failed to create semaphore\n"); -+ info.semaphore = semaphores[0]; -+ -+ /* 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 new wait items */ -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ -+ wait1 = NULL; -+ status = pTpAllocWait(&wait1, wait_cb, &info, &environment); -+ ok(!status, "TpAllocWait failed with status %x\n", status); -+ ok(wait1 != NULL, "expected wait1 != NULL\n"); -+ -+ wait2 = NULL; -+ status = pTpAllocWait(&wait2, wait_cb, &info, &environment); -+ ok(!status, "TpAllocWait failed with status %x\n", status); -+ ok(wait2 != NULL, "expected wait2 != NULL\n"); -+ -+ /* infinite timeout, signal the semaphore immediately */ -+ info.userdata = 0; -+ pTpSetWait(wait1, semaphores[1], NULL); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* relative timeout, no event */ -+ info.userdata = 0; -+ when.QuadPart = (ULONGLONG)200 * -10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[0], 200); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* repeat test with call to TpWaitForWait(..., TRUE) */ -+ info.userdata = 0; -+ when.QuadPart = (ULONGLONG)200 * -10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ pTpWaitForWait(wait1, TRUE); -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[0], 200); -+ ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, -+ "WaitForSingleObject returned %u\n", result); -+ if (result == WAIT_OBJECT_0) -+ ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); -+ else -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* relative timeout, with event */ -+ info.userdata = 0; -+ when.QuadPart = (ULONGLONG)200 * -10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* repeat test with call to TpWaitForWait(..., TRUE) */ -+ info.userdata = 0; -+ when.QuadPart = (ULONGLONG)200 * -10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ pTpWaitForWait(wait1, TRUE); -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, -+ "WaitForSingleObject returned %u\n", result); -+ if (result == WAIT_OBJECT_0) -+ { -+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ } -+ else -+ { -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ } -+ -+ /* absolute timeout, no event */ -+ info.userdata = 0; -+ NtQuerySystemTime( &when ); -+ when.QuadPart += (ULONGLONG)200 * 10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[0], 200); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* absolute timeout, with event */ -+ info.userdata = 0; -+ NtQuerySystemTime( &when ); -+ when.QuadPart += (ULONGLONG)200 * 10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* test timeout of zero */ -+ info.userdata = 0; -+ when.QuadPart = 0; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* cancel a pending wait */ -+ info.userdata = 0; -+ when.QuadPart = (ULONGLONG)250 * -10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ pTpSetWait(wait1, NULL, (void *)0xdeadbeef); -+ Sleep(50); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ -+ /* test with INVALID_HANDLE_VALUE */ -+ info.userdata = 0; -+ when.QuadPart = 0; -+ pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); -+ -+ /* cancel a pending wait with INVALID_HANDLE_VALUE */ -+ info.userdata = 0; -+ when.QuadPart = (ULONGLONG)250 * -10000; -+ pTpSetWait(wait1, semaphores[1], &when); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ when.QuadPart = 0; -+ pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); -+ Sleep(50); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ -+ CloseHandle(semaphores[1]); -+ semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL); -+ ok(semaphores[1] != NULL, "failed to create semaphore\n"); -+ -+ /* add two wait objects with the same semaphore */ -+ info.userdata = 0; -+ pTpSetWait(wait1, semaphores[1], NULL); -+ pTpSetWait(wait2, semaphores[1], NULL); -+ Sleep(50); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* repeat test above, but with a semaphore of count 2 */ -+ info.userdata = 0; -+ pTpSetWait(wait1, semaphores[1], NULL); -+ pTpSetWait(wait2, semaphores[1], NULL); -+ Sleep(50); -+ result = ReleaseSemaphore(semaphores[1], 2, NULL); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); -+ result = WaitForSingleObject(semaphores[1], 0); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ -+ /* cleanup */ -+ pTpReleaseWait(wait1); -+ pTpReleaseWait(wait2); -+ pTpReleasePool(pool); -+ CloseHandle(semaphores[0]); -+ CloseHandle(semaphores[1]); -+} -+ - START_TEST(threadpool) - { - if (!init_threadpool()) -@@ -919,4 +1184,5 @@ START_TEST(threadpool) - test_tp_disassociate(); - test_tp_timer(); - test_tp_window_length(); -+ test_tp_wait(); - } --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0004-ntdll-tests-Add-highly-multithreaded-wait-tests.patch b/patches/ntdll-Vista_Threadpool/0004-ntdll-tests-Add-highly-multithreaded-wait-tests.patch deleted file mode 100644 index 4db348b7..00000000 --- a/patches/ntdll-Vista_Threadpool/0004-ntdll-tests-Add-highly-multithreaded-wait-tests.patch +++ /dev/null @@ -1,147 +0,0 @@ -From fa0a0443778b2c4730a66ee4909681e0379673f4 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 4 Jul 2015 13:29:38 +0200 -Subject: ntdll/tests: Add highly multithreaded wait tests. - ---- - dlls/ntdll/tests/threadpool.c | 119 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 119 insertions(+) - -diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index c808400..7235dfd 100644 ---- a/dlls/ntdll/tests/threadpool.c -+++ b/dlls/ntdll/tests/threadpool.c -@@ -1171,6 +1171,124 @@ static void test_tp_wait(void) - CloseHandle(semaphores[1]); - } - -+static struct -+{ -+ HANDLE semaphore; -+ DWORD result; -+} multi_wait_info; -+ -+static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result) -+{ -+ DWORD index = (DWORD)(DWORD_PTR)userdata; -+ -+ if (result == WAIT_OBJECT_0) -+ multi_wait_info.result = index; -+ else if (result == WAIT_TIMEOUT) -+ multi_wait_info.result = 0x10000 | index; -+ else -+ ok(0, "unexpected result %u\n", result); -+ ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL); -+} -+ -+static void test_tp_multi_wait(void) -+{ -+ TP_CALLBACK_ENVIRON environment; -+ HANDLE semaphores[512]; -+ TP_WAIT *waits[512]; -+ LARGE_INTEGER when; -+ HANDLE semaphore; -+ NTSTATUS status; -+ TP_POOL *pool; -+ DWORD result; -+ int i; -+ -+ semaphore = CreateSemaphoreW(NULL, 0, 512, NULL); -+ ok(semaphore != NULL, "failed to create semaphore\n"); -+ multi_wait_info.semaphore = semaphore; -+ -+ /* 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"); -+ -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ -+ /* create semaphores, wait objects and enable them */ -+ for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) -+ { -+ semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL); -+ ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i); -+ -+ waits[i] = NULL; -+ status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment); -+ ok(!status, "TpAllocWait failed with status %x\n", status); -+ ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i); -+ -+ pTpSetWait(waits[i], semaphores[i], NULL); -+ } -+ -+ /* test releasing each semaphore */ -+ for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) -+ { -+ multi_wait_info.result = 0; -+ ReleaseSemaphore(semaphores[i], 1, NULL); -+ -+ result = WaitForSingleObject(semaphore, 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result); -+ -+ pTpSetWait(waits[i], semaphores[i], NULL); -+ } -+ -+ /* repeat the same test in reverse order */ -+ for (i = sizeof(semaphores)/sizeof(semaphores[0]) - 1; i >= 0; i--) -+ { -+ multi_wait_info.result = 0; -+ ReleaseSemaphore(semaphores[i], 1, NULL); -+ -+ result = WaitForSingleObject(semaphore, 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result); -+ -+ pTpSetWait(waits[i], semaphores[i], NULL); -+ } -+ -+ /* now test with a timeout */ -+ multi_wait_info.result = 0; -+ for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) -+ { -+ when.QuadPart = (ULONGLONG)50 * -10000; -+ pTpSetWait(waits[i], semaphores[i], &when); -+ } -+ for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) -+ { -+ result = WaitForSingleObject(semaphore, 100); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ } -+ ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n"); -+ -+ /* destroy the wait objects and semaphores while waiting - -+ * broken applications might do that too. */ -+ for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) -+ { -+ pTpSetWait(waits[i], semaphores[i], NULL); -+ } -+ -+ Sleep(50); -+ -+ for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) -+ { -+ pTpReleaseWait(waits[i]); -+ NtClose(semaphores[i]); -+ } -+ -+ pTpReleasePool(pool); -+ CloseHandle(semaphore); -+} -+ - START_TEST(threadpool) - { - if (!init_threadpool()) -@@ -1185,4 +1303,5 @@ START_TEST(threadpool) - test_tp_timer(); - test_tp_window_length(); - test_tp_wait(); -+ test_tp_multi_wait(); - } --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0005-ntdll-Try-to-merge-threadpool-wait-queue-buckets-if-.patch b/patches/ntdll-Vista_Threadpool/0005-ntdll-Try-to-merge-threadpool-wait-queue-buckets-if-.patch deleted file mode 100644 index d19a7935..00000000 --- a/patches/ntdll-Vista_Threadpool/0005-ntdll-Try-to-merge-threadpool-wait-queue-buckets-if-.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 6cdcda50c44c46c50feccc486f96a2e4e4818bfb Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 4 Jul 2015 15:54:45 +0200 -Subject: ntdll: Try to merge threadpool wait queue buckets if possible. - ---- - dlls/ntdll/threadpool.c | 40 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 40 insertions(+) - -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index f86e965..d6a57c3 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -1530,6 +1530,46 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - assert( wait->type == TP_OBJECT_TYPE_WAIT ); - tp_object_release( wait ); - } -+ -+ /* Try to merge bucket with other threads. */ -+ if (waitqueue.num_buckets > 1 && bucket->objcount && -+ bucket->objcount <= MAXIMUM_WAITQUEUE_OBJECTS * 1 / 3) -+ { -+ struct waitqueue_bucket *other_bucket; -+ LIST_FOR_EACH_ENTRY( other_bucket, &waitqueue.buckets, struct waitqueue_bucket, bucket_entry ) -+ { -+ if (other_bucket != bucket && other_bucket->objcount && -+ other_bucket->objcount + bucket->objcount <= MAXIMUM_WAITQUEUE_OBJECTS * 2 / 3) -+ { -+ other_bucket->objcount += bucket->objcount; -+ bucket->objcount = 0; -+ -+ /* Update reserved list. */ -+ LIST_FOR_EACH_ENTRY( wait, &bucket->reserved, struct threadpool_object, u.wait.wait_entry ) -+ { -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ wait->u.wait.bucket = other_bucket; -+ } -+ list_move_tail( &other_bucket->reserved, &bucket->reserved ); -+ -+ /* Update waiting list. */ -+ LIST_FOR_EACH_ENTRY( wait, &bucket->waiting, struct threadpool_object, u.wait.wait_entry ) -+ { -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ wait->u.wait.bucket = other_bucket; -+ } -+ list_move_tail( &other_bucket->waiting, &bucket->waiting ); -+ -+ /* Move bucket to the end, to keep the probability of -+ * newly added wait objects as small as possible. */ -+ list_remove( &bucket->bucket_entry ); -+ list_add_tail( &waitqueue.buckets, &bucket->bucket_entry ); -+ -+ NtSetEvent( other_bucket->update_event, NULL ); -+ break; -+ } -+ } -+ } - } - - /* Remove this bucket from the list. */ --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch b/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch deleted file mode 100644 index 78823797..00000000 --- a/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 25310b36af718466fc095b6dd9b86ce15d42e0ee Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Fri, 6 Feb 2015 20:24:27 +0100 -Subject: kernel32: Forward threadpool wait functions to ntdll. - ---- - dlls/kernel32/kernel32.spec | 8 ++++---- - dlls/kernel32/thread.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - include/winternl.h | 4 ++++ - 3 files changed, 51 insertions(+), 4 deletions(-) - -diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index a14d03b..77e55e1 100644 ---- a/dlls/kernel32/kernel32.spec -+++ b/dlls/kernel32/kernel32.spec -@@ -233,7 +233,7 @@ - @ stdcall CloseThreadpoolCleanupGroupMembers(ptr long ptr) ntdll.TpReleaseCleanupGroupMembers - # @ stub CloseThreadpoolIo - @ stdcall CloseThreadpoolTimer(ptr) ntdll.TpReleaseTimer --# @ stub CloseThreadpoolWait -+@ stdcall CloseThreadpoolWait(ptr) ntdll.TpReleaseWait - @ stdcall CloseThreadpoolWork(ptr) ntdll.TpReleaseWork - @ stdcall CmdBatNotification(long) - @ stdcall CommConfigDialogA(str long ptr) -@@ -335,7 +335,7 @@ - @ stdcall CreateThreadpoolCleanupGroup() - # @ stub CreateThreadpoolIo - @ stdcall CreateThreadpoolTimer(ptr ptr ptr) --# @ stub CreateThreadpoolWait -+@ stdcall CreateThreadpoolWait(ptr ptr ptr) - @ stdcall CreateThreadpoolWork(ptr ptr ptr) - @ stdcall CreateTimerQueue () - @ stdcall CreateTimerQueueTimer(ptr long ptr ptr long long long) -@@ -1457,7 +1457,7 @@ - @ stdcall SetThreadpoolThreadMaximum(ptr long) ntdll.TpSetPoolMaxThreads - @ stdcall SetThreadpoolThreadMinimum(ptr long) ntdll.TpSetPoolMinThreads - @ stdcall SetThreadpoolTimer(ptr ptr long long) --# @ stub SetThreadpoolWait -+@ stdcall SetThreadpoolWait(ptr long ptr) - @ stdcall SetTimeZoneInformation(ptr) - @ stub SetTimerQueueTimer - # @ stub -arch=x86_64 SetUmsThreadInformation -@@ -1572,7 +1572,7 @@ - @ stdcall WaitForSingleObjectEx(long long long) - # @ stub WaitForThreadpoolIoCallbacks - @ stdcall WaitForThreadpoolTimerCallbacks(ptr long) ntdll.TpWaitForTimer --# @ stub WaitForThreadpoolWaitCallbacks -+@ stdcall WaitForThreadpoolWaitCallbacks(ptr long) ntdll.TpWaitForWait - @ stdcall WaitForThreadpoolWorkCallbacks(ptr long) ntdll.TpWaitForWork - @ stdcall WaitNamedPipeA (str long) - @ stdcall WaitNamedPipeW (wstr long) -diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c -index 21ec276..c992e0d 100644 ---- a/dlls/kernel32/thread.c -+++ b/dlls/kernel32/thread.c -@@ -942,6 +942,27 @@ PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userd - } - - /*********************************************************************** -+ * CreateThreadpoolWait (KERNEL32.@) -+ */ -+PTP_WAIT WINAPI CreateThreadpoolWait( PTP_WAIT_CALLBACK callback, PVOID userdata, -+ TP_CALLBACK_ENVIRON *environment ) -+{ -+ TP_WAIT *wait; -+ NTSTATUS status; -+ -+ TRACE( "%p, %p, %p\n", callback, userdata, environment ); -+ -+ status = TpAllocWait( &wait, callback, userdata, environment ); -+ if (status) -+ { -+ SetLastError( RtlNtStatusToDosError(status) ); -+ return NULL; -+ } -+ -+ return wait; -+} -+ -+/*********************************************************************** - * CreateThreadpoolWork (KERNEL32.@) - */ - PTP_WORK WINAPI CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata, -@@ -982,6 +1003,28 @@ VOID WINAPI SetThreadpoolTimer( TP_TIMER *timer, FILETIME *due_time, - } - - /*********************************************************************** -+ * SetThreadpoolWait (KERNEL32.@) -+ */ -+VOID WINAPI SetThreadpoolWait( TP_WAIT *wait, HANDLE handle, FILETIME *due_time ) -+{ -+ LARGE_INTEGER timeout; -+ -+ TRACE( "%p, %p, %p\n", wait, handle, due_time ); -+ -+ if (!handle) -+ { -+ due_time = NULL; -+ } -+ else if (due_time) -+ { -+ timeout.u.LowPart = due_time->dwLowDateTime; -+ timeout.u.HighPart = due_time->dwHighDateTime; -+ } -+ -+ TpSetWait( wait, handle, due_time ? &timeout : NULL ); -+} -+ -+/*********************************************************************** - * TrySubmitThreadpoolCallback (KERNEL32.@) - */ - BOOL WINAPI TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback, PVOID userdata, -diff --git a/include/winternl.h b/include/winternl.h -index e1707fd..7ab1bd8 100644 ---- a/include/winternl.h -+++ b/include/winternl.h -@@ -2621,6 +2621,7 @@ NTSYSAPI NTSTATUS WINAPI RtlLargeIntegerToChar(const ULONGLONG *,ULONG,ULONG,PC - NTSYSAPI NTSTATUS WINAPI TpAllocCleanupGroup(TP_CLEANUP_GROUP **); - NTSYSAPI NTSTATUS WINAPI TpAllocPool(TP_POOL **,PVOID); - NTSYSAPI NTSTATUS WINAPI TpAllocTimer(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); -+NTSYSAPI NTSTATUS WINAPI TpAllocWait(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); - NTSYSAPI NTSTATUS WINAPI TpAllocWork(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); - NTSYSAPI void WINAPI TpCallbackLeaveCriticalSectionOnCompletion(TP_CALLBACK_INSTANCE *,RTL_CRITICAL_SECTION *); - NTSYSAPI NTSTATUS WINAPI TpCallbackMayRunLong(TP_CALLBACK_INSTANCE *); -@@ -2635,12 +2636,15 @@ NTSYSAPI void WINAPI TpReleaseCleanupGroup(TP_CLEANUP_GROUP *); - NTSYSAPI void WINAPI TpReleaseCleanupGroupMembers(TP_CLEANUP_GROUP *,BOOL,PVOID); - NTSYSAPI void WINAPI TpReleasePool(TP_POOL *); - NTSYSAPI void WINAPI TpReleaseTimer(TP_TIMER *); -+NTSYSAPI void WINAPI TpReleaseWait(TP_WAIT *); - NTSYSAPI void WINAPI TpReleaseWork(TP_WORK *); - NTSYSAPI void WINAPI TpSetPoolMaxThreads(TP_POOL *,DWORD); - NTSYSAPI BOOL WINAPI TpSetPoolMinThreads(TP_POOL *,DWORD); - NTSYSAPI void WINAPI TpSetTimer(TP_TIMER *, LARGE_INTEGER *,LONG,LONG); -+NTSYSAPI void WINAPI TpSetWait(TP_WAIT *,HANDLE,LARGE_INTEGER *); - NTSYSAPI NTSTATUS WINAPI TpSimpleTryPost(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); - NTSYSAPI void WINAPI TpWaitForTimer(TP_TIMER *,BOOL); -+NTSYSAPI void WINAPI TpWaitForWait(TP_WAIT *,BOOL); - NTSYSAPI void WINAPI TpWaitForWork(TP_WORK *,BOOL); - - /* Wine internal functions */ --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/definition b/patches/ntdll-Vista_Threadpool/definition deleted file mode 100644 index c7e3add8..00000000 --- a/patches/ntdll-Vista_Threadpool/definition +++ /dev/null @@ -1,4 +0,0 @@ -# Fixes: [35192] Add implementation for CreateThreadpool -# Fixes: [32531] Implement threadpool work items -# Fixes: [37306] Implement threadpool timers -Fixes: Implement threadpool wait objects diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index d7fc2445..ff533f89 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -55,7 +55,7 @@ version() echo "Copyright (C) 2014-2015 the Wine Staging project authors." echo "" echo "Patchset to be applied on upstream Wine:" - echo " commit 8b566b1da71a412fe58c3cc1988d610c2aba5f2d" + echo " commit f6653a93eb6796b733c6b0e9e289746692ab0a69" echo "" } @@ -175,7 +175,6 @@ patch_enable_all () enable_ntdll_ThreadTime="$1" enable_ntdll_Threading="$1" enable_ntdll_User_Shared_Data="$1" - enable_ntdll_Vista_Threadpool="$1" enable_ntdll_WRITECOPY="$1" enable_ntdll_WinSqm="$1" enable_ntdll_WriteWatches="$1" @@ -599,9 +598,6 @@ patch_enable () ntdll-User_Shared_Data) enable_ntdll_User_Shared_Data="$2" ;; - ntdll-Vista_Threadpool) - enable_ntdll_Vista_Threadpool="$2" - ;; ntdll-WRITECOPY) enable_ntdll_WRITECOPY="$2" ;; @@ -3689,29 +3685,6 @@ if test "$enable_ntdll_User_Shared_Data" -eq 1; then ) >> "$patchlist" fi -# Patchset ntdll-Vista_Threadpool -# | -# | Modified files: -# | * dlls/kernel32/kernel32.spec, dlls/kernel32/thread.c, dlls/ntdll/ntdll.spec, dlls/ntdll/tests/threadpool.c, -# | dlls/ntdll/threadpool.c, include/winternl.h -# | -if test "$enable_ntdll_Vista_Threadpool" -eq 1; then - patch_apply ntdll-Vista_Threadpool/0001-ntdll-Implement-TpAllocWait-and-TpReleaseWait.patch - patch_apply ntdll-Vista_Threadpool/0002-ntdll-Implement-threadpool-wait-queues.patch - patch_apply ntdll-Vista_Threadpool/0003-ntdll-tests-Add-basic-tests-for-threadpool-wait-obje.patch - patch_apply ntdll-Vista_Threadpool/0004-ntdll-tests-Add-highly-multithreaded-wait-tests.patch - patch_apply ntdll-Vista_Threadpool/0005-ntdll-Try-to-merge-threadpool-wait-queue-buckets-if-.patch - patch_apply ntdll-Vista_Threadpool/0006-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch - ( - echo '+ { "Sebastian Lackner", "ntdll: Implement TpAllocWait and TpReleaseWait.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool wait queues.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll/tests: Add basic tests for threadpool wait objects.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll/tests: Add highly multithreaded wait tests.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Try to merge threadpool wait queue buckets if possible.", 1 },'; - echo '+ { "Sebastian Lackner", "kernel32: Forward threadpool wait functions to ntdll.", 1 },'; - ) >> "$patchlist" -fi - # Patchset ntdll-WinSqm # | # | This patchset fixes the following Wine bugs: