mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
Rebase against 8b566b1da71a412fe58c3cc1988d610c2aba5f2d.
This commit is contained in:
parent
dfd86e0f91
commit
cde323b772
@ -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\<UserSID> 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
|
||||
|
@ -1,175 +0,0 @@
|
||||
From 1651eab61e449fef2119ff35703d6c9acc43f2b3 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
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
|
||||
|
@ -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 <sebastian@fds-team.de>
|
||||
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 )
|
||||
}
|
||||
|
||||
/***********************************************************************
|
@ -1,191 +0,0 @@
|
||||
From 8041e8ccf5ed9021525a95b7c6bcedfa7d945cb4 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
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
|
||||
|
@ -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 <sebastian@fds-team.de>
|
||||
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
|
||||
|
@ -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 <sebastian@fds-team.de>
|
||||
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;
|
||||
}
|
||||
+
|
||||
+/***********************************************************************
|
@ -1,84 +0,0 @@
|
||||
From aef4ab9059bc29f2449c7ec19cb6562896ac1708 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
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
|
||||
|
@ -1,533 +0,0 @@
|
||||
From e138d4b3eedeb471f70f2e48cdbb8c4c55207554 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
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
|
||||
|
@ -1,294 +0,0 @@
|
||||
From 8e03c37240d2a0fafbe6347bc8d509ce5555757a Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
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
|
||||
|
@ -1,342 +0,0 @@
|
||||
From 37906069933d6bd73b8c6a691292288c57b09e22 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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 },';
|
||||
|
@ -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?= <stefan@codeweavers.com>
|
||||
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
|
||||
|
||||
|
@ -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 <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user