From cde323b77245f9659346a6b7866af7120fcd1c35 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 4 Jul 2015 04:01:01 +0200 Subject: [PATCH] Rebase against 8b566b1da71a412fe58c3cc1988d610c2aba5f2d. --- README.md | 6 +- ...TpDisassociateCallback-and-add-separ.patch | 175 ----- ...l-Implement-threadpool-wait-objects.patch} | 617 +++++++++--------- ...Add-tests-for-TpDisassociateCallback.patch | 191 ------ ...d-tests-for-threadpool-wait-objects.patch} | 66 +- ...-threadpool-wait-functions-to-ntdll.patch} | 12 +- ...ing-threadpool-functions-to-specfile.patch | 84 --- ...nt-threadpool-timer-functions.-rev-2.patch | 533 --------------- ...dd-tests-for-Tp-threadpool-functions.patch | 294 --------- ...-various-threadpool-functions-to-ntd.patch | 342 ---------- patches/ntdll-Vista_Threadpool/definition | 6 +- patches/patchinstall.sh | 29 +- ...introduce-a-multithreaded-command-st.patch | 50 +- .../wined3d-CSMT_Main/9999-IfDefined.patch | 118 ++-- 14 files changed, 458 insertions(+), 2065 deletions(-) delete mode 100644 patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch rename patches/ntdll-Vista_Threadpool/{0007-ntdll-Implement-threadpool-wait-objects.patch => 0001-ntdll-Implement-threadpool-wait-objects.patch} (73%) delete mode 100644 patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch rename patches/ntdll-Vista_Threadpool/{0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch => 0002-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch} (78%) rename patches/ntdll-Vista_Threadpool/{0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch => 0003-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch} (93%) delete mode 100644 patches/ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch delete mode 100644 patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch delete mode 100644 patches/ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch delete mode 100644 patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch diff --git a/README.md b/README.md index 91cb7277..1e257d96 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ for more details.* * Add HTTP Host header in HttpSendRequest instead of HttpOpenRequest ([Wine Bug #28911](https://bugs.winehq.org/show_bug.cgi?id=28911)) * Add a ProfileList\ registry subkey ([Wine Bug #15670](https://bugs.winehq.org/show_bug.cgi?id=15670)) -* Add implementation for CreateThreadpool ([Wine Bug #35192](https://bugs.winehq.org/show_bug.cgi?id=35192)) +* ~~Add implementation for CreateThreadpool~~ ([Wine Bug #35192](https://bugs.winehq.org/show_bug.cgi?id=35192)) * ~~Add implementation for kernel32.GetNumaProcessorNode~~ ([Wine Bug #38660](https://bugs.winehq.org/show_bug.cgi?id=38660)) * Add implementation for mfplat.MFTRegister ([Wine Bug #37811](https://bugs.winehq.org/show_bug.cgi?id=37811)) * Add implementation for shlwapi.AssocGetPerceivedType @@ -186,9 +186,9 @@ for more details.* * Implement stub for ntoskrnl.KeDelayExecutionThread. * 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 timers~~ ([Wine Bug #37306](https://bugs.winehq.org/show_bug.cgi?id=37306)) * Implement threadpool wait objects -* Implement threadpool work items ([Wine Bug #32531](https://bugs.winehq.org/show_bug.cgi?id=32531)) +* ~~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)) * Improve stub for ID3DXEffectImpl_CloneEffect diff --git a/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch b/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch deleted file mode 100644 index 2a3313f9..00000000 --- a/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-TpDisassociateCallback-and-add-separ.patch +++ /dev/null @@ -1,175 +0,0 @@ -From 1651eab61e449fef2119ff35703d6c9acc43f2b3 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Thu, 2 Jul 2015 17:15:41 +0200 -Subject: ntdll: Implement TpDisassociateCallback and add separate group - finished event. - ---- - dlls/ntdll/ntdll.spec | 1 + - dlls/ntdll/threadpool.c | 67 ++++++++++++++++++++++++++++++++++++++++++++----- - 2 files changed, 62 insertions(+), 6 deletions(-) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index 134a3f7..ee90705 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -979,6 +979,7 @@ - @ stdcall TpCallbackReleaseSemaphoreOnCompletion(ptr long long) - @ stdcall TpCallbackSetEventOnCompletion(ptr long) - @ stdcall TpCallbackUnloadDllOnCompletion(ptr ptr) -+@ stdcall TpDisassociateCallback(ptr) - @ stdcall TpPostWork(ptr) - @ stdcall TpReleaseCleanupGroup(ptr) - @ stdcall TpReleaseCleanupGroupMembers(ptr long ptr) -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index eeb275f..0e09d0f 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -181,8 +181,10 @@ struct threadpool_object - /* information about the pool, locked via .pool->cs */ - struct list pool_entry; - RTL_CONDITION_VARIABLE finished_event; -+ RTL_CONDITION_VARIABLE group_finished_event; - LONG num_pending_callbacks; - LONG num_running_callbacks; -+ LONG num_associated_callbacks; - /* arguments for callback */ - union - { -@@ -202,6 +204,7 @@ struct threadpool_instance - { - struct threadpool_object *object; - DWORD threadid; -+ BOOL associated; - BOOL may_run_long; - struct - { -@@ -1406,8 +1409,10 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - - memset( &object->pool_entry, 0, sizeof(object->pool_entry) ); - RtlInitializeConditionVariable( &object->finished_event ); -+ RtlInitializeConditionVariable( &object->group_finished_event ); - object->num_pending_callbacks = 0; - object->num_running_callbacks = 0; -+ object->num_associated_callbacks = 0; - - if (environment) - { -@@ -1540,13 +1545,21 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance - * Waits until all pending and running callbacks of a specific object - * have been processed. - */ --static void tp_object_wait( struct threadpool_object *object ) -+static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) - { - struct threadpool *pool = object->pool; - - RtlEnterCriticalSection( &pool->cs ); -- while (object->num_pending_callbacks || object->num_running_callbacks) -- RtlSleepConditionVariableCS( &object->finished_event, &pool->cs, NULL ); -+ if (group_wait) -+ { -+ while (object->num_pending_callbacks || object->num_running_callbacks) -+ RtlSleepConditionVariableCS( &object->group_finished_event, &pool->cs, NULL ); -+ } -+ else -+ { -+ while (object->num_pending_callbacks || object->num_associated_callbacks) -+ RtlSleepConditionVariableCS( &object->finished_event, &pool->cs, NULL ); -+ } - RtlLeaveCriticalSection( &pool->cs ); - } - -@@ -1631,6 +1644,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - list_add_tail( &pool->pool, &object->pool_entry ); - - /* Leave critical section and do the actual callback. */ -+ object->num_associated_callbacks++; - object->num_running_callbacks++; - pool->num_busy_workers++; - RtlLeaveCriticalSection( &pool->cs ); -@@ -1639,6 +1653,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - callback_instance = (TP_CALLBACK_INSTANCE *)&instance; - instance.object = object; - instance.threadid = GetCurrentThreadId(); -+ instance.associated = TRUE; - instance.may_run_long = object->may_run_long; - instance.cleanup.critical_section = NULL; - instance.cleanup.mutex = NULL; -@@ -1709,9 +1724,18 @@ static void CALLBACK threadpool_worker_proc( void *param ) - skip_cleanup: - RtlEnterCriticalSection( &pool->cs ); - pool->num_busy_workers--; -+ - object->num_running_callbacks--; - if (!object->num_pending_callbacks && !object->num_running_callbacks) -- RtlWakeAllConditionVariable( &object->finished_event ); -+ RtlWakeAllConditionVariable( &object->group_finished_event ); -+ -+ if (instance.associated) -+ { -+ object->num_associated_callbacks--; -+ if (!object->num_pending_callbacks && !object->num_associated_callbacks) -+ RtlWakeAllConditionVariable( &object->finished_event ); -+ } -+ - tp_object_release( object ); - } - -@@ -1913,6 +1937,37 @@ VOID WINAPI TpCallbackUnloadDllOnCompletion( TP_CALLBACK_INSTANCE *instance, HMO - } - - /*********************************************************************** -+ * TpDisassociateCallback (NTDLL.@) -+ */ -+VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) -+{ -+ struct threadpool_instance *this = impl_from_TP_CALLBACK_INSTANCE( instance ); -+ struct threadpool_object *object = this->object; -+ struct threadpool *pool; -+ -+ TRACE( "%p\n", instance ); -+ -+ if (this->threadid != GetCurrentThreadId()) -+ { -+ ERR("called from wrong thread, ignoring\n"); -+ return; -+ } -+ -+ if (!this->associated) -+ return; -+ -+ pool = object->pool; -+ RtlEnterCriticalSection( &pool->cs ); -+ -+ object->num_associated_callbacks--; -+ if (!object->num_pending_callbacks && !object->num_associated_callbacks) -+ RtlWakeAllConditionVariable( &object->finished_event ); -+ -+ RtlLeaveCriticalSection( &pool->cs ); -+ this->associated = FALSE; -+} -+ -+/*********************************************************************** - * TpPostWork (NTDLL.@) - */ - VOID WINAPI TpPostWork( TP_WORK *work ) -@@ -1993,7 +2048,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p - /* Wait for remaining callbacks to finish */ - LIST_FOR_EACH_ENTRY_SAFE( object, next, &members, struct threadpool_object, group_entry ) - { -- tp_object_wait( object ); -+ tp_object_wait( object, TRUE ); - tp_object_release( object ); - } - } -@@ -2115,5 +2170,5 @@ VOID WINAPI TpWaitForWork( TP_WORK *work, BOOL cancel_pending ) - - if (cancel_pending) - tp_object_cancel( this, FALSE, NULL ); -- tp_object_wait( this ); -+ tp_object_wait( this, FALSE ); - } --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch b/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-threadpool-wait-objects.patch similarity index 73% rename from patches/ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch rename to patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-threadpool-wait-objects.patch index 0e8f1173..1fcb52c7 100644 --- a/patches/ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch +++ b/patches/ntdll-Vista_Threadpool/0001-ntdll-Implement-threadpool-wait-objects.patch @@ -1,55 +1,43 @@ -From 5dd5ac0fa0ef0845cc8611ce664e48e8b25f290b Mon Sep 17 00:00:00 2001 +From 102fb5ddc55779ac9c95937faef0cc063774612f Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 4 Mar 2015 13:33:25 +0100 Subject: ntdll: Implement threadpool wait objects. --- - dlls/ntdll/ntdll.spec | 8 +- - dlls/ntdll/threadpool.c | 472 +++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 469 insertions(+), 11 deletions(-) + dlls/ntdll/ntdll.spec | 4 + + dlls/ntdll/threadpool.c | 474 +++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 471 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index 0f4374e..ffcf58d 100644 +index ce9d1bb..75dc647 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec -@@ -977,7 +977,7 @@ - # @ stub TpAllocJobNotification +@@ -973,6 +973,7 @@ + @ stdcall TpAllocCleanupGroup(ptr) @ stdcall TpAllocPool(ptr ptr) - @ stdcall TpAllocTimer(ptr ptr ptr) --# @ stub TpAllocWait + @ stdcall TpAllocTimer(ptr ptr ptr ptr) +@ stdcall TpAllocWait(ptr ptr ptr ptr) @ stdcall TpAllocWork(ptr ptr ptr ptr) - # @ stub TpAlpcRegisterCompletionList - # @ stub TpAlpcUnregisterCompletionList -@@ -1008,7 +1008,7 @@ - # @ stub TpReleaseJobNotification + @ stdcall TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr) + @ stdcall TpCallbackMayRunLong(ptr) +@@ -987,12 +988,15 @@ + @ stdcall TpReleaseCleanupGroupMembers(ptr long ptr) @ stdcall TpReleasePool(ptr) @ stdcall TpReleaseTimer(ptr) --# @ stub TpReleaseWait +@ stdcall TpReleaseWait(ptr) @ stdcall TpReleaseWork(ptr) - # @ stub TpSetDefaultPoolMaxThreads - # @ stub TpSetDefaultPoolStackInformation -@@ -1020,7 +1020,7 @@ - # @ stub TpSetPoolWorkerThreadIdleTimeout + @ stdcall TpSetPoolMaxThreads(ptr long) + @ stdcall TpSetPoolMinThreads(ptr long) @ stdcall TpSetTimer(ptr ptr long long) - # @ stub TpSetTimerEx --# @ stub TpSetWait +@ stdcall TpSetWait(ptr long ptr) - # @ stub TpSetWaitEx @ stdcall TpSimpleTryPost(ptr ptr ptr) - # @ stub TpStartAsyncIoOperation -@@ -1030,7 +1030,7 @@ - # @ stub TpWaitForIoCompletion - # @ stub TpWaitForJobNotification @ stdcall TpWaitForTimer(ptr long) --# @ stub TpWaitForWait +@ 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 c44988c..b8d761b 100644 +index ef502ba..773c3d6 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -137,6 +137,7 @@ struct timer_queue @@ -89,18 +77,9 @@ index c44988c..b8d761b 100644 }; @@ -267,6 +280,38 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug = - 0, 0, { (DWORD_PTR)(__FILE__ ": timerqueue.cs") } + 0, 0, { (DWORD_PTR)(__FILE__ ": timerqueue.cs") } }; -+struct waitqueue_bucket -+{ -+ struct list bucket_entry; -+ LONG num_waits; -+ struct list reserved; -+ struct list waits; -+ HANDLE update_event; -+}; -+ +/* global waitqueue object */ +static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug; + @@ -112,16 +91,25 @@ index c44988c..b8d761b 100644 +} +waitqueue = +{ -+ { &waitqueue_debug, -1, 0, 0, 0, 0 }, -+ 0, -+ LIST_INIT( waitqueue.buckets ) ++ { &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") } ++ 0, 0, { (DWORD_PTR)(__FILE__ ": waitqueue.cs") } ++}; ++ ++struct waitqueue_bucket ++{ ++ struct list bucket_entry; ++ LONG objcount; ++ struct list reserved; ++ struct list waits; ++ HANDLE update_event; +}; + static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool ) @@ -141,39 +129,182 @@ index c44988c..b8d761b 100644 static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group ) { return (struct threadpool_group *)group; -@@ -298,7 +350,8 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL +@@ -297,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 CALLBACK timerqueue_thread_proc( void *param ); -static void tp_object_submit( struct threadpool_object *object ); -+static void CALLBACK waitqueue_thread_proc( void *param ); +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; -@@ -1352,7 +1405,7 @@ update_timer: - RtlLeaveCriticalSection( &timerqueue.cs ); - - if (submit_timer) -- tp_object_submit( new_timer ); -+ tp_object_submit( new_timer, FALSE ); - } - - static void CALLBACK timerqueue_thread_proc( void *param ) -@@ -1379,7 +1432,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) - - /* Queue a new callback in one of the worker threads */ +@@ -1249,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 ); - /* Requeue the timer, except its marked for shutdown */ - if (!timer->shutdown && timer->u.timer.period) -@@ -1445,6 +1498,301 @@ static void CALLBACK timerqueue_thread_proc( void *param ) - RtlLeaveCriticalSection( &timerqueue.cs ); + /* Insert the timer back into the queue, except its marked for shutdown. */ + if (timer->u.timer.period && !timer->shutdown) +@@ -1386,6 +1438,255 @@ static void tp_timerqueue_unlock( struct threadpool_object *timer ) } -+static NTSTATUS tp_waitqueue_acquire( struct threadpool_object *wait ) + /*********************************************************************** ++ * 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->waits, 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 a wait queue update event or until an event is triggered */ ++ 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 fulfilled. */ ++ 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 ); ++ } ++ ++ /* Try to merge with other threads. */ ++ if (waitqueue.num_buckets > 1 && bucket->objcount && ++ bucket->objcount < MAXIMUM_WAITQUEUE_OBJECTS / 2) ++ { ++ 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) ++ { ++ 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 wait list. */ ++ LIST_FOR_EACH_ENTRY( wait, &bucket->waits, 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->waits, &bucket->waits ); ++ ++ /* Move bucket to the end to keep 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. */ ++ 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->waits ) ); ++ ++ 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; @@ -183,25 +314,26 @@ index c44988c..b8d761b 100644 + wait->u.wait.signaled = 0; + wait->u.wait.bucket = NULL; + wait->u.wait.wait_pending = FALSE; -+ memset( &wait->u.wait.wait_entry, 0, sizeof(wait->u.wait.wait_entry) ); + 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->num_waits < MAXIMUM_WAITQUEUE_OBJECTS) ++ if (bucket->objcount < MAXIMUM_WAITQUEUE_OBJECTS) + { -+ bucket->num_waits++; -+ wait->u.wait.bucket = bucket; + 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) + { @@ -209,11 +341,12 @@ index c44988c..b8d761b 100644 + goto out; + } + -+ bucket->num_waits = 1; ++ bucket->objcount = 0; + list_init( &bucket->reserved ); + list_init( &bucket->waits ); + -+ status = NtCreateEvent( &bucket->update_event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ); ++ status = NtCreateEvent( &bucket->update_event, EVENT_ALL_ACCESS, ++ NULL, SynchronizationEvent, FALSE ); + if (status) + { + RtlFreeHeap( GetProcessHeap(), 0, bucket ); @@ -224,11 +357,12 @@ index c44988c..b8d761b 100644 + waitqueue_thread_proc, bucket, &thread, NULL ); + if (status == STATUS_SUCCESS) + { -+ waitqueue.num_buckets++; + list_add_tail( &waitqueue.buckets, &bucket->bucket_entry ); ++ waitqueue.num_buckets++; + -+ wait->u.wait.bucket = bucket; + list_add_tail( &bucket->reserved, &wait->u.wait.wait_entry ); ++ wait->u.wait.bucket = bucket; ++ bucket->objcount++; + + NtClose( thread ); + } @@ -243,235 +377,33 @@ index c44988c..b8d761b 100644 + return status; +} + -+/* Decrement the refcount of a timer queue. */ -+static void tp_waitqueue_release( struct threadpool_object *wait ) ++/*********************************************************************** ++ * tp_waitqueue_unlock (internal) ++ */ ++static void tp_waitqueue_unlock( struct threadpool_object *wait ) +{ + assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ RtlEnterCriticalSection( &waitqueue.cs ); + ++ RtlEnterCriticalSection( &waitqueue.cs ); + if (wait->u.wait.bucket) + { + struct waitqueue_bucket *bucket = wait->u.wait.bucket; -+ assert( bucket->num_waits > 0 ); ++ assert( bucket->objcount > 0 ); + -+ bucket->num_waits--; + list_remove( &wait->u.wait.wait_entry ); -+ NtSetEvent( bucket->update_event, NULL ); -+ + wait->u.wait.bucket = NULL; -+ } -+ -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+} -+ -+static void tp_waitqueue_update_wait( struct threadpool_object *new_wait, HANDLE handle, LARGE_INTEGER *timeout ) -+{ -+ BOOL submit_wait = FALSE; -+ -+ assert( new_wait->type == TP_OBJECT_TYPE_WAIT ); -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ assert( new_wait->u.wait.bucket ); -+ -+ /* update wait handle */ -+ new_wait->u.wait.handle = handle; -+ -+ /* for performance reasons we only wake up when something has changed */ -+ if (handle || new_wait->u.wait.wait_pending) -+ { -+ struct waitqueue_bucket *bucket = new_wait->u.wait.bucket; -+ list_remove( &new_wait->u.wait.wait_entry ); -+ -+ if (handle) -+ { -+ ULONGLONG when = TIMEOUT_INFINITE; -+ -+ if (timeout) -+ { -+ when = timeout->QuadPart; -+ -+ /* A timeout of zero means that the wait should be submitted immediately */ -+ if (when == 0) -+ { -+ submit_wait = TRUE; -+ goto remove_wait; -+ } -+ -+ /* Convert relative timeout to absolute */ -+ if ((LONGLONG)when < 0) -+ { -+ LARGE_INTEGER now; -+ NtQuerySystemTime( &now ); -+ when = now.QuadPart - when; -+ } -+ } -+ -+ list_add_tail( &bucket->waits, &new_wait->u.wait.wait_entry ); -+ new_wait->u.wait.wait_pending = TRUE; -+ new_wait->u.wait.timeout = when; -+ } -+ else -+ { -+remove_wait: -+ list_add_tail( &bucket->reserved, &new_wait->u.wait.wait_entry ); -+ new_wait->u.wait.wait_pending = FALSE; -+ } ++ bucket->objcount--; + + NtSetEvent( bucket->update_event, NULL ); + } -+ + RtlLeaveCriticalSection( &waitqueue.cs ); -+ -+ if (submit_wait) -+ tp_object_submit( new_wait, FALSE ); +} + -+static void CALLBACK waitqueue_thread_proc( void *param ) -+{ -+ HANDLE handles[MAXIMUM_WAITQUEUE_OBJECTS + 1]; -+ struct threadpool_object *objects[MAXIMUM_WAITQUEUE_OBJECTS]; -+ struct waitqueue_bucket *bucket = param; -+ LARGE_INTEGER now, timeout; -+ struct threadpool_object *wait, *next; -+ DWORD num_handles; -+ NTSTATUS status; -+ -+ RtlEnterCriticalSection( &waitqueue.cs ); -+ -+ for (;;) -+ { -+ NtQuerySystemTime( &now ); -+ timeout.QuadPart = TIMEOUT_INFINITE; -+ num_handles = 0; -+ -+ LIST_FOR_EACH_ENTRY_SAFE( wait, next, &bucket->waits, struct threadpool_object, u.wait.wait_entry ) -+ { -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ -+ /* Timeout expired or object was signaled */ -+ if (wait->u.wait.timeout <= now.QuadPart) -+ { -+ 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; -+ -+ /* We will have to wait for this object - keep a reference to make sure it 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->num_waits) -+ { -+ assert( num_handles == 0 ); -+ -+ /* All wait objects have been destroyed, if there are no new wait objects within some -+ * amount of time, then we can shutdown this thread. */ -+ 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->num_waits) -+ break; -+ } -+ else -+ { -+ handles[num_handles] = bucket->update_event; -+ -+ /* Wait for a wait queue update event or until an event is triggered */ -+ 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) -+ { -+ 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 -+ FIXME("Wait object triggered while object was destroyed, race-condition.\n"); -+ } -+ -+ while (num_handles) -+ { -+ wait = objects[--num_handles]; -+ assert( wait->type == TP_OBJECT_TYPE_WAIT ); -+ tp_object_release( wait ); -+ } -+ } -+ -+ /* Try to merge with other buckets */ -+ if (waitqueue.num_buckets > 1 && bucket->num_waits && bucket->num_waits < MAXIMUM_WAITQUEUE_OBJECTS / 2) -+ { -+ struct waitqueue_bucket *other_bucket; -+ LIST_FOR_EACH_ENTRY( other_bucket, &waitqueue.buckets, struct waitqueue_bucket, bucket_entry ) -+ { -+ if (other_bucket != bucket && other_bucket->num_waits && -+ other_bucket->num_waits + bucket->num_waits <= MAXIMUM_WAITQUEUE_OBJECTS) -+ { -+ other_bucket->num_waits += bucket->num_waits; -+ bucket->num_waits = 0; -+ -+ 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 ); -+ -+ LIST_FOR_EACH_ENTRY( wait, &bucket->waits, 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->waits, &bucket->waits ); -+ -+ /* we will not terminate immediately, but instead after a timeout. Make sure that this -+ * bucket appears as the last one in the list, otherwise there is a high risk that -+ * elements will be added again. */ -+ list_remove( &bucket->bucket_entry ); -+ list_add_tail( &waitqueue.buckets, &bucket->bucket_entry ); -+ -+ NtSetEvent( other_bucket->update_event, NULL ); -+ break; -+ } -+ } -+ } -+ } -+ -+ waitqueue.num_buckets--; -+ list_remove( &bucket->bucket_entry ); -+ if (!waitqueue.num_buckets) -+ assert( list_empty( &waitqueue.buckets ) ); -+ RtlLeaveCriticalSection( &waitqueue.cs ); -+ -+ assert( bucket->num_waits == 0 ); -+ assert( list_empty( &bucket->reserved ) ); -+ assert( list_empty( &bucket->waits ) ); -+ -+ NtClose( bucket->update_event ); -+ RtlFreeHeap( GetProcessHeap(), 0, bucket ); -+} -+ - /*********************************************************************** ++/*********************************************************************** * tp_threadpool_alloc (internal) * -@@ -1714,7 +2062,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa + * Allocates a new threadpool object. +@@ -1654,7 +1955,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) @@ -480,7 +412,7 @@ index c44988c..b8d761b 100644 if (object->group) { -@@ -1740,7 +2088,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa +@@ -1680,7 +1981,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. */ @@ -489,37 +421,37 @@ index c44988c..b8d761b 100644 { struct threadpool *pool = object->pool; NTSTATUS status = STATUS_UNSUCCESSFUL; -@@ -1770,6 +2118,10 @@ static void tp_object_submit( struct threadpool_object *object ) +@@ -1710,6 +2011,10 @@ static void tp_object_submit( struct threadpool_object *object ) if (!object->num_pending_callbacks++) list_add_tail( &pool->pool, &object->pool_entry ); -+ /* increment success counter by one */ ++ /* Remember how often the wait was fulfilled. */ + 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) { -@@ -1797,6 +2149,9 @@ static void tp_object_cancel( struct threadpool_object *object, BOOL group_cance +@@ -1736,6 +2041,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; ++ if (object->type == TP_OBJECT_TYPE_WAIT) ++ object->u.wait.signaled = 0; + } RtlLeaveCriticalSection( &pool->cs ); - /* Execute group cancellation callback if defined, and if this was actually a group cancel. */ -@@ -1845,6 +2200,8 @@ static void tp_object_shutdown( struct threadpool_object *object ) +@@ -1785,6 +2093,8 @@ static void tp_object_shutdown( struct threadpool_object *object ) { if (object->type == TP_OBJECT_TYPE_TIMER) - tp_timerqueue_release( object ); + tp_timerqueue_unlock( object ); + else if (object->type == TP_OBJECT_TYPE_WAIT) -+ tp_waitqueue_release( object ); ++ tp_waitqueue_unlock( object ); object->shutdown = TRUE; } -@@ -1898,6 +2255,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) +@@ -1839,6 +2149,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) TP_CALLBACK_INSTANCE *callback_instance; struct threadpool_instance instance; struct threadpool *pool = param; @@ -527,26 +459,21 @@ index c44988c..b8d761b 100644 LARGE_INTEGER timeout; struct list *ptr; NTSTATUS status; -@@ -1918,6 +2276,18 @@ static void CALLBACK threadpool_worker_proc( void *param ) +@@ -1859,6 +2170,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 object was signaled or if this -+ * is a timeout. */ ++ /* For wait objects determine if the operation was successful. */ + if (object->type == TP_OBJECT_TYPE_WAIT) + { -+ if (object->u.wait.signaled > 0) -+ { -+ wait_result = WAIT_OBJECT_0; -+ object->u.wait.signaled--; -+ } -+ else wait_result = WAIT_TIMEOUT; ++ 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++; -@@ -1966,6 +2336,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) +@@ -1907,6 +2225,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) break; } @@ -562,7 +489,7 @@ index c44988c..b8d761b 100644 default: assert(0); break; -@@ -2112,6 +2491,46 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID +@@ -2052,6 +2379,46 @@ NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID } /*********************************************************************** @@ -591,7 +518,7 @@ index c44988c..b8d761b 100644 + object->type = TP_OBJECT_TYPE_WAIT; + object->u.wait.callback = callback; + -+ status = tp_waitqueue_acquire( object ); ++ status = tp_waitqueue_lock( object ); + if (status) + { + tp_threadpool_unlock( pool ); @@ -609,7 +536,7 @@ index c44988c..b8d761b 100644 * TpAllocWork (NTDLL.@) */ NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata, -@@ -2311,7 +2730,7 @@ VOID WINAPI TpPostWork( TP_WORK *work ) +@@ -2252,7 +2619,7 @@ VOID WINAPI TpPostWork( TP_WORK *work ) TRACE( "%p\n", work ); @@ -618,7 +545,7 @@ index c44988c..b8d761b 100644 } /*********************************************************************** -@@ -2415,6 +2834,19 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer ) +@@ -2356,6 +2723,19 @@ VOID WINAPI TpReleaseTimer( TP_TIMER *timer ) } /*********************************************************************** @@ -638,26 +565,82 @@ index c44988c..b8d761b 100644 * TpReleaseWork (NTDLL.@) */ VOID WINAPI TpReleaseWork( TP_WORK *work ) -@@ -2490,6 +2922,18 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO - } +@@ -2493,7 +2873,73 @@ 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 ); ++ BOOL submit_wait = FALSE; + + TRACE( "%p %p %p\n", wait, handle, timeout ); + -+ tp_waitqueue_update_wait( this, handle, timeout ); -+} ++ RtlEnterCriticalSection( &waitqueue.cs ); ++ assert( this->u.wait.bucket ); + -+/*********************************************************************** - * TpSimpleTryPost (NTDLL.@) - */ - NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, -@@ -2534,6 +2978,20 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending ) ++ /* update wait handle */ ++ this->u.wait.handle = handle; ++ ++ /* for performance reasons we only wake up when something has changed */ ++ if (handle || this->u.wait.wait_pending) ++ { ++ struct waitqueue_bucket *bucket = this->u.wait.bucket; ++ list_remove( &this->u.wait.wait_entry ); ++ ++ if (handle) ++ { ++ ULONGLONG when = TIMEOUT_INFINITE; ++ ++ if (timeout) ++ { ++ when = timeout->QuadPart; ++ ++ /* A timeout of zero means that the wait should be submitted immediately */ ++ if (when == 0) ++ { ++ submit_wait = TRUE; ++ goto remove_wait; ++ } ++ ++ /* Convert relative timeout to absolute */ ++ if ((LONGLONG)when < 0) ++ { ++ LARGE_INTEGER now; ++ NtQuerySystemTime( &now ); ++ when = now.QuadPart - when; ++ } ++ } ++ ++ list_add_tail( &bucket->waits, &this->u.wait.wait_entry ); ++ this->u.wait.wait_pending = TRUE; ++ this->u.wait.timeout = when; ++ } ++ else ++ { ++remove_wait: ++ list_add_tail( &bucket->reserved, &this->u.wait.wait_entry ); ++ this->u.wait.wait_pending = FALSE; ++ } ++ ++ NtSetEvent( bucket->update_event, NULL ); ++ } ++ ++ RtlLeaveCriticalSection( &waitqueue.cs ); ++ ++ if (submit_wait) ++ tp_object_submit( this, FALSE ); + } + + /*********************************************************************** +@@ -2541,6 +2987,20 @@ VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending ) } /*********************************************************************** diff --git a/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch b/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch deleted file mode 100644 index 61dfe226..00000000 --- a/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch +++ /dev/null @@ -1,191 +0,0 @@ -From 8041e8ccf5ed9021525a95b7c6bcedfa7d945cb4 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Thu, 2 Jul 2015 17:18:00 +0200 -Subject: ntdll/tests: Add tests for TpDisassociateCallback. - ---- - dlls/ntdll/tests/threadpool.c | 149 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 149 insertions(+) - -diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index 62bd064..a75b622 100644 ---- a/dlls/ntdll/tests/threadpool.c -+++ b/dlls/ntdll/tests/threadpool.c -@@ -26,6 +26,7 @@ static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID); - 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 VOID (WINAPI *pTpPostWork)(TP_WORK *); - static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); - static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID); -@@ -57,6 +58,7 @@ static BOOL init_threadpool(void) - NTDLL_GET_PROC(TpAllocWork); - NTDLL_GET_PROC(TpCallbackMayRunLong); - NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); -+ NTDLL_GET_PROC(TpDisassociateCallback); - NTDLL_GET_PROC(TpPostWork); - NTDLL_GET_PROC(TpReleaseCleanupGroup); - NTDLL_GET_PROC(TpReleaseCleanupGroupMembers); -@@ -498,6 +500,152 @@ static void test_tp_instance(void) - CloseHandle(semaphores[1]); - } - -+static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) -+{ -+ HANDLE *semaphores = userdata; -+ DWORD result; -+ -+ trace("Running disassociate callback\n"); -+ -+ pTpDisassociateCallback(instance); -+ result = WaitForSingleObject(semaphores[0], 1000); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+} -+ -+static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) -+{ -+ HANDLE *semaphores = userdata; -+ DWORD result; -+ -+ trace("Running disassociate2 callback\n"); -+ -+ pTpDisassociateCallback(instance); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+} -+ -+static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) -+{ -+ HANDLE *semaphores = userdata; -+ DWORD result; -+ -+ trace("Running disassociate3 callback\n"); -+ -+ pTpDisassociateCallback(instance); -+ result = WaitForSingleObject(semaphores[0], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ReleaseSemaphore(semaphores[1], 1, NULL); -+} -+ -+static void test_tp_disassociate(void) -+{ -+ TP_CALLBACK_ENVIRON environment; -+ TP_CLEANUP_GROUP *group; -+ HANDLE semaphores[2]; -+ NTSTATUS status; -+ TP_POOL *pool; -+ TP_WORK *work; -+ DWORD result; -+ -+ semaphores[0] = CreateSemaphoreW(NULL, 0, 1, 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"); -+ -+ /* allocate new threadpool and cleanup group */ -+ pool = NULL; -+ status = pTpAllocPool(&pool, NULL); -+ ok(!status, "TpAllocPool failed with status %x\n", status); -+ ok(pool != NULL, "expected pool != NULL\n"); -+ -+ group = NULL; -+ status = pTpAllocCleanupGroup(&group); -+ ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); -+ ok(group != NULL, "expected pool != NULL\n"); -+ -+ /* test TpDisassociateCallback on work objects without group */ -+ work = NULL; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); -+ ok(!status, "TpAllocWork failed with status %x\n", status); -+ ok(work != NULL, "expected work != NULL\n"); -+ -+ pTpPostWork(work); -+ pTpWaitForWork(work, FALSE); -+ -+ result = WaitForSingleObject(semaphores[1], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ReleaseSemaphore(semaphores[0], 1, NULL); -+ result = WaitForSingleObject(semaphores[1], 1000); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ pTpReleaseWork(work); -+ -+ /* test TpDisassociateCallback on work objects with group (1) */ -+ work = NULL; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ environment.CleanupGroup = group; -+ status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); -+ ok(!status, "TpAllocWork failed with status %x\n", status); -+ ok(work != NULL, "expected work != NULL\n"); -+ -+ pTpPostWork(work); -+ pTpWaitForWork(work, FALSE); -+ -+ result = WaitForSingleObject(semaphores[1], 100); -+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); -+ ReleaseSemaphore(semaphores[0], 1, NULL); -+ result = WaitForSingleObject(semaphores[1], 1000); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL); -+ -+ /* test TpDisassociateCallback on work objects with group (2) */ -+ work = NULL; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ environment.CleanupGroup = group; -+ status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment); -+ ok(!status, "TpAllocWork failed with status %x\n", status); -+ ok(work != NULL, "expected work != NULL\n"); -+ -+ pTpPostWork(work); -+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL); -+ -+ ReleaseSemaphore(semaphores[0], 1, NULL); -+ result = WaitForSingleObject(semaphores[1], 1000); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ result = WaitForSingleObject(semaphores[0], 1000); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ -+ /* test TpDisassociateCallback on simple callbacks */ -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ environment.CleanupGroup = group; -+ status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment); -+ ok(!status, "TpSimpleTryPost failed with status %x\n", status); -+ -+ pTpReleaseCleanupGroupMembers(group, FALSE, NULL); -+ -+ ReleaseSemaphore(semaphores[0], 1, NULL); -+ result = WaitForSingleObject(semaphores[1], 1000); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ result = WaitForSingleObject(semaphores[0], 1000); -+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); -+ -+ /* cleanup */ -+ pTpReleaseCleanupGroup(group); -+ pTpReleasePool(pool); -+ CloseHandle(semaphores[0]); -+ CloseHandle(semaphores[1]); -+} -+ - START_TEST(threadpool) - { - if (!init_threadpool()) -@@ -508,4 +656,5 @@ START_TEST(threadpool) - test_tp_work_scheduler(); - test_tp_group_cancel(); - test_tp_instance(); -+ test_tp_disassociate(); - } --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch b/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch similarity index 78% rename from patches/ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch rename to patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch index 6a9363f9..25349247 100644 --- a/patches/ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch +++ b/patches/ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch @@ -1,18 +1,66 @@ -From 0aa4ad9970796cbbbe4fc5f81209e6d5d505a385 Mon Sep 17 00:00:00 2001 +From c8a3a30a9d4f4a3609d59298d486b691f682390e Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 6 Feb 2015 20:09:41 +0100 Subject: ntdll/tests: Add tests for threadpool wait objects. --- - dlls/ntdll/tests/threadpool.c | 287 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 287 insertions(+) + dlls/ntdll/tests/threadpool.c | 295 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 295 insertions(+) diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index 4be3a8b..fd587ba 100644 +index 0671202..9904d46 100644 --- a/dlls/ntdll/tests/threadpool.c +++ b/dlls/ntdll/tests/threadpool.c -@@ -869,6 +869,291 @@ static void test_tp_window_length(void) - pTpReleasePool(pool); +@@ -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,291 @@ static void test_tp_window_length(void) + CloseHandle(semaphore); } +static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result) @@ -303,15 +351,13 @@ index 4be3a8b..fd587ba 100644 START_TEST(threadpool) { if (!init_threadpool()) -@@ -882,6 +1167,8 @@ START_TEST(threadpool) +@@ -919,4 +1212,6 @@ START_TEST(threadpool) test_tp_disassociate(); test_tp_timer(); test_tp_window_length(); + test_tp_wait(); + test_tp_multi_wait(); - - /* FIXME: Make sure worker threads have terminated before. */ - Sleep(100); + } -- 2.4.4 diff --git a/patches/ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch b/patches/ntdll-Vista_Threadpool/0003-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch similarity index 93% rename from patches/ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch rename to patches/ntdll-Vista_Threadpool/0003-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch index fbb858f4..f7ddc76a 100644 --- a/patches/ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch +++ b/patches/ntdll-Vista_Threadpool/0003-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch @@ -1,4 +1,4 @@ -From b32a93ef14e23672df3a11ef1e9718857c933ff9 Mon Sep 17 00:00:00 2001 +From 898045c05b21aa7cbdfb168f4b4ce8ffb06b1ae0 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. @@ -10,7 +10,7 @@ Subject: kernel32: Forward threadpool wait functions to ntdll. 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index 337b339..146db0f 100644 +index a14d03b..77e55e1 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -233,7 +233,7 @@ @@ -50,10 +50,10 @@ index 337b339..146db0f 100644 @ stdcall WaitNamedPipeA (str long) @ stdcall WaitNamedPipeW (wstr long) diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c -index 945fe0b..89b0b60 100644 +index 21ec276..d592692 100644 --- a/dlls/kernel32/thread.c +++ b/dlls/kernel32/thread.c -@@ -923,6 +923,27 @@ PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userd +@@ -942,6 +942,27 @@ PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userd } /*********************************************************************** @@ -81,9 +81,9 @@ index 945fe0b..89b0b60 100644 * CreateThreadpoolWork (KERNEL32.@) */ PTP_WORK WINAPI CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata, -@@ -961,3 +982,25 @@ VOID WINAPI SetThreadpoolTimer( TP_TIMER *timer, FILETIME *due_time, +@@ -1000,3 +1021,25 @@ BOOL WINAPI TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK callback, PVOID use - TpSetTimer( timer, due_time ? &timeout : NULL, period, window_length ); + return TRUE; } + +/*********************************************************************** diff --git a/patches/ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch b/patches/ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch deleted file mode 100644 index e66cd5de..00000000 --- a/patches/ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch +++ /dev/null @@ -1,84 +0,0 @@ -From aef4ab9059bc29f2449c7ec19cb6562896ac1708 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 08:01:00 +0100 -Subject: ntdll: Add remaining threadpool functions to specfile. - ---- - dlls/ntdll/ntdll.spec | 43 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index ee90705..d75efdc 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -970,24 +970,67 @@ - @ stdcall RtlxOemStringToUnicodeSize(ptr) RtlOemStringToUnicodeSize - @ stdcall RtlxUnicodeStringToAnsiSize(ptr) RtlUnicodeStringToAnsiSize - @ stdcall RtlxUnicodeStringToOemSize(ptr) RtlUnicodeStringToOemSize -+# @ stub TpAllocAlpcCompletion -+# @ stub TpAllocAlpcCompletionEx - @ stdcall TpAllocCleanupGroup(ptr) -+# @ stub TpAllocIoCompletion -+# @ stub TpAllocJobNotification - @ stdcall TpAllocPool(ptr ptr) -+# @ stub TpAllocTimer -+# @ stub TpAllocWait - @ stdcall TpAllocWork(ptr ptr ptr ptr) -+# @ stub TpAlpcRegisterCompletionList -+# @ stub TpAlpcUnregisterCompletionList -+# @ stub TpCallbackDetectedUnrecoverableError -+# @ stub TpCallbackIndependent - @ stdcall TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr) - @ stdcall TpCallbackMayRunLong(ptr) - @ stdcall TpCallbackReleaseMutexOnCompletion(ptr long) - @ stdcall TpCallbackReleaseSemaphoreOnCompletion(ptr long long) -+# @ stub TpCallbackSendAlpcMessageOnCompletion -+# @ stub TpCallbackSendPendingAlpcMessage - @ stdcall TpCallbackSetEventOnCompletion(ptr long) - @ stdcall TpCallbackUnloadDllOnCompletion(ptr ptr) -+# @ stub TpCancelAsyncIoOperation -+# @ stub TpCaptureCaller -+# @ stub TpCheckTerminateWorker -+# @ stub TpDbgDumpHeapUsage -+# @ stub TpDbgSetLogRoutine -+# @ stub TpDisablePoolCallbackChecks - @ stdcall TpDisassociateCallback(ptr) -+# @ stub TpIsTimerSet - @ stdcall TpPostWork(ptr) -+# @ stub TpQueryPoolStackInformation -+# @ stub TpReleaseAlpcCompletion - @ stdcall TpReleaseCleanupGroup(ptr) - @ stdcall TpReleaseCleanupGroupMembers(ptr long ptr) -+# @ stub TpReleaseIoCompletion -+# @ stub TpReleaseJobNotification - @ stdcall TpReleasePool(ptr) -+# @ stub TpReleaseTimer -+# @ stub TpReleaseWait - @ stdcall TpReleaseWork(ptr) -+# @ stub TpSetDefaultPoolMaxThreads -+# @ stub TpSetDefaultPoolStackInformation - @ stdcall TpSetPoolMaxThreads(ptr long) -+# @ stub TpSetPoolMaxThreadsSoftLimit - @ stdcall TpSetPoolMinThreads(ptr long) -+# @ stub TpSetPoolStackInformation -+# @ stub TpSetPoolThreadBasePriority -+# @ stub TpSetPoolWorkerThreadIdleTimeout -+# @ stub TpSetTimer -+# @ stub TpSetTimerEx -+# @ stub TpSetWait -+# @ stub TpSetWaitEx - @ stdcall TpSimpleTryPost(ptr ptr ptr) -+# @ stub TpStartAsyncIoOperation -+# @ stub TpTimerOutstandingCallbackCount -+# @ stub TpTrimPools -+# @ stub TpWaitForAlpcCompletion -+# @ stub TpWaitForIoCompletion -+# @ stub TpWaitForJobNotification -+# @ stub TpWaitForTimer -+# @ stub TpWaitForWait - @ stdcall TpWaitForWork(ptr long) - @ stdcall -ret64 VerSetConditionMask(int64 long long) - @ stdcall WinSqmIsOptedIn() --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch b/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch deleted file mode 100644 index 16655c57..00000000 --- a/patches/ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch +++ /dev/null @@ -1,533 +0,0 @@ -From e138d4b3eedeb471f70f2e48cdbb8c4c55207554 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 08:19:47 +0100 -Subject: ntdll: Implement threadpool timer functions. (rev 2) - ---- - dlls/ntdll/ntdll.spec | 10 +- - dlls/ntdll/threadpool.c | 376 +++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 380 insertions(+), 6 deletions(-) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index d75efdc..0f4374e 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -976,7 +976,7 @@ - # @ stub TpAllocIoCompletion - # @ stub TpAllocJobNotification - @ stdcall TpAllocPool(ptr ptr) --# @ stub TpAllocTimer -+@ stdcall TpAllocTimer(ptr ptr ptr) - # @ stub TpAllocWait - @ stdcall TpAllocWork(ptr ptr ptr ptr) - # @ stub TpAlpcRegisterCompletionList -@@ -998,7 +998,7 @@ - # @ stub TpDbgSetLogRoutine - # @ stub TpDisablePoolCallbackChecks - @ stdcall TpDisassociateCallback(ptr) --# @ stub TpIsTimerSet -+@ stdcall TpIsTimerSet(ptr) - @ stdcall TpPostWork(ptr) - # @ stub TpQueryPoolStackInformation - # @ stub TpReleaseAlpcCompletion -@@ -1007,7 +1007,7 @@ - # @ stub TpReleaseIoCompletion - # @ stub TpReleaseJobNotification - @ stdcall TpReleasePool(ptr) --# @ stub TpReleaseTimer -+@ stdcall TpReleaseTimer(ptr) - # @ stub TpReleaseWait - @ stdcall TpReleaseWork(ptr) - # @ stub TpSetDefaultPoolMaxThreads -@@ -1018,7 +1018,7 @@ - # @ stub TpSetPoolStackInformation - # @ stub TpSetPoolThreadBasePriority - # @ stub TpSetPoolWorkerThreadIdleTimeout --# @ stub TpSetTimer -+@ stdcall TpSetTimer(ptr ptr long long) - # @ stub TpSetTimerEx - # @ stub TpSetWait - # @ stub TpSetWaitEx -@@ -1029,7 +1029,7 @@ - # @ stub TpWaitForAlpcCompletion - # @ stub TpWaitForIoCompletion - # @ stub TpWaitForJobNotification --# @ stub TpWaitForTimer -+@ stdcall TpWaitForTimer(ptr long) - # @ stub TpWaitForWait - @ stdcall TpWaitForWork(ptr long) - @ stdcall -ret64 VerSetConditionMask(int64 long long) -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 0e09d0f..c44988c 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -158,7 +158,8 @@ struct threadpool - enum threadpool_objtype - { - TP_OBJECT_TYPE_SIMPLE, -- TP_OBJECT_TYPE_WORK -+ TP_OBJECT_TYPE_WORK, -+ TP_OBJECT_TYPE_TIMER - }; - - /* internal threadpool object representation */ -@@ -196,6 +197,18 @@ struct threadpool_object - { - PTP_WORK_CALLBACK callback; - } work; -+ struct -+ { -+ PTP_TIMER_CALLBACK callback; -+ /* information about the timer, locked via timerqueue.cs */ -+ BOOL timer_initialized; -+ BOOL timer_pending; -+ struct list timer_entry; -+ BOOL timer_set; -+ ULONGLONG timeout; -+ LONG period; -+ LONG window_length; -+ } timer; - } u; - }; - -@@ -227,6 +240,33 @@ struct threadpool_group - struct list members; - }; - -+/* global timerqueue object */ -+static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug; -+ -+static struct -+{ -+ CRITICAL_SECTION cs; -+ BOOL thread_running; -+ LONG num_timers; -+ struct list pending_timers; -+ RTL_CONDITION_VARIABLE update_event; -+} -+timerqueue = -+{ -+ { &timerqueue_debug, -1, 0, 0, 0, 0 }, -+ FALSE, -+ 0, -+ LIST_INIT( timerqueue.pending_timers ), -+ RTL_CONDITION_VARIABLE_INIT -+}; -+ -+static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug = -+{ -+ 0, 0, &timerqueue.cs, -+ { &timerqueue_debug.ProcessLocksList, &timerqueue_debug.ProcessLocksList }, -+ 0, 0, { (DWORD_PTR)(__FILE__ ": timerqueue.cs") } -+}; -+ - static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool ) - { - return (struct threadpool *)pool; -@@ -239,6 +279,13 @@ static inline struct threadpool_object *impl_from_TP_WORK( TP_WORK *work ) - return object; - } - -+static inline struct threadpool_object *impl_from_TP_TIMER( TP_TIMER *timer ) -+{ -+ struct threadpool_object *object = (struct threadpool_object *)timer; -+ assert( object->type == TP_OBJECT_TYPE_TIMER ); -+ return object; -+} -+ - static inline struct threadpool_group *impl_from_TP_CLEANUP_GROUP( TP_CLEANUP_GROUP *group ) - { - return (struct threadpool_group *)group; -@@ -250,6 +297,7 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL - } - - static void CALLBACK threadpool_worker_proc( void *param ); -+static void CALLBACK timerqueue_thread_proc( void *param ); - static void tp_object_submit( struct threadpool_object *object ); - static void tp_object_shutdown( struct threadpool_object *object ); - static BOOL tp_object_release( struct threadpool_object *object ); -@@ -1173,6 +1221,230 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer, - return status; - } - -+static NTSTATUS tp_timerqueue_acquire( struct threadpool_object *timer ) -+{ -+ NTSTATUS status = STATUS_SUCCESS; -+ assert( timer->type == TP_OBJECT_TYPE_TIMER ); -+ -+ timer->u.timer.timer_initialized = TRUE; -+ timer->u.timer.timer_pending = FALSE; -+ memset( &timer->u.timer.timer_entry, 0, sizeof(timer->u.timer.timer_entry) ); -+ timer->u.timer.timer_set = FALSE; -+ timer->u.timer.timeout = 0; -+ timer->u.timer.period = 0; -+ timer->u.timer.window_length = 0; -+ -+ RtlEnterCriticalSection( &timerqueue.cs ); -+ -+ if (!timerqueue.thread_running) -+ { -+ HANDLE thread; -+ status = RtlCreateUserThread( GetCurrentProcess(), NULL, FALSE, NULL, 0, 0, -+ timerqueue_thread_proc, NULL, &thread, NULL ); -+ if (status == STATUS_SUCCESS) -+ { -+ NtClose( thread ); -+ timerqueue.thread_running = TRUE; -+ } -+ } -+ -+ if (!status) timerqueue.num_timers++; -+ RtlLeaveCriticalSection( &timerqueue.cs ); -+ return status; -+} -+ -+static void tp_timerqueue_release( struct threadpool_object *timer ) -+{ -+ assert( timer->type == TP_OBJECT_TYPE_TIMER ); -+ RtlEnterCriticalSection( &timerqueue.cs ); -+ if (timer->u.timer.timer_initialized) -+ { -+ -+ if (timer->u.timer.timer_pending) -+ { -+ list_remove( &timer->u.timer.timer_entry ); -+ timer->u.timer.timer_pending = FALSE; -+ } -+ -+ if (!--timerqueue.num_timers) -+ { -+ assert( list_empty( &timerqueue.pending_timers ) ); -+ RtlWakeAllConditionVariable( &timerqueue.update_event ); -+ } -+ -+ timer->u.timer.timer_initialized = FALSE; -+ } -+ RtlLeaveCriticalSection( &timerqueue.cs ); -+} -+ -+static void tp_timerqueue_update_timer( struct threadpool_object *new_timer, LARGE_INTEGER *timeout, -+ LONG period, LONG window_length ) -+{ -+ BOOL submit_timer = FALSE; -+ struct threadpool_object *timer; -+ ULONGLONG when; -+ -+ assert( new_timer->type == TP_OBJECT_TYPE_TIMER ); -+ RtlEnterCriticalSection( &timerqueue.cs ); -+ assert( new_timer->u.timer.timer_initialized ); -+ -+ /* Remember if the timer is set or unset */ -+ new_timer->u.timer.timer_set = timeout != NULL; -+ -+ if (timeout) -+ { -+ when = timeout->QuadPart; -+ -+ /* A timeout of zero means that the timer should be submitted immediately */ -+ if (when == 0) -+ { -+ submit_timer = TRUE; -+ if (!period) -+ { -+ timeout = NULL; -+ goto update_timer; -+ } -+ when = (ULONGLONG)period * -10000; -+ } -+ -+ /* Convert relative timeout to absolute */ -+ if ((LONGLONG)when < 0) -+ { -+ LARGE_INTEGER now; -+ NtQuerySystemTime( &now ); -+ when = now.QuadPart - when; -+ } -+ } -+ -+update_timer: -+ -+ /* If timer is still pending, then remove the old one */ -+ if (new_timer->u.timer.timer_pending) -+ { -+ list_remove( &new_timer->u.timer.timer_entry ); -+ memset( &new_timer->u.timer.timer_entry, 0, sizeof(new_timer->u.timer.timer_entry) ); -+ new_timer->u.timer.timer_pending = FALSE; -+ } -+ -+ /* Timer should be enabled again, add it to the queue */ -+ if (timeout) -+ { -+ new_timer->u.timer.timeout = when; -+ new_timer->u.timer.period = period; -+ new_timer->u.timer.window_length = window_length; -+ -+ /* insert new_timer into the timer queue */ -+ LIST_FOR_EACH_ENTRY( timer, &timerqueue.pending_timers, struct threadpool_object, u.timer.timer_entry ) -+ { -+ assert( timer->type == TP_OBJECT_TYPE_TIMER ); -+ if (new_timer->u.timer.timeout < timer->u.timer.timeout) -+ break; -+ } -+ list_add_before( &timer->u.timer.timer_entry, &new_timer->u.timer.timer_entry ); -+ -+ /* wake up thread if it should expire earlier than before */ -+ if (list_head( &timerqueue.pending_timers ) == &new_timer->u.timer.timer_entry ) -+ RtlWakeAllConditionVariable( &timerqueue.update_event ); -+ -+ new_timer->u.timer.timer_pending = TRUE; -+ } -+ -+ RtlLeaveCriticalSection( &timerqueue.cs ); -+ -+ if (submit_timer) -+ tp_object_submit( new_timer ); -+} -+ -+static void CALLBACK timerqueue_thread_proc( void *param ) -+{ -+ LARGE_INTEGER now, timeout; -+ ULONGLONG timeout_lower, timeout_upper; -+ struct threadpool_object *other_timer; -+ struct list *ptr; -+ -+ RtlEnterCriticalSection( &timerqueue.cs ); -+ -+ for (;;) -+ { -+ NtQuerySystemTime( &now ); -+ -+ while ((ptr = list_head( &timerqueue.pending_timers ))) -+ { -+ struct threadpool_object *timer = LIST_ENTRY( ptr, struct threadpool_object, u.timer.timer_entry ); -+ assert( timer->type == TP_OBJECT_TYPE_TIMER ); -+ -+ /* Timeout didn't expire yet, nothing to do */ -+ if (timer->u.timer.timeout > now.QuadPart) -+ break; -+ -+ /* Queue a new callback in one of the worker threads */ -+ list_remove( &timer->u.timer.timer_entry ); -+ tp_object_submit( timer ); -+ -+ /* Requeue the timer, except its marked for shutdown */ -+ if (!timer->shutdown && timer->u.timer.period) -+ { -+ /* Update the timeout, make sure its at least the current time (to avoid too many work items) */ -+ timer->u.timer.timeout += (ULONGLONG)timer->u.timer.period * 10000; -+ if (timer->u.timer.timeout <= now.QuadPart) -+ timer->u.timer.timeout = now.QuadPart + 1; -+ -+ /* Insert timer back into the timer queue */ -+ LIST_FOR_EACH_ENTRY( other_timer, &timerqueue.pending_timers, struct threadpool_object, u.timer.timer_entry ) -+ { -+ assert( other_timer->type == TP_OBJECT_TYPE_TIMER ); -+ if (timer->u.timer.timeout < other_timer->u.timer.timeout) -+ break; -+ } -+ list_add_before( &other_timer->u.timer.timer_entry, &timer->u.timer.timer_entry ); -+ } -+ else -+ { -+ /* The element is no longer queued */ -+ timer->u.timer.timer_pending = FALSE; -+ } -+ } -+ -+ /* Determine next timeout - we use the window_length arguments to optimize wakeup times */ -+ timeout_lower = timeout_upper = TIMEOUT_INFINITE; -+ LIST_FOR_EACH_ENTRY( other_timer, &timerqueue.pending_timers, struct threadpool_object, u.timer.timer_entry ) -+ { -+ ULONGLONG new_timeout_upper; -+ assert( other_timer->type == TP_OBJECT_TYPE_TIMER ); -+ if (other_timer->u.timer.timeout >= timeout_upper) -+ break; -+ -+ timeout_lower = other_timer->u.timer.timeout; -+ new_timeout_upper = timeout_lower + (ULONGLONG)other_timer->u.timer.window_length * 10000; -+ -+ if (timeout_upper > new_timeout_upper) -+ timeout_upper = new_timeout_upper; -+ } -+ -+ -+ if (!timerqueue.num_timers) -+ { -+ /* All timers have been destroyed, if no new timers are created within some amount of -+ * time, then we can shutdown this thread. */ -+ timeout.QuadPart = (ULONGLONG)THREADPOOL_WORKER_TIMEOUT * -10000; -+ if (RtlSleepConditionVariableCS( &timerqueue.update_event, -+ &timerqueue.cs, &timeout ) == STATUS_TIMEOUT && !timerqueue.num_timers) -+ { -+ break; -+ } -+ } -+ else -+ { -+ /* Wait for timer update events or until the next timer expires. */ -+ timeout.QuadPart = timeout_lower; -+ RtlSleepConditionVariableCS( &timerqueue.update_event, &timerqueue.cs, &timeout ); -+ } -+ } -+ -+ timerqueue.thread_running = FALSE; -+ RtlLeaveCriticalSection( &timerqueue.cs ); -+} -+ - /*********************************************************************** - * tp_threadpool_alloc (internal) - * -@@ -1571,6 +1843,9 @@ static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) - */ - static void tp_object_shutdown( struct threadpool_object *object ) - { -+ if (object->type == TP_OBJECT_TYPE_TIMER) -+ tp_timerqueue_release( object ); -+ - object->shutdown = TRUE; - } - -@@ -1682,6 +1957,15 @@ static void CALLBACK threadpool_worker_proc( void *param ) - break; - } - -+ case TP_OBJECT_TYPE_TIMER: -+ { -+ TRACE( "executing timer callback %p(%p, %p, %p)\n", -+ object->u.timer.callback, callback_instance, object->userdata, object ); -+ object->u.timer.callback( callback_instance, object->userdata, (TP_TIMER *)object ); -+ TRACE( "callback %p returned\n", object->u.timer.callback ); -+ break; -+ } -+ - default: - assert(0); - break; -@@ -1788,6 +2072,46 @@ NTSTATUS WINAPI TpAllocPool( TP_POOL **out, PVOID reserved ) - } - - /*********************************************************************** -+ * TpAllocTimer (NTDLL.@) -+ */ -+NTSTATUS WINAPI TpAllocTimer( TP_TIMER **out, PTP_TIMER_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_TIMER; -+ object->u.timer.callback = callback; -+ -+ status = tp_timerqueue_acquire( object ); -+ if (status) -+ { -+ tp_threadpool_unlock( pool ); -+ RtlFreeHeap( GetProcessHeap(), 0, object ); -+ return status; -+ } -+ -+ tp_object_initialize( object, pool, userdata, environment ); -+ -+ *out = (TP_TIMER *)object; -+ return STATUS_SUCCESS; -+} -+ -+/*********************************************************************** - * TpAllocWork (NTDLL.@) - */ - NTSTATUS WINAPI TpAllocWork( TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata, -@@ -1968,6 +2292,17 @@ VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) - } - - /*********************************************************************** -+ * TpIsTimerSet (NTDLL.@) -+ */ -+BOOL WINAPI TpIsTimerSet( TP_TIMER *timer ) -+{ -+ struct threadpool_object *this = impl_from_TP_TIMER( timer ); -+ TRACE( "%p\n", timer ); -+ -+ return this->u.timer.timer_set; -+} -+ -+/*********************************************************************** - * TpPostWork (NTDLL.@) - */ - VOID WINAPI TpPostWork( TP_WORK *work ) -@@ -2067,6 +2402,19 @@ VOID WINAPI TpReleasePool( TP_POOL *pool ) - } - - /*********************************************************************** -+ * TpReleaseTimer (NTDLL.@) -+ */ -+VOID WINAPI TpReleaseTimer( TP_TIMER *timer ) -+{ -+ struct threadpool_object *this = impl_from_TP_TIMER( timer ); -+ -+ TRACE( "%p\n", timer ); -+ -+ tp_object_shutdown( this ); -+ tp_object_release( this ); -+} -+ -+/*********************************************************************** - * TpReleaseWork (NTDLL.@) - */ - VOID WINAPI TpReleaseWork( TP_WORK *work ) -@@ -2130,6 +2478,18 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum ) - } - - /*********************************************************************** -+ * TpSetTimer (NTDLL.@) -+ */ -+VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LONG window_length ) -+{ -+ struct threadpool_object *this = impl_from_TP_TIMER( timer ); -+ -+ TRACE( "%p %p %u %u\n", timer, timeout, period, window_length ); -+ -+ tp_timerqueue_update_timer( this, timeout, period, window_length ); -+} -+ -+/*********************************************************************** - * TpSimpleTryPost (NTDLL.@) - */ - NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, -@@ -2160,6 +2520,20 @@ NTSTATUS WINAPI TpSimpleTryPost( PTP_SIMPLE_CALLBACK callback, PVOID userdata, - } - - /*********************************************************************** -+ * TpWaitForTimer (NTDLL.@) -+ */ -+VOID WINAPI TpWaitForTimer( TP_TIMER *timer, BOOL cancel_pending ) -+{ -+ struct threadpool_object *this = impl_from_TP_TIMER( timer ); -+ -+ TRACE( "%p %d\n", timer, 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/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch b/patches/ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch deleted file mode 100644 index d9b8e07e..00000000 --- a/patches/ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch +++ /dev/null @@ -1,294 +0,0 @@ -From 8e03c37240d2a0fafbe6347bc8d509ce5555757a Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 4 Mar 2015 13:17:04 +0100 -Subject: ntdll/tests: Add tests for Tp* threadpool functions. - ---- - dlls/ntdll/tests/threadpool.c | 228 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 228 insertions(+) - -diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index a75b622..4be3a8b 100644 ---- a/dlls/ntdll/tests/threadpool.c -+++ b/dlls/ntdll/tests/threadpool.c -@@ -22,18 +22,37 @@ - - static HMODULE hntdll = 0; - static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **); -+static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_WIN32_IO_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); - 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 VOID (WINAPI *pTpCallbackLeaveCriticalSectionOnCompletion)(TP_CALLBACK_INSTANCE *,CRITICAL_SECTION *); - static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); -+static VOID (WINAPI *pTpCallbackReleaseMutexOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE); - static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); -+static VOID (WINAPI *pTpCallbackSetEventOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE); -+static VOID (WINAPI *pTpCallbackUnloadDllOnCompletion)(TP_CALLBACK_INSTANCE *,HMODULE); -+static VOID (WINAPI *pTpCancelAsyncIoOperation)(TP_IO *); - static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); -+static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *); - static VOID (WINAPI *pTpPostWork)(TP_WORK *); - static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); - static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID); -+static VOID (WINAPI *pTpReleaseIoCompletion)(TP_IO *); - static VOID (WINAPI *pTpReleasePool)(TP_POOL *); -+static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *); -+static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *); - static VOID (WINAPI *pTpReleaseWork)(TP_WORK *); - static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD); -+static BOOL (WINAPI *pTpSetPoolMinThreads)(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 *pTpStartAsyncIoOperation)(TP_IO *); -+static VOID (WINAPI *pTpWaitForIoCompletion)(TP_IO *,BOOL); -+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) \ -@@ -54,18 +73,37 @@ static BOOL init_threadpool(void) - } - - NTDLL_GET_PROC(TpAllocCleanupGroup); -+ NTDLL_GET_PROC(TpAllocIoCompletion); - NTDLL_GET_PROC(TpAllocPool); -+ NTDLL_GET_PROC(TpAllocTimer); -+ NTDLL_GET_PROC(TpAllocWait); - NTDLL_GET_PROC(TpAllocWork); -+ NTDLL_GET_PROC(TpCallbackLeaveCriticalSectionOnCompletion); - NTDLL_GET_PROC(TpCallbackMayRunLong); -+ NTDLL_GET_PROC(TpCallbackReleaseMutexOnCompletion); - NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); -+ NTDLL_GET_PROC(TpCallbackSetEventOnCompletion); -+ NTDLL_GET_PROC(TpCallbackUnloadDllOnCompletion); -+ NTDLL_GET_PROC(TpCancelAsyncIoOperation); - NTDLL_GET_PROC(TpDisassociateCallback); -+ NTDLL_GET_PROC(TpIsTimerSet); - NTDLL_GET_PROC(TpPostWork); - NTDLL_GET_PROC(TpReleaseCleanupGroup); - NTDLL_GET_PROC(TpReleaseCleanupGroupMembers); -+ NTDLL_GET_PROC(TpReleaseIoCompletion); - NTDLL_GET_PROC(TpReleasePool); -+ NTDLL_GET_PROC(TpReleaseTimer); -+ NTDLL_GET_PROC(TpReleaseWait); - NTDLL_GET_PROC(TpReleaseWork); - NTDLL_GET_PROC(TpSetPoolMaxThreads); -+ NTDLL_GET_PROC(TpSetPoolMinThreads); -+ NTDLL_GET_PROC(TpSetTimer); -+ NTDLL_GET_PROC(TpSetWait); - NTDLL_GET_PROC(TpSimpleTryPost); -+ NTDLL_GET_PROC(TpStartAsyncIoOperation); -+ NTDLL_GET_PROC(TpWaitForIoCompletion); -+ NTDLL_GET_PROC(TpWaitForTimer); -+ NTDLL_GET_PROC(TpWaitForWait); - NTDLL_GET_PROC(TpWaitForWork); - - if (!pTpAllocPool) -@@ -646,6 +684,191 @@ static void test_tp_disassociate(void) - CloseHandle(semaphores[1]); - } - -+static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) -+{ -+ trace("Running timer callback\n"); -+ InterlockedIncrement( (LONG *)userdata ); -+} -+ -+static void test_tp_timer(void) -+{ -+ TP_CALLBACK_ENVIRON environment; -+ TP_TIMER *timer; -+ TP_POOL *pool; -+ NTSTATUS status; -+ LONG userdata; -+ BOOL success; -+ LARGE_INTEGER when; -+ DWORD ticks; -+ -+ /* 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 timer item */ -+ timer = NULL; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ status = pTpAllocTimer(&timer, timer_cb, &userdata, &environment); -+ ok(!status, "TpAllocTimer failed with status %x\n", status); -+ ok(timer != NULL, "expected timer != NULL\n"); -+ -+ success = pTpIsTimerSet(timer); -+ ok(!success, "expected TpIsTimerSet(...) = FALSE\n"); -+ -+ /* Set a relative timeout */ -+ userdata = 0; -+ when.QuadPart = (ULONGLONG)500 * -10000; -+ pTpSetTimer(timer, &when, 0, 0); -+ success = pTpIsTimerSet(timer); -+ ok(success, "expected TpIsTimerSet(...) = TRUE\n"); -+ -+ /* Wait until timer has triggered */ -+ pTpWaitForTimer(timer, FALSE); -+ Sleep(250); -+ ok(userdata == 0, "expected userdata = 0, got %u\n", userdata); -+ while (userdata == 0) Sleep(10); -+ ok(userdata == 1, "expected userdata = 1, got %u\n", userdata); -+ success = pTpIsTimerSet(timer); -+ ok(success, "expected TpIsTimerSet(...) = TRUE\n"); -+ -+ /* Set an absolute timeout */ -+ userdata = 0; -+ NtQuerySystemTime( &when ); -+ when.QuadPart += (ULONGLONG)500 * 10000; -+ pTpSetTimer(timer, &when, 0, 0); -+ success = pTpIsTimerSet(timer); -+ ok(success, "expected TpIsTimerSet(...) = TRUE\n"); -+ -+ /* Wait until timer has triggered */ -+ pTpWaitForTimer(timer, FALSE); -+ Sleep(250); -+ ok(userdata == 0, "expected userdata = 0, got %u\n", userdata); -+ while (userdata == 0) Sleep(10); -+ ok(userdata == 1, "expected userdata = 1, got %u\n", userdata); -+ success = pTpIsTimerSet(timer); -+ ok(success, "expected TpIsTimerSet(...) = TRUE\n"); -+ -+ /* Test a relative timeout repeated periodically */ -+ userdata = 0; -+ when.QuadPart = (ULONGLONG)50 * -10000; -+ pTpSetTimer(timer, &when, 50, 0); -+ success = pTpIsTimerSet(timer); -+ ok(success, "expected TpIsTimerSet(...) = TRUE\n"); -+ -+ /* Wait until the timer was triggered a couple of times */ -+ ticks = GetTickCount(); -+ while (userdata < 100) Sleep(10); -+ ticks = GetTickCount() - ticks; -+ pTpSetTimer(timer, NULL, 0, 0); -+ pTpWaitForTimer(timer, TRUE); -+ ok(ticks >= 4500 && ticks <= 5500, "expected approximately 5000 ticks, got %u\n", ticks); -+ success = pTpIsTimerSet(timer); -+ ok(!success, "expected TpIsTimerSet(...) = FALSE\n"); -+ -+ /* Test with zero timeout, we expect a call immediately */ -+ userdata = 0; -+ when.QuadPart = 0; -+ pTpSetTimer(timer, &when, 0, 0); -+ success = pTpIsTimerSet(timer); -+ ok(success, "expected TpIsTimerSet(...) = TRUE\n"); -+ -+ /* Wait until timer has triggered */ -+ pTpWaitForTimer(timer, FALSE); -+ ok(userdata == 1 || broken(userdata == 0) /* Win 8 */, -+ "expected userdata = 1, got %u\n", userdata); -+ while (userdata == 0) Sleep(10); -+ success = pTpIsTimerSet(timer); -+ ok(success, "expected TpIsTimerSet(...) = TRUE\n"); -+ -+ /* Unset the timer again */ -+ pTpSetTimer(timer, NULL, 0, 0); -+ success = pTpIsTimerSet(timer); -+ ok(!success, "expected TpIsTimerSet(...) = FALSE\n"); -+ -+ /* Cleanup */ -+ pTpReleaseTimer(timer); -+ pTpReleasePool(pool); -+} -+ -+static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) -+{ -+ trace("Running window length callback\n"); -+ (*(DWORD *)userdata) = GetTickCount(); -+} -+ -+static void test_tp_window_length(void) -+{ -+ TP_CALLBACK_ENVIRON environment; -+ TP_TIMER *timer, *timer2; -+ DWORD ticks, ticks2; -+ TP_POOL *pool; -+ NTSTATUS status; -+ LARGE_INTEGER when; -+ -+ /* 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 two identical timers */ -+ timer = NULL; -+ memset(&environment, 0, sizeof(environment)); -+ environment.Version = 1; -+ environment.Pool = pool; -+ status = pTpAllocTimer(&timer, window_length_cb, &ticks, &environment); -+ ok(!status, "TpAllocTimer failed with status %x\n", status); -+ ok(timer != NULL, "expected timer != NULL\n"); -+ -+ timer2 = NULL; -+ status = pTpAllocTimer(&timer2, window_length_cb, &ticks2, &environment); -+ ok(!status, "TpAllocTimer failed with status %x\n", status); -+ ok(timer2 != NULL, "expected timer2 != NULL\n"); -+ -+ /* Choose parameters so that timers are not merged */ -+ ticks = ticks2 = 0; -+ NtQuerySystemTime( &when ); -+ when.QuadPart += (ULONGLONG)500 * 10000; -+ pTpSetTimer(timer2, &when, 0, 0); -+ Sleep(50); -+ when.QuadPart -= (ULONGLONG)400 * 10000; -+ pTpSetTimer(timer, &when, 0, 200); -+ while (!ticks || !ticks2) Sleep(10); -+ ok(ticks2 >= ticks + 150, "expected that timers are not merged\n"); -+ -+ /* On Windows the timers also get merged in this case */ -+ ticks = ticks2 = 0; -+ NtQuerySystemTime( &when ); -+ when.QuadPart += (ULONGLONG)100 * 10000; -+ pTpSetTimer(timer, &when, 0, 450); -+ Sleep(50); -+ when.QuadPart += (ULONGLONG)400 * 10000; -+ pTpSetTimer(timer2, &when, 0, 0); -+ while (!ticks || !ticks2) Sleep(10); -+ todo_wine -+ ok(ticks2 >= ticks - 50 && ticks2 <= ticks + 50, "expected that timers are merged\n"); -+ -+ /* Timers will be merged */ -+ ticks = ticks2 = 0; -+ NtQuerySystemTime( &when ); -+ when.QuadPart += (ULONGLONG)500 * 10000; -+ pTpSetTimer(timer2, &when, 0, 0); -+ Sleep(50); -+ when.QuadPart -= (ULONGLONG)400 * 10000; -+ pTpSetTimer(timer, &when, 0, 450); -+ while (!ticks || !ticks2) Sleep(10); -+ ok(ticks2 >= ticks - 50 && ticks2 <= ticks + 50, "expected that timers are merged\n"); -+ -+ /* Cleanup */ -+ pTpReleaseTimer(timer); -+ pTpReleaseTimer(timer2); -+ pTpReleasePool(pool); -+} -+ - START_TEST(threadpool) - { - if (!init_threadpool()) -@@ -657,4 +880,9 @@ START_TEST(threadpool) - test_tp_group_cancel(); - test_tp_instance(); - test_tp_disassociate(); -+ test_tp_timer(); -+ test_tp_window_length(); -+ -+ /* FIXME: Make sure worker threads have terminated before. */ -+ Sleep(100); - } --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch b/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch deleted file mode 100644 index 7a9f10bb..00000000 --- a/patches/ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch +++ /dev/null @@ -1,342 +0,0 @@ -From 37906069933d6bd73b8c6a691292288c57b09e22 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sun, 1 Feb 2015 19:41:13 +0100 -Subject: kernel32: Forward various threadpool functions to ntdll. - ---- - dlls/kernel32/kernel32.spec | 48 ++++++++++---------- - dlls/kernel32/tests/thread.c | 6 +-- - dlls/kernel32/thread.c | 101 +++++++++++++++++++++++++++++++++++++++++++ - include/winternl.h | 27 ++++++++++++ - 4 files changed, 155 insertions(+), 27 deletions(-) - -diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index 3c40975..337b339 100644 ---- a/dlls/kernel32/kernel32.spec -+++ b/dlls/kernel32/kernel32.spec -@@ -204,7 +204,7 @@ - @ stdcall BuildCommDCBAndTimeoutsA(str ptr ptr) - @ stdcall BuildCommDCBAndTimeoutsW(wstr ptr ptr) - @ stdcall BuildCommDCBW(wstr ptr) --# @ stub CallbackMayRunLong -+@ stdcall CallbackMayRunLong(ptr) ntdll.TpCallbackMayRunLong - @ stdcall CallNamedPipeA(str ptr long ptr long ptr long) - @ stdcall CallNamedPipeW(wstr ptr long ptr long ptr long) - @ stub CancelDeviceWakeupRequest -@@ -228,13 +228,13 @@ - # @ stub ClosePrivateNamespace - @ stdcall CloseProfileUserMapping() - @ stub CloseSystemHandle --# @ stub CloseThreadpool --# @ stub CloseThreadpoolCleanupGroup --# @ stub CloseThreadpoolCleanupGroupMembers -+@ stdcall CloseThreadpool(ptr) ntdll.TpReleasePool -+@ stdcall CloseThreadpoolCleanupGroup(ptr) ntdll.TpReleaseCleanupGroup -+@ stdcall CloseThreadpoolCleanupGroupMembers(ptr long ptr) ntdll.TpReleaseCleanupGroupMembers - # @ stub CloseThreadpoolIo --# @ stub CloseThreadpoolTimer -+@ stdcall CloseThreadpoolTimer(ptr) ntdll.TpReleaseTimer - # @ stub CloseThreadpoolWait --# @ stub CloseThreadpoolWork -+@ stdcall CloseThreadpoolWork(ptr) ntdll.TpReleaseWork - @ stdcall CmdBatNotification(long) - @ stdcall CommConfigDialogA(str long ptr) - @ stdcall CommConfigDialogW(wstr long ptr) -@@ -331,12 +331,12 @@ - @ stdcall CreateSymbolicLinkW(wstr wstr long) - @ stdcall CreateTapePartition(long long long long) - @ stdcall CreateThread(ptr long ptr long long ptr) --# @ stub CreateThreadpool --# @ stub CreateThreadpoolCleanupGroup -+@ stdcall CreateThreadpool(ptr) -+@ stdcall CreateThreadpoolCleanupGroup() - # @ stub CreateThreadpoolIo --# @ stub CreateThreadpoolTimer -+@ stdcall CreateThreadpoolTimer(ptr ptr ptr) - # @ stub CreateThreadpoolWait --# @ stub CreateThreadpoolWork -+@ stdcall CreateThreadpoolWork(ptr ptr ptr) - @ stdcall CreateTimerQueue () - @ stdcall CreateTimerQueueTimer(ptr long ptr ptr long long long) - @ stdcall CreateToolhelp32Snapshot(long long) -@@ -369,7 +369,7 @@ - @ stdcall DeleteFileW(wstr) - # @ stub DeleteProcThreadAttributeList - # @ stub DisableThreadProfiling --# @ stub DisassociateCurrentThreadFromCallback -+@ stdcall DisassociateCurrentThreadFromCallback(ptr) ntdll.TpDisassociateCallback - @ stdcall DeleteTimerQueue(long) - @ stdcall DeleteTimerQueueEx (long long) - @ stdcall DeleteTimerQueueTimer(long long long) -@@ -495,7 +495,6 @@ - @ stdcall FindFirstVolumeMountPointA(str ptr long) - @ stdcall FindFirstVolumeMountPointW(wstr ptr long) - @ stdcall FindFirstVolumeW(ptr long) --# @ stub FreeLibraryWhenCallbackReturns - @ stdcall FindNextChangeNotification(long) - @ stdcall FindNextFileA(long ptr) - # @ stub FindNextFileNameW -@@ -533,6 +532,7 @@ - @ stub -i386 FreeLSCallback - @ stdcall FreeLibrary(long) - @ stdcall FreeLibraryAndExitThread(long long) -+@ stdcall FreeLibraryWhenCallbackReturns(ptr ptr) ntdll.TpCallbackUnloadDllOnCompletion - @ stdcall FreeResource(long) - @ stdcall -i386 -private FreeSLCallback(long) krnl386.exe16.FreeSLCallback - @ stub FreeUserPhysicalPages -@@ -981,7 +981,7 @@ - @ stub -i386 IsSLCallback - @ stdcall IsSystemResumeAutomatic() - @ stdcall IsThreadAFiber() --# @ stub IsThreadpoolTimerSet -+@ stdcall IsThreadpoolTimerSet(ptr) ntdll.TpIsTimerSet - # @ stub IsTimeZoneRedirectionEnabled - # @ stub IsValidCalDateTime - @ stdcall IsValidCodePage(long) -@@ -1035,7 +1035,7 @@ - @ stdcall LZSeek(long long long) - @ stdcall LZStart() - @ stdcall LeaveCriticalSection(ptr) ntdll.RtlLeaveCriticalSection --# @ stub LeaveCriticalSectionWhenCallbackReturns -+@ stdcall LeaveCriticalSectionWhenCallbackReturns(ptr ptr) ntdll.TpCallbackLeaveCriticalSectionOnCompletion - # @ stub LoadAppInitDlls - @ stdcall LoadLibraryA(str) - @ stdcall LoadLibraryExA( str long long) -@@ -1252,9 +1252,9 @@ - @ stdcall ReinitializeCriticalSection(ptr) - @ stdcall ReleaseActCtx(ptr) - @ stdcall ReleaseMutex(long) --# @ stub ReleaseMutexWhenCallbackReturns -+@ stdcall ReleaseMutexWhenCallbackReturns(ptr long) ntdll.TpCallbackReleaseMutexOnCompletion - @ stdcall ReleaseSemaphore(long long ptr) --# @ stub ReleaseSemaphoreWhenCallbackReturns -+@ stdcall ReleaseSemaphoreWhenCallbackReturns(ptr long long) ntdll.TpCallbackReleaseSemaphoreOnCompletion - @ stdcall ReleaseSRWLockExclusive(ptr) ntdll.RtlReleaseSRWLockExclusive - @ stdcall ReleaseSRWLockShared(ptr) ntdll.RtlReleaseSRWLockShared - @ stdcall RemoveDirectoryA(str) -@@ -1385,7 +1385,7 @@ - @ stdcall SetEnvironmentVariableW(wstr wstr) - @ stdcall SetErrorMode(long) - @ stdcall SetEvent(long) --# @ stub SetEventWhenCallbackReturns -+@ stdcall SetEventWhenCallbackReturns(ptr long) ntdll.TpCallbackSetEventOnCompletion - @ stdcall SetFileApisToANSI() - @ stdcall SetFileApisToOEM() - @ stdcall SetFileAttributesA(str long) -@@ -1454,9 +1454,9 @@ - # @ stub SetThreadToken - @ stdcall SetThreadUILanguage(long) - # @ stub SetThreadpoolStackInformation --# @ stub SetThreadpoolThreadMaximum --# @ stub SetThreadpoolThreadMinimum --# @ stub SetThreadpoolTimer -+@ stdcall SetThreadpoolThreadMaximum(ptr long) ntdll.TpSetPoolMaxThreads -+@ stdcall SetThreadpoolThreadMinimum(ptr long) ntdll.TpSetPoolMinThreads -+@ stdcall SetThreadpoolTimer(ptr ptr long long) - # @ stub SetThreadpoolWait - @ stdcall SetTimeZoneInformation(ptr) - @ stub SetTimerQueueTimer -@@ -1482,7 +1482,7 @@ - # @ stub SortCloseHandle - # @ stub SortGetHandle - # @ stub StartThreadpoolIo --# @ stub SubmitThreadpoolWork -+@ stdcall SubmitThreadpoolWork(ptr) ntdll.TpPostWork - @ stdcall SuspendThread(long) - @ stdcall SwitchToFiber(ptr) - @ stdcall SwitchToThread() -@@ -1509,7 +1509,7 @@ - @ stdcall TryAcquireSRWLockExclusive(ptr) ntdll.RtlTryAcquireSRWLockExclusive - @ stdcall TryAcquireSRWLockShared(ptr) ntdll.RtlTryAcquireSRWLockShared - @ stdcall TryEnterCriticalSection(ptr) ntdll.RtlTryEnterCriticalSection --# @ stub TrySubmitThreadpoolCallback -+@ stdcall TrySubmitThreadpoolCallback(ptr ptr ptr) ntdll.TpSimpleTryPost - @ stdcall TzSpecificLocalTimeToSystemTime(ptr ptr ptr) - # @ stub TzSpecificLocalTimeToSystemTimeEx - # @ stub -arch=x86_64 uaw_lstrcmpW -@@ -1571,9 +1571,9 @@ - @ stdcall WaitForSingleObject(long long) - @ stdcall WaitForSingleObjectEx(long long long) - # @ stub WaitForThreadpoolIoCallbacks --# @ stub WaitForThreadpoolTimerCallbacks -+@ stdcall WaitForThreadpoolTimerCallbacks(ptr long) ntdll.TpWaitForTimer - # @ stub WaitForThreadpoolWaitCallbacks --# @ stub WaitForThreadpoolWorkCallbacks -+@ stdcall WaitForThreadpoolWorkCallbacks(ptr long) ntdll.TpWaitForWork - @ stdcall WaitNamedPipeA (str long) - @ stdcall WaitNamedPipeW (wstr long) - @ stdcall WakeAllConditionVariable(ptr) ntdll.RtlWakeAllConditionVariable -diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c -index d3ecd2a..25801b2 100644 ---- a/dlls/kernel32/tests/thread.c -+++ b/dlls/kernel32/tests/thread.c -@@ -1627,8 +1627,8 @@ static void test_threadpool(void) - int workcalled = 0; - - if (!pCreateThreadpool) { -- todo_wine win_skip("thread pool apis not supported.\n"); -- return; -+ win_skip("thread pool apis not supported.\n"); -+ return; - } - - work = pCreateThreadpoolWork(threadpool_workcallback, &workcalled, NULL); -@@ -1640,7 +1640,7 @@ static void test_threadpool(void) - ok (workcalled == 1, "expected work to be called once, got %d\n", workcalled); - - pool = pCreateThreadpool(NULL); -- todo_wine ok (pool != NULL, "CreateThreadpool failed\n"); -+ ok (pool != NULL, "CreateThreadpool failed\n"); - } - - static void test_reserved_tls(void) -diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c -index 3dabf94..945fe0b 100644 ---- a/dlls/kernel32/thread.c -+++ b/dlls/kernel32/thread.c -@@ -860,3 +860,104 @@ BOOL WINAPI GetThreadPreferredUILanguages( DWORD flags, PULONG count, PCZZWSTR b - *buffersize = 0; - return TRUE; - } -+ -+/*********************************************************************** -+ * CreateThreadpool (KERNEL32.@) -+ */ -+PTP_POOL WINAPI CreateThreadpool( PVOID reserved ) -+{ -+ TP_POOL *pool; -+ NTSTATUS status; -+ -+ TRACE( "%p\n", reserved ); -+ -+ status = TpAllocPool( &pool, reserved ); -+ if (status) -+ { -+ SetLastError( RtlNtStatusToDosError(status) ); -+ return NULL; -+ } -+ -+ return pool; -+} -+ -+/*********************************************************************** -+ * CreateThreadpoolCleanupGroup (KERNEL32.@) -+ */ -+PTP_CLEANUP_GROUP WINAPI CreateThreadpoolCleanupGroup( void ) -+{ -+ TP_CLEANUP_GROUP *group; -+ NTSTATUS status; -+ -+ TRACE( "\n" ); -+ -+ status = TpAllocCleanupGroup( &group ); -+ if (status) -+ { -+ SetLastError( RtlNtStatusToDosError(status) ); -+ return NULL; -+ } -+ -+ return group; -+} -+ -+/*********************************************************************** -+ * CreateThreadpoolTimer (KERNEL32.@) -+ */ -+PTP_TIMER WINAPI CreateThreadpoolTimer( PTP_TIMER_CALLBACK callback, PVOID userdata, -+ TP_CALLBACK_ENVIRON *environment ) -+{ -+ TP_TIMER *timer; -+ NTSTATUS status; -+ -+ TRACE( "%p, %p, %p\n", callback, userdata, environment ); -+ -+ status = TpAllocTimer( &timer, callback, userdata, environment ); -+ if (status) -+ { -+ SetLastError( RtlNtStatusToDosError(status) ); -+ return NULL; -+ } -+ -+ return timer; -+} -+ -+/*********************************************************************** -+ * CreateThreadpoolWork (KERNEL32.@) -+ */ -+PTP_WORK WINAPI CreateThreadpoolWork( PTP_WORK_CALLBACK callback, PVOID userdata, -+ TP_CALLBACK_ENVIRON *environment ) -+{ -+ TP_WORK *work; -+ NTSTATUS status; -+ -+ TRACE( "%p, %p, %p\n", callback, userdata, environment ); -+ -+ status = TpAllocWork( &work, callback, userdata, environment ); -+ if (status) -+ { -+ SetLastError( RtlNtStatusToDosError(status) ); -+ return NULL; -+ } -+ -+ return work; -+} -+ -+/*********************************************************************** -+ * SetThreadpoolTimer (KERNEL32.@) -+ */ -+VOID WINAPI SetThreadpoolTimer( TP_TIMER *timer, FILETIME *due_time, -+ DWORD period, DWORD window_length ) -+{ -+ LARGE_INTEGER timeout; -+ -+ TRACE( "%p, %p, %u, %u\n", timer, due_time, period, window_length ); -+ -+ if (due_time) -+ { -+ timeout.u.LowPart = due_time->dwLowDateTime; -+ timeout.u.HighPart = due_time->dwHighDateTime; -+ } -+ -+ TpSetTimer( timer, due_time ? &timeout : NULL, period, window_length ); -+} -diff --git a/include/winternl.h b/include/winternl.h -index a84c6d4..e1707fd 100644 ---- a/include/winternl.h -+++ b/include/winternl.h -@@ -2616,6 +2616,33 @@ NTSYSAPI LONGLONG WINAPI RtlLargeIntegerSubtract(LONGLONG,LONGLONG); - NTSYSAPI NTSTATUS WINAPI RtlLargeIntegerToChar(const ULONGLONG *,ULONG,ULONG,PCHAR); - #endif - -+/* Threadpool functions */ -+ -+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 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 *); -+NTSYSAPI void WINAPI TpCallbackReleaseMutexOnCompletion(TP_CALLBACK_INSTANCE *,HANDLE); -+NTSYSAPI void WINAPI TpCallbackReleaseSemaphoreOnCompletion(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); -+NTSYSAPI void WINAPI TpCallbackSetEventOnCompletion(TP_CALLBACK_INSTANCE *,HANDLE); -+NTSYSAPI void WINAPI TpCallbackUnloadDllOnCompletion(TP_CALLBACK_INSTANCE *,HMODULE); -+NTSYSAPI void WINAPI TpDisassociateCallback(TP_CALLBACK_INSTANCE *); -+NTSYSAPI BOOL WINAPI TpIsTimerSet(TP_TIMER *); -+NTSYSAPI void WINAPI TpPostWork(TP_WORK *); -+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 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 NTSTATUS WINAPI TpSimpleTryPost(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); -+NTSYSAPI void WINAPI TpWaitForTimer(TP_TIMER *,BOOL); -+NTSYSAPI void WINAPI TpWaitForWork(TP_WORK *,BOOL); -+ - /* Wine internal functions */ - - NTSYSAPI NTSTATUS CDECL wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret, --- -2.4.4 - diff --git a/patches/ntdll-Vista_Threadpool/definition b/patches/ntdll-Vista_Threadpool/definition index dbffb71d..c7e3add8 100644 --- a/patches/ntdll-Vista_Threadpool/definition +++ b/patches/ntdll-Vista_Threadpool/definition @@ -1,4 +1,4 @@ -Fixes: [35192] Add implementation for CreateThreadpool -Fixes: [32531] Implement threadpool work items -Fixes: [37306] Implement threadpool timers +# 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 a285fca5..1926e1f9 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 3d8353fe182f3e7742cd7dab3420635e45ace129" + echo " commit 8b566b1da71a412fe58c3cc1988d610c2aba5f2d" echo "" } @@ -3691,32 +3691,15 @@ fi # Patchset ntdll-Vista_Threadpool # | -# | This patchset fixes the following Wine bugs: -# | * [#35192] Add implementation for CreateThreadpool -# | * [#32531] Implement threadpool work items -# | * [#37306] Implement threadpool timers -# | # | Modified files: -# | * dlls/kernel32/kernel32.spec, dlls/kernel32/tests/thread.c, dlls/kernel32/thread.c, dlls/ntdll/ntdll.spec, -# | dlls/ntdll/tests/threadpool.c, dlls/ntdll/threadpool.c, include/winternl.h +# | * 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-TpDisassociateCallback-and-add-separ.patch - patch_apply ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-TpDisassociateCallback.patch - patch_apply ntdll-Vista_Threadpool/0003-ntdll-Add-remaining-threadpool-functions-to-specfile.patch - patch_apply ntdll-Vista_Threadpool/0004-ntdll-Implement-threadpool-timer-functions.-rev-2.patch - patch_apply ntdll-Vista_Threadpool/0005-ntdll-tests-Add-tests-for-Tp-threadpool-functions.patch - patch_apply ntdll-Vista_Threadpool/0006-kernel32-Forward-various-threadpool-functions-to-ntd.patch - patch_apply ntdll-Vista_Threadpool/0007-ntdll-Implement-threadpool-wait-objects.patch - patch_apply ntdll-Vista_Threadpool/0008-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch - patch_apply ntdll-Vista_Threadpool/0009-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch + patch_apply ntdll-Vista_Threadpool/0001-ntdll-Implement-threadpool-wait-objects.patch + patch_apply ntdll-Vista_Threadpool/0002-ntdll-tests-Add-tests-for-threadpool-wait-objects.patch + patch_apply ntdll-Vista_Threadpool/0003-kernel32-Forward-threadpool-wait-functions-to-ntdll.patch ( - echo '+ { "Sebastian Lackner", "ntdll: Implement TpDisassociateCallback and add separate group finished event.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for TpDisassociateCallback.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Add remaining threadpool functions to specfile.", 1 },'; - echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool timer functions.", 2 },'; - echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for Tp* threadpool functions.", 1 },'; - echo '+ { "Sebastian Lackner", "kernel32: Forward various threadpool functions to ntdll.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll: Implement threadpool wait objects.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll/tests: Add tests for threadpool wait objects.", 1 },'; echo '+ { "Sebastian Lackner", "kernel32: Forward threadpool wait functions to ntdll.", 1 },'; diff --git a/patches/wined3d-CSMT_Main/0046-wined3d-Hackily-introduce-a-multithreaded-command-st.patch b/patches/wined3d-CSMT_Main/0046-wined3d-Hackily-introduce-a-multithreaded-command-st.patch index 5f1e6927..97c978b2 100644 --- a/patches/wined3d-CSMT_Main/0046-wined3d-Hackily-introduce-a-multithreaded-command-st.patch +++ b/patches/wined3d-CSMT_Main/0046-wined3d-Hackily-introduce-a-multithreaded-command-st.patch @@ -1,4 +1,4 @@ -From 449e8ea8593261284351648eb19504e8e8769dde Mon Sep 17 00:00:00 2001 +From 37df70888f1e9c12f63d5fc3a511ec34fce4b10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Tue, 1 Oct 2013 14:31:56 +0200 Subject: wined3d: Hackily introduce a multithreaded command stream @@ -10,7 +10,7 @@ Subject: wined3d: Hackily introduce a multithreaded command stream 3 files changed, 368 insertions(+), 39 deletions(-) diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index 639dc4f..9247d98 100644 +index daebc94..40c04db 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -24,8 +24,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d); @@ -467,7 +467,7 @@ index 639dc4f..9247d98 100644 { const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info; const struct wined3d_cs_set_texture *op = data; -@@ -708,6 +885,8 @@ static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data) +@@ -710,6 +887,8 @@ static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data) if (new_use_color_key) device_invalidate_state(cs->device, STATE_COLOR_KEY); @@ -476,7 +476,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture) -@@ -722,12 +901,14 @@ void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined +@@ -724,12 +903,14 @@ void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined cs->ops->submit(cs); } @@ -492,7 +492,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type, -@@ -744,12 +925,14 @@ void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3 +@@ -746,12 +927,14 @@ void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3 cs->ops->submit(cs); } @@ -508,7 +508,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type, -@@ -766,13 +949,15 @@ void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type +@@ -768,13 +951,15 @@ void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type cs->ops->submit(cs); } @@ -525,7 +525,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader) -@@ -787,12 +972,14 @@ void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type +@@ -789,12 +974,14 @@ void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type cs->ops->submit(cs); } @@ -541,7 +541,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value) -@@ -807,12 +994,14 @@ void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render +@@ -809,12 +996,14 @@ void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render cs->ops->submit(cs); } @@ -557,7 +557,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage, -@@ -829,12 +1018,14 @@ void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage, +@@ -831,12 +1020,14 @@ void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage, cs->ops->submit(cs); } @@ -573,7 +573,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx, -@@ -851,13 +1042,15 @@ void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx, +@@ -853,13 +1044,15 @@ void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx, cs->ops->submit(cs); } @@ -584,14 +584,14 @@ index 639dc4f..9247d98 100644 - cs->state.transforms[op->state] = *op->matrix; + cs->state.transforms[op->state] = op->matrix; - if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->gl_info.limits.blends)) + if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->d3d_info.limits.ffp_vertex_blend_matrices)) device_invalidate_state(cs->device, STATE_TRANSFORM(op->state)); + + return sizeof(*op); } void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform_state state, -@@ -868,17 +1061,19 @@ void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform +@@ -870,17 +1063,19 @@ void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform op = cs->ops->require_space(cs, sizeof(*op)); op->opcode = WINED3D_CS_OP_SET_TRANSFORM; op->state = state; @@ -614,7 +614,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const struct wined3d_vec4 *plane) -@@ -888,12 +1083,12 @@ void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const +@@ -890,12 +1085,12 @@ void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const op = cs->ops->require_space(cs, sizeof(*op)); op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE; op->plane_idx = plane_idx; @@ -629,7 +629,7 @@ index 639dc4f..9247d98 100644 { const struct wined3d_cs_set_color_key *op = data; struct wined3d_texture *texture = op->texture; -@@ -954,6 +1149,8 @@ static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *dat +@@ -956,6 +1151,8 @@ static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *dat break; } } @@ -638,7 +638,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture, -@@ -976,12 +1173,14 @@ void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture +@@ -978,12 +1175,14 @@ void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture cs->ops->submit(cs); } @@ -655,7 +655,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material) -@@ -990,12 +1189,12 @@ void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_ma +@@ -992,12 +1191,12 @@ void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_ma op = cs->ops->require_space(cs, sizeof(*op)); op->opcode = WINED3D_CS_OP_SET_MATERIAL; @@ -670,7 +670,7 @@ index 639dc4f..9247d98 100644 { struct wined3d_adapter *adapter = cs->device->adapter; HRESULT hr; -@@ -1005,6 +1204,8 @@ static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data) +@@ -1007,6 +1206,8 @@ static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data) if (FAILED(hr = state_init(&cs->state, &adapter->gl_info, &adapter->d3d_info, WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT))) ERR("Failed to initialize CS state, hr %#x.\n", hr); @@ -679,7 +679,7 @@ index 639dc4f..9247d98 100644 } void wined3d_cs_emit_reset_state(struct wined3d_cs *cs) -@@ -1017,8 +1218,9 @@ void wined3d_cs_emit_reset_state(struct wined3d_cs *cs) +@@ -1019,8 +1220,9 @@ void wined3d_cs_emit_reset_state(struct wined3d_cs *cs) cs->ops->submit(cs); } @@ -690,7 +690,7 @@ index 639dc4f..9247d98 100644 /* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present, /* WINED3D_CS_OP_CLEAR */ wined3d_cs_exec_clear, /* WINED3D_CS_OP_DRAW */ wined3d_cs_exec_draw, -@@ -1077,6 +1279,58 @@ static const struct wined3d_cs_ops wined3d_cs_st_ops = +@@ -1079,6 +1281,58 @@ static const struct wined3d_cs_ops wined3d_cs_st_ops = wined3d_cs_st_submit, }; @@ -749,7 +749,7 @@ index 639dc4f..9247d98 100644 struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; -@@ -1102,12 +1356,60 @@ struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device) +@@ -1104,12 +1358,60 @@ struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device) return NULL; } @@ -838,10 +838,10 @@ index 08021a2..088e59a 100644 if (appkey) RegCloseKey( appkey ); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 089faa4..2addced 100644 +index 59f9772..01c045b 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h -@@ -278,6 +278,7 @@ struct wined3d_settings +@@ -279,6 +279,7 @@ struct wined3d_settings unsigned int max_sm_gs; unsigned int max_sm_ps; BOOL no_3d; @@ -849,7 +849,7 @@ index 089faa4..2addced 100644 }; extern struct wined3d_settings wined3d_settings DECLSPEC_HIDDEN; -@@ -2573,6 +2574,18 @@ HRESULT state_init(struct wined3d_state *state, const struct wined3d_gl_info *gl +@@ -2589,6 +2590,18 @@ HRESULT state_init(struct wined3d_state *state, const struct wined3d_gl_info *gl const struct wined3d_d3d_info *d3d_info, DWORD flags) DECLSPEC_HIDDEN; void state_unbind_resources(struct wined3d_state *state) DECLSPEC_HIDDEN; @@ -868,7 +868,7 @@ index 089faa4..2addced 100644 struct wined3d_cs_ops { void *(*require_space)(struct wined3d_cs *cs, size_t size); -@@ -2584,9 +2597,14 @@ struct wined3d_cs +@@ -2600,9 +2613,14 @@ struct wined3d_cs const struct wined3d_cs_ops *ops; struct wined3d_device *device; struct wined3d_state state; @@ -884,5 +884,5 @@ index 089faa4..2addced 100644 struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device) DECLSPEC_HIDDEN; -- -2.3.5 +2.4.4 diff --git a/patches/wined3d-CSMT_Main/9999-IfDefined.patch b/patches/wined3d-CSMT_Main/9999-IfDefined.patch index 5b3cc523..4c107493 100644 --- a/patches/wined3d-CSMT_Main/9999-IfDefined.patch +++ b/patches/wined3d-CSMT_Main/9999-IfDefined.patch @@ -408,7 +408,7 @@ diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c float scale; union -@@ -4174,9 +4206,15 @@ +@@ -4178,9 +4210,15 @@ } } } else { @@ -424,7 +424,7 @@ diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c WARN("unsupported blending in openGl\n"); } } -@@ -4530,7 +4568,11 @@ +@@ -4534,7 +4572,11 @@ static void viewport_miscpart(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { @@ -436,7 +436,7 @@ diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c const struct wined3d_gl_info *gl_info = context->gl_info; struct wined3d_viewport vp = state->viewport; -@@ -4708,7 +4750,11 @@ +@@ -4712,7 +4754,11 @@ } else { @@ -448,7 +448,7 @@ diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c UINT height; UINT width; -@@ -4772,7 +4818,11 @@ +@@ -4776,7 +4822,11 @@ void state_srgbwrite(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { @@ -1099,7 +1099,7 @@ diff --git a/dlls/wined3d/volume.c b/dlls/wined3d/volume.c diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c -@@ -3514,7 +3514,11 @@ +@@ -3518,7 +3518,11 @@ float y_offset = context->render_offscreen ? (center_offset - (2.0f * y) - h) / h : (center_offset - (2.0f * y) - h) / -h; @@ -1111,7 +1111,7 @@ diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c state->render_states[WINED3D_RS_ZENABLE] : WINED3D_ZB_FALSE; float z_scale = zenable ? 2.0f : 0.0f; float z_offset = zenable ? -1.0f : 0.0f; -@@ -3637,6 +3641,7 @@ +@@ -3641,6 +3645,7 @@ /* case WINED3D_TTFF_COUNT1: Won't ever get here. */ case WINED3D_TTFF_COUNT2: mat._13 = mat._23 = mat._33 = mat._43 = 0.0f; @@ -1119,7 +1119,7 @@ diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c /* OpenGL divides the first 3 vertex coord by the 4th by default, * which is essentially the same as D3DTTFF_PROJECTED. Make sure that * the 4th coord evaluates to 1.0 to eliminate that. -@@ -3649,6 +3654,20 @@ +@@ -3653,6 +3658,20 @@ * A more serious problem occurs if the app passes 4 coordinates in, and the * 4th is != 1.0(opengl default). This would have to be fixed in draw_strided_slow * or a replacement shader. */ @@ -1140,7 +1140,7 @@ diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c default: mat._14 = mat._24 = mat._34 = 0.0f; mat._44 = 1.0f; } -@@ -4104,7 +4123,11 @@ +@@ -4108,7 +4127,11 @@ unsigned int i; DWORD ttff; DWORD cop, aop, carg0, carg1, carg2, aarg0, aarg1, aarg2; @@ -1747,7 +1747,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h #include #include #include -@@ -279,8 +307,10 @@ +@@ -280,8 +308,10 @@ unsigned int max_sm_gs; unsigned int max_sm_ps; BOOL no_3d; @@ -1758,7 +1758,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; extern struct wined3d_settings wined3d_settings DECLSPEC_HIDDEN; -@@ -1012,9 +1042,14 @@ +@@ -1014,9 +1044,14 @@ WORD use_map; /* MAX_ATTRIBS, 16 */ }; @@ -1773,7 +1773,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h DWORD get_flexible_vertex_size(DWORD d3dvtVertexType) DECLSPEC_HIDDEN; #define eps 1e-8f -@@ -1102,8 +1137,10 @@ +@@ -1104,8 +1139,10 @@ struct list entry; GLuint id; struct wined3d_context *context; @@ -1784,7 +1784,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; union wined3d_gl_query_object -@@ -1139,6 +1176,7 @@ +@@ -1141,6 +1178,7 @@ struct list entry; GLuint id; struct wined3d_context *context; @@ -1792,7 +1792,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h UINT64 timestamp; }; -@@ -1174,6 +1212,12 @@ +@@ -1176,6 +1214,12 @@ for (i = 0; i < min(dst->rt_size, src->rt_size); i++) dst->render_targets[i] = src->render_targets[i]; } @@ -1805,7 +1805,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h struct wined3d_context { -@@ -1189,7 +1233,9 @@ +@@ -1191,7 +1235,9 @@ DWORD dirtyArray[STATE_HIGHEST + 1]; /* Won't get bigger than that, a state is never marked dirty 2 times */ DWORD numDirtyEntries; DWORD isStateDirty[STATE_HIGHEST / (sizeof(DWORD) * CHAR_BIT) + 1]; /* Bitmap to find out quickly if a state is dirty */ @@ -1815,7 +1815,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h struct wined3d_swapchain *swapchain; struct wined3d_surface *current_rt; -@@ -1289,8 +1335,17 @@ +@@ -1291,8 +1337,17 @@ GLfloat fog_coord_value; GLfloat color[4], fogstart, fogend, fogcolor[4]; GLuint dummy_arbfp_prog; @@ -1833,7 +1833,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; typedef void (*APPLYSTATEFUNC)(struct wined3d_context *ctx, const struct wined3d_state *state, DWORD state_id); -@@ -1425,8 +1480,12 @@ +@@ -1427,8 +1482,12 @@ void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device) DECLSPEC_HIDDEN; BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb) DECLSPEC_HIDDEN; @@ -1846,7 +1846,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target, struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location) DECLSPEC_HIDDEN; void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, -@@ -1980,7 +2039,11 @@ +@@ -1984,7 +2043,11 @@ struct wined3d_state { DWORD flags; @@ -1858,7 +1858,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h struct wined3d_vertex_declaration *vertex_declaration; struct wined3d_stream_output stream_output[MAX_STREAM_OUT]; -@@ -2025,6 +2088,7 @@ +@@ -2029,6 +2092,7 @@ DWORD render_states[WINEHIGHEST_RENDER_STATE + 1]; }; @@ -1866,7 +1866,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h struct wined3d_gl_bo { GLuint name; -@@ -2033,6 +2097,7 @@ +@@ -2037,6 +2101,7 @@ UINT size; }; @@ -1874,7 +1874,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h #define WINED3D_UNMAPPED_STAGE ~0U /* Multithreaded flag. Removed from the public header to signal that -@@ -2088,11 +2153,23 @@ +@@ -2092,11 +2157,23 @@ struct wined3d_rendertarget_view *back_buffer_view; struct wined3d_swapchain **swapchains; UINT swapchain_count; @@ -1898,7 +1898,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h /* For rendering to a texture using glCopyTexImage */ GLuint depth_blt_texture; -@@ -2103,6 +2180,9 @@ +@@ -2107,6 +2184,9 @@ UINT xScreenSpace; UINT yScreenSpace; UINT cursorWidth, cursorHeight; @@ -1908,7 +1908,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h HCURSOR hardwareCursor; /* The Wine logo texture */ -@@ -2134,6 +2214,7 @@ +@@ -2138,6 +2218,7 @@ UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc) DECLSPEC_HIDDEN; void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource) DECLSPEC_HIDDEN; void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource) DECLSPEC_HIDDEN; @@ -1916,7 +1916,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void device_invalidate_state(const struct wined3d_device *device, DWORD state) DECLSPEC_HIDDEN; void device_invalidate_shader_constants(const struct wined3d_device *device, DWORD mask) DECLSPEC_HIDDEN; void device_exec_update_texture(struct wined3d_context *context, struct wined3d_texture *src_texture, -@@ -2145,6 +2226,11 @@ +@@ -2149,6 +2230,11 @@ void device_create_dummy_textures(struct wined3d_device *device, struct wined3d_context *context) DECLSPEC_HIDDEN; void device_delete_opengl_contexts_cs(struct wined3d_device *device, struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; @@ -1928,7 +1928,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h static inline BOOL isStateDirty(const struct wined3d_context *context, DWORD state) { -@@ -2161,9 +2247,11 @@ +@@ -2165,9 +2251,11 @@ ULONG (*resource_incref)(struct wined3d_resource *resource); ULONG (*resource_decref)(struct wined3d_resource *resource); void (*resource_unload)(struct wined3d_resource *resource); @@ -1940,7 +1940,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; struct wined3d_resource -@@ -2188,6 +2276,7 @@ +@@ -2192,6 +2280,7 @@ UINT depth; UINT size; DWORD priority; @@ -1948,7 +1948,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void *heap_memory, *map_heap_memory, *user_memory, *bitmap_data; UINT custom_row_pitch, custom_slice_pitch; struct wined3d_gl_bo *buffer, *map_buffer; -@@ -2195,6 +2284,11 @@ +@@ -2199,6 +2288,11 @@ DWORD locations; LONG access_fence; BOOL unmap_dirtify; @@ -1960,7 +1960,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void *parent; const struct wined3d_parent_ops *parent_ops; -@@ -2219,6 +2313,7 @@ +@@ -2223,6 +2317,7 @@ void *parent, const struct wined3d_parent_ops *parent_ops, const struct wined3d_resource_ops *resource_ops) DECLSPEC_HIDDEN; void resource_unload(struct wined3d_resource *resource) DECLSPEC_HIDDEN; @@ -1968,7 +1968,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h DWORD wined3d_resource_access_from_location(DWORD location) DECLSPEC_HIDDEN; BOOL wined3d_resource_allocate_sysmem(struct wined3d_resource *resource) DECLSPEC_HIDDEN; void wined3d_resource_changed(struct wined3d_resource *resource, -@@ -2265,6 +2360,15 @@ +@@ -2269,6 +2364,15 @@ { while(InterlockedCompareExchange(&resource->access_fence, 0, 0)); } @@ -1984,7 +1984,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h /* Tests show that the start address of resources is 32 byte aligned */ #define RESOURCE_ALIGNMENT 16 -@@ -2349,7 +2453,9 @@ +@@ -2353,7 +2457,9 @@ void wined3d_texture_apply_sampler_desc(struct wined3d_texture *texture, const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN; @@ -1994,7 +1994,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void wined3d_texture_bind(struct wined3d_texture *texture, struct wined3d_context *context, BOOL srgb) DECLSPEC_HIDDEN; void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture, -@@ -2383,9 +2489,16 @@ +@@ -2387,9 +2493,16 @@ struct wined3d_resource resource; struct wined3d_texture *container; @@ -2011,7 +2011,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; static inline struct wined3d_volume *volume_from_resource(struct wined3d_resource *resource) -@@ -2393,6 +2506,7 @@ +@@ -2397,6 +2510,7 @@ return CONTAINING_RECORD(resource, struct wined3d_volume, resource); } @@ -2019,7 +2019,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h HRESULT wined3d_volume_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc, unsigned int level, struct wined3d_volume **volume) DECLSPEC_HIDDEN; void wined3d_volume_destroy(struct wined3d_volume *volume) DECLSPEC_HIDDEN; -@@ -2405,6 +2519,23 @@ +@@ -2409,6 +2523,23 @@ struct wined3d_surface_dib { HBITMAP DIBsection; @@ -2043,7 +2043,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h UINT bitmap_size; }; -@@ -2430,7 +2561,11 @@ +@@ -2434,7 +2565,11 @@ struct wined3d_surface_ops { HRESULT (*surface_private_setup)(struct wined3d_surface *surface); @@ -2055,7 +2055,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; struct wined3d_surface -@@ -2438,12 +2573,25 @@ +@@ -2442,12 +2577,25 @@ struct wined3d_resource resource; const struct wined3d_surface_ops *surface_ops; struct wined3d_texture *container; @@ -2081,7 +2081,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h GLuint rb_multisample; GLuint rb_resolved; GLenum texture_target; -@@ -2487,10 +2635,19 @@ +@@ -2491,10 +2639,19 @@ GLenum surface_get_gl_buffer(const struct wined3d_surface *surface) DECLSPEC_HIDDEN; void surface_get_drawable_size(const struct wined3d_surface *surface, const struct wined3d_context *context, unsigned int *width, unsigned int *height) DECLSPEC_HIDDEN; @@ -2101,7 +2101,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void surface_modify_ds_location(struct wined3d_surface *surface, DWORD location, UINT w, UINT h) DECLSPEC_HIDDEN; void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample) DECLSPEC_HIDDEN; -@@ -2502,6 +2659,7 @@ +@@ -2506,6 +2663,7 @@ const struct wined3d_gl_info *gl_info, void *mem, unsigned int pitch) DECLSPEC_HIDDEN; HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point, struct wined3d_surface *src_surface, const RECT *src_rect) DECLSPEC_HIDDEN; @@ -2109,7 +2109,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags, struct wined3d_surface **surface) DECLSPEC_HIDDEN; -@@ -2520,6 +2678,21 @@ +@@ -2524,6 +2682,21 @@ void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter) DECLSPEC_HIDDEN; void surface_flip(struct wined3d_surface *front, struct wined3d_surface *back) DECLSPEC_HIDDEN; @@ -2131,7 +2131,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h /* Surface flags: */ #define SFLAG_DIBSECTION 0x00000001 /* Has a DIB section attached for GetDC. */ -@@ -2567,8 +2740,10 @@ +@@ -2571,8 +2744,10 @@ BOOL half_float_conv_needed; }; @@ -2142,7 +2142,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h struct wined3d_saved_states { DWORD transform[(HIGHEST_TRANSFORMSTATE >> 5) + 1]; -@@ -2636,6 +2811,7 @@ +@@ -2640,6 +2815,7 @@ void stateblock_init_contained_states(struct wined3d_stateblock *stateblock) DECLSPEC_HIDDEN; void state_cleanup(struct wined3d_state *state) DECLSPEC_HIDDEN; @@ -2150,7 +2150,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h HRESULT state_init(struct wined3d_state *state, const struct wined3d_gl_info *gl_info, const struct wined3d_d3d_info *d3d_info, DWORD flags) DECLSPEC_HIDDEN; void state_unbind_resources(struct wined3d_state *state) DECLSPEC_HIDDEN; -@@ -2686,6 +2862,32 @@ +@@ -2690,6 +2866,32 @@ void wined3d_cs_destroy(struct wined3d_cs *cs) DECLSPEC_HIDDEN; void wined3d_cs_switch_onscreen_ds(struct wined3d_cs *cs, struct wined3d_context *context, struct wined3d_surface *depth_stencil) DECLSPEC_HIDDEN; @@ -2183,7 +2183,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil) DECLSPEC_HIDDEN; -@@ -2735,6 +2937,7 @@ +@@ -2739,6 +2941,7 @@ void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3d_vertex_declaration *declaration) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport) DECLSPEC_HIDDEN; @@ -2191,7 +2191,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void wined3d_cs_emit_set_consts_f(struct wined3d_cs *cs, UINT start_register, const float *constants, UINT vector4f_count, enum wined3d_shader_type type) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_consts_b(struct wined3d_cs *cs, UINT start_register, -@@ -2794,6 +2997,7 @@ +@@ -2798,6 +3001,7 @@ struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; void wined3d_cs_emit_getdc(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN; void wined3d_cs_emit_releasedc(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN; @@ -2199,7 +2199,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h /* Direct3D terminology with little modifications. We do not have an issued state * because only the driver knows about it, but we have a created state because d3d -@@ -2808,8 +3012,12 @@ +@@ -2812,8 +3016,12 @@ struct wined3d_query_ops { HRESULT (*query_get_data)(struct wined3d_query *query, void *data, DWORD data_size, DWORD flags); @@ -2212,7 +2212,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; struct wined3d_query -@@ -2823,12 +3031,16 @@ +@@ -2827,12 +3035,16 @@ enum wined3d_query_type type; DWORD data_size; void *extendedData; @@ -2229,7 +2229,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h /* TODO: Add tests and support for FLOAT16_4 POSITIONT, D3DCOLOR position, other * fixed function semantics as D3DCOLOR or FLOAT16 */ -@@ -2855,7 +3067,9 @@ +@@ -2859,7 +3071,9 @@ GLenum buffer_object_usage; GLenum buffer_type_hint; DWORD flags; @@ -2239,7 +2239,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h void *map_ptr; struct wined3d_map_range *maps; -@@ -2880,11 +3094,15 @@ +@@ -2884,11 +3098,15 @@ BYTE *buffer_get_sysmem(struct wined3d_buffer *This, struct wined3d_context *context) DECLSPEC_HIDDEN; void buffer_internal_preload(struct wined3d_buffer *buffer, struct wined3d_context *context, const struct wined3d_state *state) DECLSPEC_HIDDEN; @@ -2255,7 +2255,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h struct wined3d_rendertarget_view { -@@ -2923,8 +3141,10 @@ +@@ -2927,8 +3145,10 @@ return surface_from_resource(resource); } @@ -2266,7 +2266,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h struct wined3d_shader_resource_view { LONG refcount; -@@ -2937,8 +3157,12 @@ +@@ -2941,8 +3161,12 @@ struct wined3d_swapchain_ops { void (*swapchain_present)(struct wined3d_swapchain *swapchain, const RECT *src_rect, @@ -2279,7 +2279,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h }; struct wined3d_swapchain -@@ -2978,8 +3202,10 @@ +@@ -2982,8 +3206,10 @@ HDC swapchain_get_backup_dc(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; void swapchain_update_render_to_fbo(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; @@ -2290,7 +2290,7 @@ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h /***************************************************************************** * Utility function prototypes -@@ -3183,7 +3409,9 @@ +@@ -3187,7 +3413,9 @@ void shader_generate_main(const struct wined3d_shader *shader, struct wined3d_string_buffer *buffer, const struct wined3d_shader_reg_maps *reg_maps, const DWORD *byte_code, void *backend_ctx) DECLSPEC_HIDDEN; BOOL shader_match_semantic(const char *semantic_name, enum wined3d_decl_usage usage) DECLSPEC_HIDDEN; @@ -4512,7 +4512,7 @@ diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c -@@ -1528,9 +1528,17 @@ +@@ -1546,9 +1546,17 @@ const struct wined3d_shader_reg_maps *reg_maps, const struct shader_glsl_ctx_priv *ctx_priv) { const struct wined3d_shader_version *version = ®_maps->shader_version; @@ -4530,7 +4530,7 @@ diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c unsigned int i, extra_constants_needed = 0; const struct wined3d_shader_lconst *lconst; const char *prefix; -@@ -1790,7 +1798,11 @@ +@@ -1808,7 +1816,11 @@ { UINT in_count = min(vec4_varyings(version->major, gl_info), shader->limits->packed_input); @@ -4542,7 +4542,7 @@ diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c shader_addline(buffer, "varying vec4 %s_link[%u];\n", prefix, in_count); shader_addline(buffer, "vec4 %s_in[%u];\n", prefix, in_count); } -@@ -1831,6 +1843,7 @@ +@@ -1849,6 +1861,7 @@ } else { @@ -4550,7 +4550,7 @@ diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c /* This happens because we do not have proper tracking of the * constant registers that are actually used, only the max * limit of the shader version. -@@ -1839,6 +1852,23 @@ +@@ -1857,6 +1870,23 @@ * it and just create the uniform. */ FIXME("Cannot find a free uniform for vpos correction params\n"); @@ -5463,7 +5463,7 @@ diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c + const struct wined3d_cs_set_transform *op = data; + + cs->state.transforms[op->state] = *op->matrix; -+ if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->gl_info.limits.blends)) ++ if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->d3d_info.limits.ffp_vertex_blend_matrices)) + device_invalidate_state(cs->device, STATE_TRANSFORM(op->state)); +} + @@ -9081,7 +9081,7 @@ diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c -@@ -1873,7 +1873,11 @@ +@@ -1867,7 +1867,11 @@ } } @@ -9093,7 +9093,7 @@ diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c { HeapFree(GetProcessHeap(), 0, shader->output_signature.elements); HeapFree(GetProcessHeap(), 0, shader->input_signature.elements); -@@ -2132,10 +2136,16 @@ +@@ -2125,10 +2129,16 @@ if (!refcount) { @@ -9110,7 +9110,7 @@ diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c } return refcount; -@@ -2412,7 +2422,11 @@ +@@ -2405,7 +2415,11 @@ memset(args, 0, sizeof(*args)); /* FIXME: Make sure all bits are set. */ if (!gl_info->supported[ARB_FRAMEBUFFER_SRGB] && state->render_states[WINED3D_RS_SRGBWRITEENABLE]) { @@ -9614,7 +9614,7 @@ diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c -@@ -5341,9 +5341,15 @@ +@@ -5343,9 +5343,15 @@ DebugBreak(); }