[KERNEL32][ROSTESTS][SDK] Enable threadpooling

[NTDLL] Init KeyedEvents even on NT5.2 dll_export
[MEDIA] Update winesync.txt accordingly
[SDK][DLL] Initialize crtical sections at runtime
This commit is contained in:
Justin Miller 2024-04-26 01:03:15 -07:00 committed by Justin Miller
parent 88a63011ea
commit 0bf42067d2
15 changed files with 249 additions and 842 deletions

View file

@ -1311,45 +1311,47 @@
@ stub -version=0x600+ ShipAssertMsgA
@ stub -version=0x600+ ShipAssertMsgW
@ stub -version=0x600+ TpAllocAlpcCompletion
@ stub -version=0x600+ TpAllocCleanupGroup
@ stub -version=0x600+ TpAllocIoCompletion
@ stub -version=0x600+ TpAllocPool
@ stub -version=0x600+ TpAllocTimer
@ stub -version=0x600+ TpAllocWait
@ stub -version=0x600+ TpAllocWork
@ stub -version=0x600+ TpCallbackLeaveCriticalSectionOnCompletion
@ stub -version=0x600+ TpCallbackMayRunLong
@ stub -version=0x600+ TpCallbackReleaseMutexOnCompletion
@ stub -version=0x600+ TpCallbackReleaseSemaphoreOnCompletion
@ stub -version=0x600+ TpCallbackSetEventOnCompletion
@ stub -version=0x600+ TpCallbackUnloadDllOnCompletion
@ stub -version=0x600+ TpCancelAsyncIoOperation
@ stdcall -version=0x600+ TpAllocCleanupGroup(ptr)
@ stdcall -version=0x600+ TpAllocIoCompletion(ptr ptr ptr ptr ptr)
@ stdcall -version=0x600+ TpAllocPool(ptr ptr)
@ stdcall -version=0x600+ TpAllocTimer(ptr ptr ptr ptr)
@ stdcall -version=0x600+ TpAllocWait(ptr ptr ptr ptr)
@ stdcall -version=0x600+ TpAllocWork(ptr ptr ptr ptr)
@ stdcall -version=0x600+ TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr)
@ stdcall -version=0x600+ TpCallbackMayRunLong(ptr)
@ stdcall -version=0x600+ TpCallbackReleaseMutexOnCompletion(ptr ptr)
@ stdcall -version=0x600+ TpCallbackReleaseSemaphoreOnCompletion(ptr ptr long)
@ stdcall -version=0x600+ TpCallbackSetEventOnCompletion(ptr ptr)
@ stdcall -version=0x600+ TpCallbackUnloadDllOnCompletion(ptr ptr)
@ stdcall -version=0x600+ TpCancelAsyncIoOperation(ptr)
@ stub -version=0x600+ TpCaptureCaller
@ stub -version=0x600+ TpCheckTerminateWorker
@ stub -version=0x600+ TpDbgDumpHeapUsage
@ stub -version=0x600+ TpDbgSetLogRoutine
@ stub -version=0x600+ TpDisassociateCallback
@ stub -version=0x600+ TpIsTimerSet
@ stub -version=0x600+ TpPostWork
@ stdcall -version=0x600+ TpDisassociateCallback(ptr)
@ stdcall -version=0x600+ TpIsTimerSet(ptr)
@ stdcall -version=0x600+ TpPostWork(ptr)
@ stdcall -version=0x600+ TpQueryPoolStackInformation(ptr ptr)
@ stub -version=0x600+ TpReleaseAlpcCompletion
@ stub -version=0x600+ TpReleaseCleanupGroup
@ stub -version=0x600+ TpReleaseCleanupGroupMembers
@ stub -version=0x600+ TpReleaseIoCompletion
@ stub -version=0x600+ TpReleasePool
@ stub -version=0x600+ TpReleaseTimer
@ stub -version=0x600+ TpReleaseWait
@ stub -version=0x600+ TpReleaseWork
@ stub -version=0x600+ TpSetPoolMaxThreads
@ stub -version=0x600+ TpSetPoolMinThreads
@ stub -version=0x600+ TpSetTimer
@ stub -version=0x600+ TpSetWait
@ stub -version=0x600+ TpSimpleTryPost
@ stub -version=0x600+ TpStartAsyncIoOperation
@ stdcall -version=0x600+ TpReleaseCleanupGroup(ptr)
@ stdcall -version=0x600+ TpReleaseCleanupGroupMembers(ptr long ptr)
@ stdcall -version=0x600+ TpReleaseIoCompletion(ptr)
@ stdcall -version=0x600+ TpReleasePool(ptr)
@ stdcall -version=0x600+ TpReleaseTimer(ptr)
@ stdcall -version=0x600+ TpReleaseWait(ptr)
@ stdcall -version=0x600+ TpReleaseWork(ptr)
@ stdcall -version=0x600+ TpSetPoolMaxThreads(ptr long)
@ stdcall -version=0x600+ TpSetPoolMinThreads(ptr long)
@ stdcall -version=0x600+ TpSetPoolStackInformation(ptr ptr)
@ stdcall -version=0x600+ TpSetTimer(ptr ptr long long)
@ stdcall -version=0x600+ TpSetWait(ptr long ptr)
@ stdcall -version=0x600+ TpSimpleTryPost(ptr ptr ptr)
@ stdcall -version=0x600+ TpStartAsyncIoOperation(ptr)
@ stub -version=0x600+ TpWaitForAlpcCompletion
@ stub -version=0x600+ TpWaitForIoCompletion
@ stub -version=0x600+ TpWaitForTimer
@ stub -version=0x600+ TpWaitForWait
@ stub -version=0x600+ TpWaitForWork
@ stdcall -version=0x600+ TpWaitForIoCompletion(ptr long)
@ stdcall -version=0x600+ TpWaitForTimer(ptr long)
@ stdcall -version=0x600+ TpWaitForWait(ptr long)
@ stdcall -version=0x600+ TpWaitForWork(ptr long)
@ stdcall -ret64 VerSetConditionMask(double long long)
@ stub -version=0x600+ WerCheckEventEscalation
@ stub -version=0x600+ WerReportSQMEvent

View file

@ -242,4 +242,9 @@ NTAPI
RtlpInitializeKeyedEvent(
VOID);
VOID
NTAPI
RtlpInitializeThreadPooling(
VOID);
/* EOF */

View file

@ -2415,10 +2415,10 @@ LdrpInitializeProcess(IN PCONTEXT Context,
/* Check whether all static imports were properly loaded and return here */
if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
#if (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
/* Following two calls are for Vista+ support, required for winesync */
/* Initialize the keyed event for condition variables */
RtlpInitializeKeyedEvent();
#endif
RtlpInitializeThreadPooling();
/* Initialize TLS */
Status = LdrpInitializeTls();

View file

@ -13,34 +13,5 @@
@ stdcall RtlRunOnceComplete(ptr long ptr)
@ stdcall RtlRunOnceExecuteOnce(ptr ptr ptr ptr)
@ stdcall TpAllocCleanupGroup(ptr)
@ stdcall TpAllocPool(ptr ptr)
@ stdcall TpAllocTimer(ptr ptr ptr ptr)
@ stdcall TpAllocWait(ptr ptr ptr ptr)
@ stdcall TpAllocWork(ptr ptr ptr ptr)
@ stdcall TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr)
@ stdcall TpCallbackMayRunLong(ptr)
@ stdcall TpCallbackReleaseMutexOnCompletion(ptr ptr)
@ stdcall TpCallbackReleaseSemaphoreOnCompletion(ptr ptr long)
@ stdcall TpCallbackSetEventOnCompletion(ptr ptr)
@ stdcall TpCallbackUnloadDllOnCompletion(ptr ptr)
@ stdcall TpDisassociateCallback(ptr)
@ stdcall TpIsTimerSet(ptr)
@ stdcall TpPostWork(ptr)
@ stdcall TpReleaseCleanupGroup(ptr)
@ stdcall TpReleaseCleanupGroupMembers(ptr long ptr)
@ stdcall TpReleasePool(ptr)
@ stdcall TpReleaseTimer(ptr)
@ stdcall TpReleaseWait(ptr)
@ stdcall TpReleaseWork(ptr)
@ stdcall TpSetPoolMaxThreads(ptr long)
@ stdcall TpSetPoolMinThreads(ptr long)
@ stdcall TpSetTimer(ptr ptr long long)
@ stdcall TpSetWait(ptr long ptr)
@ stdcall TpSimpleTryPost(ptr ptr ptr)
@ stdcall TpWaitForTimer(ptr long)
@ stdcall TpWaitForWait(ptr long)
@ stdcall TpWaitForWork(ptr long)
@ stdcall RtlConnectToSm(ptr ptr long ptr) SmConnectToSm
@ stdcall RtlSendMsgToSm(ptr ptr) SmSendMsgToSm

View file

@ -267,8 +267,8 @@ check Wine current sources first as it may already be fixed.
sdk/lib/3rdparty/strmbase # Synced to WineStaging-3.3
sdk/lib/rtl/actctx.c # Synced to wine-5.18
sdk/lib/rtl/threadpool.c # Synced with wine-9.7
sdk/lib/rtl/actctx.c # Partly synced with WineStaging-1.9.16
sdk/lib/rtl/threadpool.c # Synced with Wine-9.7
advapi32 -
dll/win32/advapi32/wine/cred.c # Synced to WineStaging-3.3

View file

@ -23,6 +23,7 @@ list(APPEND SOURCE
rtlstr.c
string.c
testlist.c
threadpool.c
time.c)
if(ARCH STREQUAL "i386")

View file

@ -23,6 +23,7 @@ extern void func_rtl(void);
extern void func_rtlbitmap(void);
extern void func_rtlstr(void);
extern void func_string(void);
extern void func_threadpool(void);
extern void func_time(void);
const struct test winetest_testlist[] =
@ -49,6 +50,7 @@ const struct test winetest_testlist[] =
{ "rtlbitmap", func_rtlbitmap },
{ "rtlstr", func_rtlstr },
{ "string", func_string },
{ "threadpool", func_threadpool},
{ "time", func_time },
{ 0, 0 }
};

View file

@ -20,6 +20,10 @@
#include "ntdll_test.h"
#ifdef __REACTOS__
typedef void (CALLBACK *PTP_IO_CALLBACK)(PTP_CALLBACK_INSTANCE,void*,void*,IO_STATUS_BLOCK*,PTP_IO);
#endif
static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *);
static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
@ -580,7 +584,9 @@ static void test_tp_simple(void)
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
TP_POOL_STACK_INFORMATION stack_info;
TP_CALLBACK_ENVIRON environment;
#ifndef __REACTOS__
TP_CALLBACK_ENVIRON_V3 environment3;
#endif
TP_CLEANUP_GROUP *group;
HANDLE semaphore;
NTSTATUS status;
@ -616,6 +622,7 @@ static void test_tp_simple(void)
result = WaitForSingleObject(semaphore, 1000);
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
#ifndef __REACTOS__ // Windows 7
/* test with environment version 3 */
memset(&environment3, 0, sizeof(environment3));
environment3.Version = 3;
@ -635,6 +642,7 @@ static void test_tp_simple(void)
status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */,
"TpSimpleTryPost failed with status %lx\n", status);
#endif
/* test with invalid version number */
memset(&environment, 0, sizeof(environment));
@ -2031,7 +2039,11 @@ static DWORD WINAPI io_wait_thread(void *arg)
static void test_tp_io(void)
{
TP_CALLBACK_ENVIRON environment = {.Version = 1};
#ifdef __REACTOS__
OVERLAPPED ovl = {0}, ovl2 = {0};
#else
OVERLAPPED ovl = {}, ovl2 = {};
#endif
HANDLE client, server, thread;
struct io_cb_ctx userdata;
char in[1], in2[1];
@ -2251,7 +2263,11 @@ static void CALLBACK kernel32_io_cb(TP_CALLBACK_INSTANCE *instance, void *userda
static void test_kernel32_tp_io(void)
{
TP_CALLBACK_ENVIRON environment = {.Version = 1};
#ifdef __REACTOS__
OVERLAPPED ovl = {0}, ovl2 = {0};
#else
OVERLAPPED ovl = {}, ovl2 = {};
#endif
HANDLE client, server, thread;
struct io_cb_ctx userdata;
char in[1], in2[1];

View file

@ -4748,24 +4748,29 @@ RtlSleepConditionVariableSRW(
//
// Synchronization functions
//
NTSYSAPI
VOID
NTAPI
RtlInitializeConditionVariable(OUT PRTL_CONDITION_VARIABLE ConditionVariable);
NTSYSAPI
VOID
NTAPI
RtlWakeConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable);
NTSYSAPI
VOID
NTAPI
RtlWakeAllConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable);
NTSYSAPI
NTSTATUS
NTAPI
RtlSleepConditionVariableCS(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable,
IN OUT PRTL_CRITICAL_SECTION CriticalSection,
IN const PLARGE_INTEGER TimeOut OPTIONAL);
NTSYSAPI
NTSTATUS
NTAPI
RtlSleepConditionVariableSRW(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable,

View file

@ -4495,6 +4495,12 @@ typedef enum _TP_CALLBACK_PRIORITY {
TP_CALLBACK_PRIORITY_COUNT = TP_CALLBACK_PRIORITY_INVALID
} TP_CALLBACK_PRIORITY;
typedef struct _TP_POOL_STACK_INFORMATION
{
SIZE_T StackReserve;
SIZE_T StackCommit;
} TP_POOL_STACK_INFORMATION,*PTP_POOL_STACK_INFORMATION;
typedef VOID
(NTAPI *PTP_WORK_CALLBACK)(
_Inout_ PTP_CALLBACK_INSTANCE Instance,

View file

@ -8,13 +8,19 @@ add_definitions(
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
# Enable this again. CORE-17637
add_compile_options(-Wunused-result)
add_compile_options(-Wno-incompatible-pointer-types)
add_compile_options(-Wno-missing-braces)
endif()
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
list(APPEND RTL_WINE_SOURCE
actctx.c
timerqueue.c
wait.c
threadpool.c
)
set_source_files_properties(threadpool.c PROPERTIES COMPILE_DEFINITIONS __WINESRC__)
if(MSVC)
# Silence warning C4267: 'initializing': conversion from 'size_t' to 'const int', possible loss of data
@ -127,7 +133,6 @@ list(APPEND SOURCE_VISTA
condvar.c
runonce.c
srw.c
threadpool.c
utf8.c)
add_library(rtl_vista ${SOURCE_VISTA})

View file

@ -56,6 +56,7 @@
/* Use intrinsics for x86 and x64 */
#if defined(_M_IX86) || defined(_M_AMD64)
#ifndef InterlockedCompareExchange
#define InterlockedCompareExchange _InterlockedCompareExchange
#define InterlockedIncrement _InterlockedIncrement
#define InterlockedDecrement _InterlockedDecrement
@ -64,5 +65,6 @@
#define InterlockedBitTestAndSet _interlockedbittestandset
#define InterlockedBitTestAndSet64 _interlockedbittestandset64
#endif
#endif
#endif /* RTL_H */

View file

@ -19,6 +19,42 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifdef __REACTOS__
#include <rtl_vista.h>
#define NDEBUG
#include "wine/list.h"
#include <debug.h>
#define ERR(fmt, ...) DPRINT1(fmt, ##__VA_ARGS__)
#define FIXME(fmt, ...) DPRINT(fmt, ##__VA_ARGS__)
#define WARN(fmt, ...) DPRINT(fmt, ##__VA_ARGS__)
#define TRACE(fmt, ...) DPRINT(fmt, ##__VA_ARGS__)
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(_x) (sizeof((_x))/sizeof((_x)[0]))
#endif
typedef struct _THREAD_NAME_INFORMATION
{
UNICODE_STRING ThreadName;
} THREAD_NAME_INFORMATION, *PTHREAD_NAME_INFORMATION;
typedef void (CALLBACK *PNTAPCFUNC)(ULONG_PTR,ULONG_PTR,ULONG_PTR);
typedef void (CALLBACK *PRTL_THREAD_START_ROUTINE)(LPVOID);
typedef DWORD (CALLBACK *PRTL_WORK_ITEM_ROUTINE)(LPVOID);
typedef void (NTAPI *RTL_WAITORTIMERCALLBACKFUNC)(PVOID,BOOLEAN);
typedef VOID (CALLBACK *PRTL_OVERLAPPED_COMPLETION_ROUTINE)(DWORD,DWORD,LPVOID);
typedef void (CALLBACK *PTP_IO_CALLBACK)(PTP_CALLBACK_INSTANCE,void*,void*,IO_STATUS_BLOCK*,PTP_IO);
NTSYSAPI NTSTATUS WINAPI TpSimpleTryPost(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
#define PRTL_WORK_ITEM_ROUTINE WORKERCALLBACKFUNC
#define CRITICAL_SECTION RTL_CRITICAL_SECTION
#define GetProcessHeap() RtlGetProcessHeap()
#define GetCurrentProcess() NtCurrentProcess()
#define GetCurrentThread() NtCurrentThread()
#define GetCurrentThreadId() HandleToULong(NtCurrentTeb()->ClientId.UniqueThread)
#else
#include <assert.h>
#include <stdarg.h>
#include <limits.h>
@ -33,6 +69,7 @@
#include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(threadpool);
#endif
/*
* Old thread pooling API
@ -47,7 +84,9 @@ struct rtl_work_item
#define EXPIRE_NEVER (~(ULONGLONG)0)
#define TIMER_QUEUE_MAGIC 0x516d6954 /* TimQ */
#ifndef __REACTOS__
static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug;
#endif
static struct
{
@ -57,15 +96,21 @@ static struct
old_threadpool =
{
NULL, /* compl_port */
#ifdef __REACTOS__
{0}, /* threadpool_compl_cs */
#else
{ &critsect_compl_debug, -1, 0, 0, 0, 0 }, /* threadpool_compl_cs */
#endif
};
#ifndef __REACTOS__
static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug =
{
0, 0, &old_threadpool.threadpool_compl_cs,
{ &critsect_compl_debug.ProcessLocksList, &critsect_compl_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": threadpool_compl_cs") }
};
#endif
struct timer_queue;
struct queue_timer
@ -235,8 +280,10 @@ struct threadpool_group
struct list members;
};
#ifndef __REACTOS__
/* global timerqueue object */
static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug;
#endif
static struct
{
@ -248,13 +295,22 @@ static struct
}
timerqueue =
{
#ifdef __REACTOS__
{0}, /* cs */
#else
{ &timerqueue_debug, -1, 0, 0, 0, 0 }, /* cs */
#endif
0, /* objcount */
FALSE, /* thread_running */
LIST_INIT( timerqueue.pending_timers ), /* pending_timers */
#if __REACTOS__
0,
#else
RTL_CONDITION_VARIABLE_INIT /* update_event */
#endif
};
#ifndef __REACTOS__
static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug =
{
0, 0, &timerqueue.cs,
@ -264,6 +320,7 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug =
/* global waitqueue object */
static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug;
#endif
static struct
{
@ -273,17 +330,23 @@ static struct
}
waitqueue =
{
#ifdef __REACTOS__
{0}, /* cs */
#else
{ &waitqueue_debug, -1, 0, 0, 0, 0 }, /* cs */
#endif
0, /* num_buckets */
LIST_INIT( waitqueue.buckets ) /* buckets */
};
#ifndef __REACTOS__
static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug =
{
0, 0, &waitqueue.cs,
{ &waitqueue_debug.ProcessLocksList, &waitqueue_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": waitqueue.cs") }
};
#endif
struct waitqueue_bucket
{
@ -295,8 +358,10 @@ struct waitqueue_bucket
BOOL alertable;
};
#ifndef __REACTOS__
/* global I/O completion queue object */
static RTL_CRITICAL_SECTION_DEBUG ioqueue_debug;
#endif
static struct
{
@ -308,15 +373,21 @@ static struct
}
ioqueue =
{
#ifdef __REACTOS__
.cs = {0},
#else
.cs = { &ioqueue_debug, -1, 0, 0, 0, 0 },
#endif
};
#ifndef __REACTOS__
static RTL_CRITICAL_SECTION_DEBUG ioqueue_debug =
{
0, 0, &ioqueue.cs,
{ &ioqueue_debug.ProcessLocksList, &ioqueue_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": ioqueue.cs") }
};
#endif
static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool )
{
@ -361,7 +432,11 @@ static inline struct threadpool_instance *impl_from_TP_CALLBACK_INSTANCE( TP_CAL
return (struct threadpool_instance *)instance;
}
#ifdef __REACTOS__
ULONG NTAPI threadpool_worker_proc(PVOID param );
#else
static void CALLBACK threadpool_worker_proc( void *param );
#endif
static void tp_object_submit( struct threadpool_object *object, BOOL signaled );
static void tp_object_execute( struct threadpool_object *object, BOOL wait_thread );
static void tp_object_prepare_shutdown( struct threadpool_object *object );
@ -397,12 +472,15 @@ static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int
static void set_thread_name(const WCHAR *name)
{
#ifndef __REACTOS__ // This is impossible on non vista+
THREAD_NAME_INFORMATION info;
RtlInitUnicodeString(&info.ThreadName, name);
NtSetInformationThread(GetCurrentThread(), ThreadNameInformation, &info, sizeof(info));
#endif
}
#ifndef __REACTOS__
static void CALLBACK process_rtl_work_item( TP_CALLBACK_INSTANCE *instance, void *userdata )
{
struct rtl_work_item *item = userdata;
@ -472,7 +550,11 @@ static DWORD CALLBACK iocp_poller(LPVOID Arg)
PRTL_OVERLAPPED_COMPLETION_ROUTINE callback;
LPVOID overlapped;
IO_STATUS_BLOCK iosb;
#ifdef __REACTOS__
NTSTATUS res = NtRemoveIoCompletion( cport, (PVOID)&callback, (PVOID)&overlapped, &iosb, NULL );
#else
NTSTATUS res = NtRemoveIoCompletion( cport, (PULONG_PTR)&callback, (PULONG_PTR)&overlapped, &iosb, NULL );
#endif
if (res)
{
ERR("NtRemoveIoCompletion failed: 0x%lx\n", res);
@ -545,6 +627,7 @@ NTSTATUS WINAPI RtlSetIoCompletionCallback(HANDLE FileHandle, PRTL_OVERLAPPED_CO
return NtSetInformationFile( FileHandle, &iosb, &info, sizeof(info), FileCompletionInformation );
}
#endif
static inline PLARGE_INTEGER get_nt_timeout( PLARGE_INTEGER pTime, ULONG timeout )
{
@ -553,7 +636,6 @@ static inline PLARGE_INTEGER get_nt_timeout( PLARGE_INTEGER pTime, ULONG timeout
return pTime;
}
/************************** Timer Queue Impl **************************/
static void queue_remove_timer(struct queue_timer *t)
@ -705,7 +787,11 @@ static ULONG queue_get_timeout(struct timer_queue *q)
return timeout;
}
#ifdef __REACTOS__
ULONG NTAPI timer_queue_thread_proc(PVOID p)
#else
static void WINAPI timer_queue_thread_proc(LPVOID p)
#endif
{
struct timer_queue *q = p;
ULONG timeout_ms;
@ -746,6 +832,9 @@ static void WINAPI timer_queue_thread_proc(LPVOID p)
q->magic = 0;
RtlFreeHeap(GetProcessHeap(), 0, q);
RtlExitUserThread( 0 );
#ifdef __REACTOS__
return STATUS_SUCCESS;
#endif
}
static void queue_destroy_timer(struct queue_timer *t)
@ -1052,7 +1141,11 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer,
/***********************************************************************
* timerqueue_thread_proc (internal)
*/
#ifdef __REACTOS__
ULONG NTAPI timerqueue_thread_proc(PVOID param )
#else
static void CALLBACK timerqueue_thread_proc( void *param )
#endif
{
ULONGLONG timeout_lower, timeout_upper, new_timeout;
struct threadpool_object *other_timer;
@ -1139,6 +1232,9 @@ static void CALLBACK timerqueue_thread_proc( void *param )
TRACE( "terminating timer queue thread\n" );
RtlExitUserThread( 0 );
#ifdef __REACTOS__
return STATUS_SUCCESS;
#endif
}
/***********************************************************************
@ -1240,7 +1336,11 @@ static void tp_timerqueue_unlock( struct threadpool_object *timer )
/***********************************************************************
* waitqueue_thread_proc (internal)
*/
#ifdef __REACTOS__
void NTAPI waitqueue_thread_proc(PVOID param )
#else
static void CALLBACK waitqueue_thread_proc( void *param )
#endif
{
struct threadpool_object *objects[MAXIMUM_WAITQUEUE_OBJECTS];
HANDLE handles[MAXIMUM_WAITQUEUE_OBJECTS + 1];
@ -1467,7 +1567,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait )
}
status = RtlCreateUserThread( GetCurrentProcess(), NULL, FALSE, 0, 0, 0,
waitqueue_thread_proc, bucket, &thread, NULL );
(PTHREAD_START_ROUTINE)waitqueue_thread_proc, bucket, &thread, NULL );
if (status == STATUS_SUCCESS)
{
list_add_tail( &waitqueue.buckets, &bucket->bucket_entry );
@ -1512,12 +1612,20 @@ static void tp_waitqueue_unlock( struct threadpool_object *wait )
RtlLeaveCriticalSection( &waitqueue.cs );
}
#ifdef __REACTOS__
ULONG NTAPI ioqueue_thread_proc(PVOID param )
#else
static void CALLBACK ioqueue_thread_proc( void *param )
#endif
{
struct io_completion *completion;
struct threadpool_object *io;
IO_STATUS_BLOCK iosb;
#ifdef __REACTOS__
PVOID key, value;
#else
ULONG_PTR key, value;
#endif
BOOL destroy, skip;
NTSTATUS status;
@ -1581,7 +1689,11 @@ static void CALLBACK ioqueue_thread_proc( void *param )
completion = &io->u.io.completions[io->u.io.completion_count++];
completion->iosb = iosb;
#ifdef __REACTOS__
completion->cvalue = (ULONG_PTR)value;
#else
completion->cvalue = value;
#endif
tp_object_submit( io, FALSE );
}
@ -1606,6 +1718,10 @@ static void CALLBACK ioqueue_thread_proc( void *param )
TRACE( "terminating I/O completion thread\n" );
RtlExitUserThread( 0 );
#ifdef __REACTOS__
return STATUS_SUCCESS;
#endif
}
static NTSTATUS tp_ioqueue_lock( struct threadpool_object *io, HANDLE file )
@ -1640,8 +1756,13 @@ static NTSTATUS tp_ioqueue_lock( struct threadpool_object *io, HANDLE file )
FILE_COMPLETION_INFORMATION info;
IO_STATUS_BLOCK iosb;
#ifdef __REACTOS__
info.Port = ioqueue.port;
info.Key = io;
#else
info.CompletionPort = ioqueue.port;
info.CompletionKey = (ULONG_PTR)io;
#endif
status = NtSetInformationFile( file, &iosb, &info, sizeof(info), FileCompletionInformation );
}
@ -1663,7 +1784,11 @@ static NTSTATUS tp_ioqueue_lock( struct threadpool_object *io, HANDLE file )
*/
static NTSTATUS tp_threadpool_alloc( struct threadpool **out )
{
#ifdef __REACTOS__
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->ProcessEnvironmentBlock->ImageBaseAddress );
#else
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
#endif
struct threadpool *pool;
unsigned int i;
@ -1675,8 +1800,13 @@ static NTSTATUS tp_threadpool_alloc( struct threadpool **out )
pool->objcount = 0;
pool->shutdown = FALSE;
#ifdef __REACTOS__
RtlInitializeCriticalSection( &pool->cs );
#else
RtlInitializeCriticalSectionEx( &pool->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
pool->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool.cs");
#endif
for (i = 0; i < ARRAY_SIZE(pool->pools); ++i)
list_init( &pool->pools[i] );
@ -1728,8 +1858,9 @@ static BOOL tp_threadpool_release( struct threadpool *pool )
assert( !pool->objcount );
for (i = 0; i < ARRAY_SIZE(pool->pools); ++i)
assert( list_empty( &pool->pools[i] ) );
#ifndef __REACTOS__
pool->cs.DebugInfo->Spare[0] = 0;
#endif
RtlDeleteCriticalSection( &pool->cs );
RtlFreeHeap( GetProcessHeap(), 0, pool );
@ -1750,6 +1881,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON
if (environment)
{
#ifndef __REACTOS__ //Windows 7 stuff
/* Validate environment parameters. */
if (environment->Version == 3)
{
@ -1765,7 +1897,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON
return STATUS_INVALID_PARAMETER;
}
}
#endif
pool = (struct threadpool *)environment->Pool;
}
@ -1786,7 +1918,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON
pool = default_threadpool;
}
RtlEnterCriticalSection( &pool->cs );
/* Make sure that the threadpool has at least one thread. */
@ -1839,8 +1971,13 @@ static NTSTATUS tp_group_alloc( struct threadpool_group **out )
group->refcount = 1;
group->shutdown = FALSE;
#ifdef __REACTOS__
RtlInitializeCriticalSection( &group->cs );
#else
RtlInitializeCriticalSectionEx( &group->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
group->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool_group.cs");
#endif
list_init( &group->members );
@ -1875,7 +2012,9 @@ static BOOL tp_group_release( struct threadpool_group *group )
assert( group->shutdown );
assert( list_empty( &group->members ) );
#ifndef __REACTOS__
group->cs.DebugInfo->Spare[0] = 0;
#endif
RtlDeleteCriticalSection( &group->cs );
RtlFreeHeap( GetProcessHeap(), 0, group );
@ -1925,6 +2064,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
object->finalization_callback = environment->FinalizationCallback;
object->may_run_long = environment->u.s.LongFunction != 0;
object->race_dll = environment->RaceDll;
#ifndef __REACTOS__ //Windows 7 stuff
if (environment->Version == 3)
{
TP_CALLBACK_ENVIRON_V3 *environment_v3 = (TP_CALLBACK_ENVIRON_V3 *)environment;
@ -1932,7 +2072,7 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa
object->priority = environment_v3->CallbackPriority;
assert( object->priority < ARRAY_SIZE(pool->pools) );
}
#endif
if (environment->ActivationContext)
FIXME( "activation context not supported yet\n" );
@ -2328,7 +2468,11 @@ skip_cleanup:
/***********************************************************************
* threadpool_worker_proc (internal)
*/
#ifdef __REACTOS__
ULONG NTAPI threadpool_worker_proc(PVOID param )
#else
static void CALLBACK threadpool_worker_proc( void *param )
#endif
{
struct threadpool *pool = param;
LARGE_INTEGER timeout;
@ -2382,6 +2526,9 @@ static void CALLBACK threadpool_worker_proc( void *param )
TRACE( "terminating worker thread for pool %p\n", pool );
tp_threadpool_release( pool );
RtlExitUserThread( 0 );
#ifdef __REACTOS__
return STATUS_SUCCESS;
#endif
}
/***********************************************************************
@ -3355,3 +3502,16 @@ NTSTATUS WINAPI RtlDeregisterWait(HANDLE WaitHandle)
{
return RtlDeregisterWaitEx(WaitHandle, NULL);
}
#ifdef __REACTOS__
VOID
NTAPI
RtlpInitializeThreadPooling(
VOID)
{
RtlInitializeCriticalSection(&old_threadpool.threadpool_compl_cs);
RtlInitializeCriticalSection(&timerqueue.cs);
RtlInitializeCriticalSection(&waitqueue.cs);
RtlInitializeCriticalSection(&ioqueue.cs);
}
#endif

View file

@ -64,405 +64,6 @@ struct timer_queue
#define EXPIRE_NEVER (~(ULONGLONG) 0)
#define TIMER_QUEUE_MAGIC 0x516d6954 /* TimQ */
static void queue_remove_timer(struct queue_timer *t)
{
/* We MUST hold the queue cs while calling this function. This ensures
that we cannot queue another callback for this timer. The runcount
being zero makes sure we don't have any already queued. */
struct timer_queue *q = t->q;
assert(t->runcount == 0);
assert(t->destroy);
list_remove(&t->entry);
if (t->event)
NtSetEvent(t->event, NULL);
RtlFreeHeap(RtlGetProcessHeap(), 0, t);
if (q->quit && list_empty(&q->timers))
NtSetEvent(q->event, NULL);
}
static void timer_cleanup_callback(struct queue_timer *t)
{
struct timer_queue *q = t->q;
RtlEnterCriticalSection(&q->cs);
assert(0 < t->runcount);
--t->runcount;
if (t->destroy && t->runcount == 0)
queue_remove_timer(t);
RtlLeaveCriticalSection(&q->cs);
}
static VOID WINAPI timer_callback_wrapper(LPVOID p)
{
struct queue_timer *t = p;
t->callback(t->param, TRUE);
timer_cleanup_callback(t);
}
static inline ULONGLONG queue_current_time(void)
{
LARGE_INTEGER now, freq;
NtQueryPerformanceCounter(&now, &freq);
return now.QuadPart * 1000 / freq.QuadPart;
}
static void queue_add_timer(struct queue_timer *t, ULONGLONG time,
BOOL set_event)
{
/* We MUST hold the queue cs while calling this function. */
struct timer_queue *q = t->q;
struct list *ptr = &q->timers;
assert(!q->quit || (t->destroy && time == EXPIRE_NEVER));
if (time != EXPIRE_NEVER)
LIST_FOR_EACH(ptr, &q->timers)
{
struct queue_timer *cur = LIST_ENTRY(ptr, struct queue_timer, entry);
if (time < cur->expire)
break;
}
list_add_before(ptr, &t->entry);
t->expire = time;
/* If we insert at the head of the list, we need to expire sooner
than expected. */
if (set_event && &t->entry == list_head(&q->timers))
NtSetEvent(q->event, NULL);
}
static inline void queue_move_timer(struct queue_timer *t, ULONGLONG time,
BOOL set_event)
{
/* We MUST hold the queue cs while calling this function. */
list_remove(&t->entry);
queue_add_timer(t, time, set_event);
}
static void queue_timer_expire(struct timer_queue *q)
{
struct queue_timer *t = NULL;
RtlEnterCriticalSection(&q->cs);
if (list_head(&q->timers))
{
ULONGLONG now, next;
t = LIST_ENTRY(list_head(&q->timers), struct queue_timer, entry);
if (!t->destroy && t->expire <= ((now = queue_current_time())))
{
++t->runcount;
if (t->period)
{
next = t->expire + t->period;
/* avoid trigger cascade if overloaded / hibernated */
if (next < now)
next = now + t->period;
}
else
next = EXPIRE_NEVER;
queue_move_timer(t, next, FALSE);
}
else
t = NULL;
}
RtlLeaveCriticalSection(&q->cs);
if (t)
{
if (t->flags & WT_EXECUTEINTIMERTHREAD)
timer_callback_wrapper(t);
else
{
ULONG flags
= (t->flags
& (WT_EXECUTEINIOTHREAD | WT_EXECUTEINPERSISTENTTHREAD
| WT_EXECUTELONGFUNCTION | WT_TRANSFER_IMPERSONATION));
NTSTATUS status = RtlQueueWorkItem(timer_callback_wrapper, t, flags);
if (status != STATUS_SUCCESS)
timer_cleanup_callback(t);
}
}
}
static ULONG queue_get_timeout(struct timer_queue *q)
{
struct queue_timer *t;
ULONG timeout = INFINITE;
RtlEnterCriticalSection(&q->cs);
if (list_head(&q->timers))
{
t = LIST_ENTRY(list_head(&q->timers), struct queue_timer, entry);
assert(!t->destroy || t->expire == EXPIRE_NEVER);
if (t->expire != EXPIRE_NEVER)
{
ULONGLONG time = queue_current_time();
timeout = t->expire < time ? 0 : (ULONG)(t->expire - time);
}
}
RtlLeaveCriticalSection(&q->cs);
return timeout;
}
static DWORD WINAPI timer_queue_thread_proc(LPVOID p)
{
struct timer_queue *q = p;
ULONG timeout_ms;
timeout_ms = INFINITE;
for (;;)
{
LARGE_INTEGER timeout;
NTSTATUS status;
BOOL done = FALSE;
status = NtWaitForSingleObject(
q->event, FALSE, get_nt_timeout(&timeout, timeout_ms));
if (status == STATUS_WAIT_0)
{
/* There are two possible ways to trigger the event. Either
we are quitting and the last timer got removed, or a new
timer got put at the head of the list so we need to adjust
our timeout. */
RtlEnterCriticalSection(&q->cs);
if (q->quit && list_empty(&q->timers))
done = TRUE;
RtlLeaveCriticalSection(&q->cs);
}
else if (status == STATUS_TIMEOUT)
queue_timer_expire(q);
if (done)
break;
timeout_ms = queue_get_timeout(q);
}
NtClose(q->event);
RtlDeleteCriticalSection(&q->cs);
q->magic = 0;
RtlFreeHeap(RtlGetProcessHeap(), 0, q);
RtlpExitThreadFunc(STATUS_SUCCESS);
return 0;
}
static void queue_destroy_timer(struct queue_timer *t)
{
/* We MUST hold the queue cs while calling this function. */
t->destroy = TRUE;
if (t->runcount == 0)
/* Ensure a timer is promptly removed. If callbacks are pending,
it will be removed after the last one finishes by the callback
cleanup wrapper. */
queue_remove_timer(t);
else
/* Make sure no destroyed timer masks an active timer at the head
of the sorted list. */
queue_move_timer(t, EXPIRE_NEVER, FALSE);
}
/***********************************************************************
* RtlCreateTimerQueue (NTDLL.@)
*
* Creates a timer queue object and returns a handle to it.
*
* PARAMS
* NewTimerQueue [O] The newly created queue.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: Any NTSTATUS code.
*/
NTSTATUS WINAPI RtlCreateTimerQueue(PHANDLE NewTimerQueue)
{
NTSTATUS status;
struct timer_queue *q = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof *q);
if (!q)
return STATUS_NO_MEMORY;
RtlInitializeCriticalSection(&q->cs);
list_init(&q->timers);
q->quit = FALSE;
q->magic = TIMER_QUEUE_MAGIC;
status = NtCreateEvent(&q->event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
if (status != STATUS_SUCCESS)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, q);
return status;
}
status = RtlpStartThreadFunc(timer_queue_thread_proc, q, &q->thread);
if (status != STATUS_SUCCESS)
{
NtClose(q->event);
RtlFreeHeap(RtlGetProcessHeap(), 0, q);
return status;
}
NtResumeThread(q->thread, NULL);
*NewTimerQueue = q;
return STATUS_SUCCESS;
}
/***********************************************************************
* RtlDeleteTimerQueueEx (NTDLL.@)
*
* Deletes a timer queue object.
*
* PARAMS
* TimerQueue [I] The timer queue to destroy.
* CompletionEvent [I] If NULL, return immediately. If INVALID_HANDLE_VALUE,
* wait until all timers are finished firing before
* returning. Otherwise, return immediately and set the
* event when all timers are done.
*
* RETURNS
* Success: STATUS_SUCCESS if synchronous, STATUS_PENDING if not.
* Failure: Any NTSTATUS code.
*/
NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
{
struct timer_queue *q = TimerQueue;
struct queue_timer *t, *temp;
HANDLE thread;
NTSTATUS status;
if (!q || q->magic != TIMER_QUEUE_MAGIC)
return STATUS_INVALID_HANDLE;
thread = q->thread;
RtlEnterCriticalSection(&q->cs);
q->quit = TRUE;
if (list_head(&q->timers))
/* When the last timer is removed, it will signal the timer thread to
exit... */
LIST_FOR_EACH_ENTRY_SAFE(t, temp, &q->timers, struct queue_timer, entry)
queue_destroy_timer(t);
else
/* However if we have none, we must do it ourselves. */
NtSetEvent(q->event, NULL);
RtlLeaveCriticalSection(&q->cs);
if (CompletionEvent == INVALID_HANDLE_VALUE)
{
NtWaitForSingleObject(thread, FALSE, NULL);
status = STATUS_SUCCESS;
}
else
{
if (CompletionEvent)
{
DPRINT1("asynchronous return on completion event unimplemented\n");
NtWaitForSingleObject(thread, FALSE, NULL);
NtSetEvent(CompletionEvent, NULL);
}
status = STATUS_PENDING;
}
NtClose(thread);
return status;
}
static struct timer_queue *get_timer_queue(HANDLE TimerQueue)
{
static struct timer_queue *default_timer_queue;
if (TimerQueue)
return TimerQueue;
else
{
if (!default_timer_queue)
{
HANDLE q;
NTSTATUS status = RtlCreateTimerQueue(&q);
if (status == STATUS_SUCCESS)
{
PVOID p = InterlockedCompareExchangePointer(
(void **) &default_timer_queue, q, NULL);
if (p)
/* Got beat to the punch. */
RtlDeleteTimerQueueEx(q, NULL);
}
}
return default_timer_queue;
}
}
/***********************************************************************
* RtlCreateTimer (NTDLL.@)
*
* Creates a new timer associated with the given queue.
*
* PARAMS
* NewTimer [O] The newly created timer.
* TimerQueue [I] The queue to hold the timer.
* Callback [I] The callback to fire.
* Parameter [I] The argument for the callback.
* DueTime [I] The delay, in milliseconds, before first firing the
* timer.
* Period [I] The period, in milliseconds, at which to fire the timer
* after the first callback. If zero, the timer will only
* fire once. It still needs to be deleted with
* RtlDeleteTimer.
* Flags [I] Flags controlling the execution of the callback. In
* addition to the WT_* thread pool flags (see
* RtlQueueWorkItem), WT_EXECUTEINTIMERTHREAD and
* WT_EXECUTEONLYONCE are supported.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: Any NTSTATUS code.
*/
NTSTATUS WINAPI RtlCreateTimer(HANDLE TimerQueue, PHANDLE NewTimer,
WAITORTIMERCALLBACKFUNC Callback,
PVOID Parameter, DWORD DueTime, DWORD Period,
ULONG Flags)
{
NTSTATUS status;
struct queue_timer *t;
struct timer_queue *q = get_timer_queue(TimerQueue);
if (!q) return STATUS_NO_MEMORY;
if (q->magic != TIMER_QUEUE_MAGIC) return STATUS_INVALID_HANDLE;
t = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof *t);
if (!t)
return STATUS_NO_MEMORY;
t->q = q;
t->runcount = 0;
t->callback = Callback;
t->param = Parameter;
t->period = Period;
t->flags = Flags;
t->destroy = FALSE;
t->event = NULL;
status = STATUS_SUCCESS;
RtlEnterCriticalSection(&q->cs);
if (q->quit)
status = STATUS_INVALID_HANDLE;
else
queue_add_timer(t, queue_current_time() + DueTime, TRUE);
RtlLeaveCriticalSection(&q->cs);
if (status == STATUS_SUCCESS)
*NewTimer = t;
else
RtlFreeHeap(RtlGetProcessHeap(), 0, t);
return status;
}
NTSTATUS
WINAPI
RtlSetTimer(
@ -483,100 +84,6 @@ RtlSetTimer(
Flags);
}
/***********************************************************************
* RtlUpdateTimer (NTDLL.@)
*
* Changes the time at which a timer expires.
*
* PARAMS
* TimerQueue [I] The queue that holds the timer.
* Timer [I] The timer to update.
* DueTime [I] The delay, in milliseconds, before next firing the timer.
* Period [I] The period, in milliseconds, at which to fire the timer
* after the first callback. If zero, the timer will not
* refire once. It still needs to be deleted with
* RtlDeleteTimer.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: Any NTSTATUS code.
*/
NTSTATUS WINAPI RtlUpdateTimer(HANDLE TimerQueue, HANDLE Timer,
DWORD DueTime, DWORD Period)
{
struct queue_timer *t = Timer;
struct timer_queue *q = t->q;
RtlEnterCriticalSection(&q->cs);
/* Can't change a timer if it was once-only or destroyed. */
if (t->expire != EXPIRE_NEVER)
{
t->period = Period;
queue_move_timer(t, queue_current_time() + DueTime, TRUE);
}
RtlLeaveCriticalSection(&q->cs);
return STATUS_SUCCESS;
}
/***********************************************************************
* RtlDeleteTimer (NTDLL.@)
*
* Cancels a timer-queue timer.
*
* PARAMS
* TimerQueue [I] The queue that holds the timer.
* Timer [I] The timer to update.
* CompletionEvent [I] If NULL, return immediately. If INVALID_HANDLE_VALUE,
* wait until the timer is finished firing all pending
* callbacks before returning. Otherwise, return
* immediately and set the timer is done.
*
* RETURNS
* Success: STATUS_SUCCESS if the timer is done, STATUS_PENDING if not,
or if the completion event is NULL.
* Failure: Any NTSTATUS code.
*/
NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer,
HANDLE CompletionEvent)
{
struct queue_timer *t = Timer;
struct timer_queue *q;
NTSTATUS status = STATUS_PENDING;
HANDLE event = NULL;
if (!Timer)
return STATUS_INVALID_PARAMETER_1;
q = t->q;
if (CompletionEvent == INVALID_HANDLE_VALUE)
{
status = NtCreateEvent(&event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
if (status == STATUS_SUCCESS)
status = STATUS_PENDING;
}
else if (CompletionEvent)
event = CompletionEvent;
RtlEnterCriticalSection(&q->cs);
t->event = event;
if (t->runcount == 0 && event)
status = STATUS_SUCCESS;
queue_destroy_timer(t);
RtlLeaveCriticalSection(&q->cs);
if (CompletionEvent == INVALID_HANDLE_VALUE && event)
{
if (status == STATUS_PENDING)
{
NtWaitForSingleObject(event, FALSE, NULL);
status = STATUS_SUCCESS;
}
NtClose(event);
}
return status;
}
/*
* @implemented
*/

View file

@ -1,275 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Rtl user wait functions
* FILE: lib/rtl/wait.c
* PROGRAMERS:
* Alex Ionescu (alex@relsoft.net)
* Eric Kohl
* KJK::Hyperion
*/
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
typedef struct _RTLP_WAIT
{
HANDLE Object;
BOOLEAN CallbackInProgress;
HANDLE CancelEvent;
LONG DeleteCount;
HANDLE CompletionEvent;
ULONG Flags;
WAITORTIMERCALLBACKFUNC Callback;
PVOID Context;
ULONG Milliseconds;
} RTLP_WAIT, *PRTLP_WAIT;
/* PRIVATE FUNCTIONS *******************************************************/
static inline PLARGE_INTEGER get_nt_timeout( PLARGE_INTEGER pTime, ULONG timeout )
{
if (timeout == INFINITE) return NULL;
pTime->QuadPart = (ULONGLONG)timeout * -10000;
return pTime;
}
static VOID
NTAPI
Wait_thread_proc(LPVOID Arg)
{
PRTLP_WAIT Wait = (PRTLP_WAIT) Arg;
NTSTATUS Status;
BOOLEAN alertable = (Wait->Flags & WT_EXECUTEINIOTHREAD) != 0;
HANDLE handles[2] = { Wait->CancelEvent, Wait->Object };
LARGE_INTEGER timeout;
HANDLE completion_event;
// TRACE("\n");
while (TRUE)
{
Status = NtWaitForMultipleObjects( 2,
handles,
WaitAny,
alertable,
get_nt_timeout( &timeout, Wait->Milliseconds ) );
if (Status == STATUS_WAIT_1 || Status == STATUS_TIMEOUT)
{
BOOLEAN TimerOrWaitFired;
if (Status == STATUS_WAIT_1)
{
// TRACE( "object %p signaled, calling callback %p with context %p\n",
// Wait->Object, Wait->Callback,
// Wait->Context );
TimerOrWaitFired = FALSE;
}
else
{
// TRACE( "wait for object %p timed out, calling callback %p with context %p\n",
// Wait->Object, Wait->Callback,
// Wait->Context );
TimerOrWaitFired = TRUE;
}
Wait->CallbackInProgress = TRUE;
Wait->Callback( Wait->Context, TimerOrWaitFired );
Wait->CallbackInProgress = FALSE;
if (Wait->Flags & WT_EXECUTEONLYONCE)
break;
}
else if (Status != STATUS_USER_APC)
break;
}
completion_event = Wait->CompletionEvent;
if (completion_event) NtSetEvent( completion_event, NULL );
if (InterlockedIncrement( &Wait->DeleteCount ) == 2 )
{
NtClose( Wait->CancelEvent );
RtlFreeHeap( RtlGetProcessHeap(), 0, Wait );
}
}
/* FUNCTIONS ***************************************************************/
/***********************************************************************
* RtlRegisterWait
*
* Registers a wait for a handle to become signaled.
*
* PARAMS
* NewWaitObject [I] Handle to the new wait object. Use RtlDeregisterWait() to free it.
* Object [I] Object to wait to become signaled.
* Callback [I] Callback function to execute when the wait times out or the handle is signaled.
* Context [I] Context to pass to the callback function when it is executed.
* Milliseconds [I] Number of milliseconds to wait before timing out.
* Flags [I] Flags. See notes.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: Any NTSTATUS code.
*
* NOTES
* Flags can be one or more of the following:
*|WT_EXECUTEDEFAULT - Executes the work item in a non-I/O worker thread.
*|WT_EXECUTEINIOTHREAD - Executes the work item in an I/O worker thread.
*|WT_EXECUTEINPERSISTENTTHREAD - Executes the work item in a thread that is persistent.
*|WT_EXECUTELONGFUNCTION - Hints that the execution can take a long time.
*|WT_TRANSFER_IMPERSONATION - Executes the function with the current access token.
*/
NTSTATUS
NTAPI
RtlRegisterWait(PHANDLE NewWaitObject,
HANDLE Object,
WAITORTIMERCALLBACKFUNC Callback,
PVOID Context,
ULONG Milliseconds,
ULONG Flags)
{
PRTLP_WAIT Wait;
NTSTATUS Status;
//TRACE( "(%p, %p, %p, %p, %d, 0x%x)\n", NewWaitObject, Object, Callback, Context, Milliseconds, Flags );
Wait = RtlAllocateHeap( RtlGetProcessHeap(), 0, sizeof(RTLP_WAIT) );
if (!Wait)
return STATUS_NO_MEMORY;
Wait->Object = Object;
Wait->Callback = Callback;
Wait->Context = Context;
Wait->Milliseconds = Milliseconds;
Wait->Flags = Flags;
Wait->CallbackInProgress = FALSE;
Wait->DeleteCount = 0;
Wait->CompletionEvent = NULL;
Status = NtCreateEvent( &Wait->CancelEvent,
EVENT_ALL_ACCESS,
NULL,
NotificationEvent,
FALSE );
if (Status != STATUS_SUCCESS)
{
RtlFreeHeap( RtlGetProcessHeap(), 0, Wait );
return Status;
}
Flags = Flags & (WT_EXECUTEINIOTHREAD | WT_EXECUTEINPERSISTENTTHREAD |
WT_EXECUTELONGFUNCTION | WT_TRANSFER_IMPERSONATION);
Status = RtlQueueWorkItem( Wait_thread_proc,
Wait,
Flags );
if (Status != STATUS_SUCCESS)
{
NtClose( Wait->CancelEvent );
RtlFreeHeap( RtlGetProcessHeap(), 0, Wait );
return Status;
}
*NewWaitObject = Wait;
return Status;
}
/***********************************************************************
* RtlDeregisterWaitEx
*
* Cancels a wait operation and frees the resources associated with calling
* RtlRegisterWait().
*
* PARAMS
* WaitObject [I] Handle to the wait object to free.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: Any NTSTATUS code.
*/
NTSTATUS
NTAPI
RtlDeregisterWaitEx(HANDLE WaitHandle,
HANDLE CompletionEvent)
{
PRTLP_WAIT Wait = (PRTLP_WAIT) WaitHandle;
NTSTATUS Status = STATUS_SUCCESS;
//TRACE( "(%p)\n", WaitHandle );
NtSetEvent( Wait->CancelEvent, NULL );
if (Wait->CallbackInProgress)
{
if (CompletionEvent != NULL)
{
if (CompletionEvent == INVALID_HANDLE_VALUE)
{
Status = NtCreateEvent( &CompletionEvent,
EVENT_ALL_ACCESS,
NULL,
NotificationEvent,
FALSE );
if (Status != STATUS_SUCCESS)
return Status;
(void)InterlockedExchangePointer( &Wait->CompletionEvent, CompletionEvent );
if (Wait->CallbackInProgress)
NtWaitForSingleObject( CompletionEvent, FALSE, NULL );
NtClose( CompletionEvent );
}
else
{
(void)InterlockedExchangePointer( &Wait->CompletionEvent, CompletionEvent );
if (Wait->CallbackInProgress)
Status = STATUS_PENDING;
}
}
else
Status = STATUS_PENDING;
}
if (InterlockedIncrement( &Wait->DeleteCount ) == 2 )
{
Status = STATUS_SUCCESS;
NtClose( Wait->CancelEvent );
RtlFreeHeap( RtlGetProcessHeap(), 0, Wait );
}
return Status;
}
/***********************************************************************
* RtlDeregisterWait
*
* Cancels a wait operation and frees the resources associated with calling
* RtlRegisterWait().
*
* PARAMS
* WaitObject [I] Handle to the wait object to free.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: Any NTSTATUS code.
*/
NTSTATUS
NTAPI
RtlDeregisterWait(HANDLE WaitHandle)
{
return RtlDeregisterWaitEx(WaitHandle, NULL);
}
/* EOF */