mirror of
https://github.com/reactos/reactos.git
synced 2025-06-11 18:58:28 +00:00
[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:
parent
88a63011ea
commit
0bf42067d2
15 changed files with 249 additions and 842 deletions
|
@ -1311,45 +1311,47 @@
|
||||||
@ stub -version=0x600+ ShipAssertMsgA
|
@ stub -version=0x600+ ShipAssertMsgA
|
||||||
@ stub -version=0x600+ ShipAssertMsgW
|
@ stub -version=0x600+ ShipAssertMsgW
|
||||||
@ stub -version=0x600+ TpAllocAlpcCompletion
|
@ stub -version=0x600+ TpAllocAlpcCompletion
|
||||||
@ stub -version=0x600+ TpAllocCleanupGroup
|
@ stdcall -version=0x600+ TpAllocCleanupGroup(ptr)
|
||||||
@ stub -version=0x600+ TpAllocIoCompletion
|
@ stdcall -version=0x600+ TpAllocIoCompletion(ptr ptr ptr ptr ptr)
|
||||||
@ stub -version=0x600+ TpAllocPool
|
@ stdcall -version=0x600+ TpAllocPool(ptr ptr)
|
||||||
@ stub -version=0x600+ TpAllocTimer
|
@ stdcall -version=0x600+ TpAllocTimer(ptr ptr ptr ptr)
|
||||||
@ stub -version=0x600+ TpAllocWait
|
@ stdcall -version=0x600+ TpAllocWait(ptr ptr ptr ptr)
|
||||||
@ stub -version=0x600+ TpAllocWork
|
@ stdcall -version=0x600+ TpAllocWork(ptr ptr ptr ptr)
|
||||||
@ stub -version=0x600+ TpCallbackLeaveCriticalSectionOnCompletion
|
@ stdcall -version=0x600+ TpCallbackLeaveCriticalSectionOnCompletion(ptr ptr)
|
||||||
@ stub -version=0x600+ TpCallbackMayRunLong
|
@ stdcall -version=0x600+ TpCallbackMayRunLong(ptr)
|
||||||
@ stub -version=0x600+ TpCallbackReleaseMutexOnCompletion
|
@ stdcall -version=0x600+ TpCallbackReleaseMutexOnCompletion(ptr ptr)
|
||||||
@ stub -version=0x600+ TpCallbackReleaseSemaphoreOnCompletion
|
@ stdcall -version=0x600+ TpCallbackReleaseSemaphoreOnCompletion(ptr ptr long)
|
||||||
@ stub -version=0x600+ TpCallbackSetEventOnCompletion
|
@ stdcall -version=0x600+ TpCallbackSetEventOnCompletion(ptr ptr)
|
||||||
@ stub -version=0x600+ TpCallbackUnloadDllOnCompletion
|
@ stdcall -version=0x600+ TpCallbackUnloadDllOnCompletion(ptr ptr)
|
||||||
@ stub -version=0x600+ TpCancelAsyncIoOperation
|
@ stdcall -version=0x600+ TpCancelAsyncIoOperation(ptr)
|
||||||
@ stub -version=0x600+ TpCaptureCaller
|
@ stub -version=0x600+ TpCaptureCaller
|
||||||
@ stub -version=0x600+ TpCheckTerminateWorker
|
@ stub -version=0x600+ TpCheckTerminateWorker
|
||||||
@ stub -version=0x600+ TpDbgDumpHeapUsage
|
@ stub -version=0x600+ TpDbgDumpHeapUsage
|
||||||
@ stub -version=0x600+ TpDbgSetLogRoutine
|
@ stub -version=0x600+ TpDbgSetLogRoutine
|
||||||
@ stub -version=0x600+ TpDisassociateCallback
|
@ stdcall -version=0x600+ TpDisassociateCallback(ptr)
|
||||||
@ stub -version=0x600+ TpIsTimerSet
|
@ stdcall -version=0x600+ TpIsTimerSet(ptr)
|
||||||
@ stub -version=0x600+ TpPostWork
|
@ stdcall -version=0x600+ TpPostWork(ptr)
|
||||||
|
@ stdcall -version=0x600+ TpQueryPoolStackInformation(ptr ptr)
|
||||||
@ stub -version=0x600+ TpReleaseAlpcCompletion
|
@ stub -version=0x600+ TpReleaseAlpcCompletion
|
||||||
@ stub -version=0x600+ TpReleaseCleanupGroup
|
@ stdcall -version=0x600+ TpReleaseCleanupGroup(ptr)
|
||||||
@ stub -version=0x600+ TpReleaseCleanupGroupMembers
|
@ stdcall -version=0x600+ TpReleaseCleanupGroupMembers(ptr long ptr)
|
||||||
@ stub -version=0x600+ TpReleaseIoCompletion
|
@ stdcall -version=0x600+ TpReleaseIoCompletion(ptr)
|
||||||
@ stub -version=0x600+ TpReleasePool
|
@ stdcall -version=0x600+ TpReleasePool(ptr)
|
||||||
@ stub -version=0x600+ TpReleaseTimer
|
@ stdcall -version=0x600+ TpReleaseTimer(ptr)
|
||||||
@ stub -version=0x600+ TpReleaseWait
|
@ stdcall -version=0x600+ TpReleaseWait(ptr)
|
||||||
@ stub -version=0x600+ TpReleaseWork
|
@ stdcall -version=0x600+ TpReleaseWork(ptr)
|
||||||
@ stub -version=0x600+ TpSetPoolMaxThreads
|
@ stdcall -version=0x600+ TpSetPoolMaxThreads(ptr long)
|
||||||
@ stub -version=0x600+ TpSetPoolMinThreads
|
@ stdcall -version=0x600+ TpSetPoolMinThreads(ptr long)
|
||||||
@ stub -version=0x600+ TpSetTimer
|
@ stdcall -version=0x600+ TpSetPoolStackInformation(ptr ptr)
|
||||||
@ stub -version=0x600+ TpSetWait
|
@ stdcall -version=0x600+ TpSetTimer(ptr ptr long long)
|
||||||
@ stub -version=0x600+ TpSimpleTryPost
|
@ stdcall -version=0x600+ TpSetWait(ptr long ptr)
|
||||||
@ stub -version=0x600+ TpStartAsyncIoOperation
|
@ stdcall -version=0x600+ TpSimpleTryPost(ptr ptr ptr)
|
||||||
|
@ stdcall -version=0x600+ TpStartAsyncIoOperation(ptr)
|
||||||
@ stub -version=0x600+ TpWaitForAlpcCompletion
|
@ stub -version=0x600+ TpWaitForAlpcCompletion
|
||||||
@ stub -version=0x600+ TpWaitForIoCompletion
|
@ stdcall -version=0x600+ TpWaitForIoCompletion(ptr long)
|
||||||
@ stub -version=0x600+ TpWaitForTimer
|
@ stdcall -version=0x600+ TpWaitForTimer(ptr long)
|
||||||
@ stub -version=0x600+ TpWaitForWait
|
@ stdcall -version=0x600+ TpWaitForWait(ptr long)
|
||||||
@ stub -version=0x600+ TpWaitForWork
|
@ stdcall -version=0x600+ TpWaitForWork(ptr long)
|
||||||
@ stdcall -ret64 VerSetConditionMask(double long long)
|
@ stdcall -ret64 VerSetConditionMask(double long long)
|
||||||
@ stub -version=0x600+ WerCheckEventEscalation
|
@ stub -version=0x600+ WerCheckEventEscalation
|
||||||
@ stub -version=0x600+ WerReportSQMEvent
|
@ stub -version=0x600+ WerReportSQMEvent
|
||||||
|
|
|
@ -242,4 +242,9 @@ NTAPI
|
||||||
RtlpInitializeKeyedEvent(
|
RtlpInitializeKeyedEvent(
|
||||||
VOID);
|
VOID);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
RtlpInitializeThreadPooling(
|
||||||
|
VOID);
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -2415,10 +2415,10 @@ LdrpInitializeProcess(IN PCONTEXT Context,
|
||||||
/* Check whether all static imports were properly loaded and return here */
|
/* Check whether all static imports were properly loaded and return here */
|
||||||
if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
|
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 */
|
/* Initialize the keyed event for condition variables */
|
||||||
RtlpInitializeKeyedEvent();
|
RtlpInitializeKeyedEvent();
|
||||||
#endif
|
RtlpInitializeThreadPooling();
|
||||||
|
|
||||||
/* Initialize TLS */
|
/* Initialize TLS */
|
||||||
Status = LdrpInitializeTls();
|
Status = LdrpInitializeTls();
|
||||||
|
|
|
@ -13,34 +13,5 @@
|
||||||
@ stdcall RtlRunOnceComplete(ptr long ptr)
|
@ stdcall RtlRunOnceComplete(ptr long ptr)
|
||||||
@ stdcall RtlRunOnceExecuteOnce(ptr ptr ptr 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 RtlConnectToSm(ptr ptr long ptr) SmConnectToSm
|
||||||
@ stdcall RtlSendMsgToSm(ptr ptr) SmSendMsgToSm
|
@ stdcall RtlSendMsgToSm(ptr ptr) SmSendMsgToSm
|
||||||
|
|
|
@ -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/3rdparty/strmbase # Synced to WineStaging-3.3
|
||||||
|
|
||||||
sdk/lib/rtl/actctx.c # Synced to wine-5.18
|
sdk/lib/rtl/actctx.c # Partly synced with WineStaging-1.9.16
|
||||||
sdk/lib/rtl/threadpool.c # Synced with wine-9.7
|
sdk/lib/rtl/threadpool.c # Synced with Wine-9.7
|
||||||
|
|
||||||
advapi32 -
|
advapi32 -
|
||||||
dll/win32/advapi32/wine/cred.c # Synced to WineStaging-3.3
|
dll/win32/advapi32/wine/cred.c # Synced to WineStaging-3.3
|
||||||
|
|
|
@ -23,6 +23,7 @@ list(APPEND SOURCE
|
||||||
rtlstr.c
|
rtlstr.c
|
||||||
string.c
|
string.c
|
||||||
testlist.c
|
testlist.c
|
||||||
|
threadpool.c
|
||||||
time.c)
|
time.c)
|
||||||
|
|
||||||
if(ARCH STREQUAL "i386")
|
if(ARCH STREQUAL "i386")
|
||||||
|
|
|
@ -23,6 +23,7 @@ extern void func_rtl(void);
|
||||||
extern void func_rtlbitmap(void);
|
extern void func_rtlbitmap(void);
|
||||||
extern void func_rtlstr(void);
|
extern void func_rtlstr(void);
|
||||||
extern void func_string(void);
|
extern void func_string(void);
|
||||||
|
extern void func_threadpool(void);
|
||||||
extern void func_time(void);
|
extern void func_time(void);
|
||||||
|
|
||||||
const struct test winetest_testlist[] =
|
const struct test winetest_testlist[] =
|
||||||
|
@ -49,6 +50,7 @@ const struct test winetest_testlist[] =
|
||||||
{ "rtlbitmap", func_rtlbitmap },
|
{ "rtlbitmap", func_rtlbitmap },
|
||||||
{ "rtlstr", func_rtlstr },
|
{ "rtlstr", func_rtlstr },
|
||||||
{ "string", func_string },
|
{ "string", func_string },
|
||||||
|
{ "threadpool", func_threadpool},
|
||||||
{ "time", func_time },
|
{ "time", func_time },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
|
|
||||||
#include "ntdll_test.h"
|
#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 *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
|
||||||
static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *);
|
static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *);
|
||||||
static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
|
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 );
|
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
|
||||||
TP_POOL_STACK_INFORMATION stack_info;
|
TP_POOL_STACK_INFORMATION stack_info;
|
||||||
TP_CALLBACK_ENVIRON environment;
|
TP_CALLBACK_ENVIRON environment;
|
||||||
|
#ifndef __REACTOS__
|
||||||
TP_CALLBACK_ENVIRON_V3 environment3;
|
TP_CALLBACK_ENVIRON_V3 environment3;
|
||||||
|
#endif
|
||||||
TP_CLEANUP_GROUP *group;
|
TP_CLEANUP_GROUP *group;
|
||||||
HANDLE semaphore;
|
HANDLE semaphore;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
@ -616,6 +622,7 @@ static void test_tp_simple(void)
|
||||||
result = WaitForSingleObject(semaphore, 1000);
|
result = WaitForSingleObject(semaphore, 1000);
|
||||||
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
|
ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
|
||||||
|
|
||||||
|
#ifndef __REACTOS__ // Windows 7
|
||||||
/* test with environment version 3 */
|
/* test with environment version 3 */
|
||||||
memset(&environment3, 0, sizeof(environment3));
|
memset(&environment3, 0, sizeof(environment3));
|
||||||
environment3.Version = 3;
|
environment3.Version = 3;
|
||||||
|
@ -635,6 +642,7 @@ static void test_tp_simple(void)
|
||||||
status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
|
status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
|
||||||
ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */,
|
ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */,
|
||||||
"TpSimpleTryPost failed with status %lx\n", status);
|
"TpSimpleTryPost failed with status %lx\n", status);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* test with invalid version number */
|
/* test with invalid version number */
|
||||||
memset(&environment, 0, sizeof(environment));
|
memset(&environment, 0, sizeof(environment));
|
||||||
|
@ -2031,7 +2039,11 @@ static DWORD WINAPI io_wait_thread(void *arg)
|
||||||
static void test_tp_io(void)
|
static void test_tp_io(void)
|
||||||
{
|
{
|
||||||
TP_CALLBACK_ENVIRON environment = {.Version = 1};
|
TP_CALLBACK_ENVIRON environment = {.Version = 1};
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
OVERLAPPED ovl = {0}, ovl2 = {0};
|
||||||
|
#else
|
||||||
OVERLAPPED ovl = {}, ovl2 = {};
|
OVERLAPPED ovl = {}, ovl2 = {};
|
||||||
|
#endif
|
||||||
HANDLE client, server, thread;
|
HANDLE client, server, thread;
|
||||||
struct io_cb_ctx userdata;
|
struct io_cb_ctx userdata;
|
||||||
char in[1], in2[1];
|
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)
|
static void test_kernel32_tp_io(void)
|
||||||
{
|
{
|
||||||
TP_CALLBACK_ENVIRON environment = {.Version = 1};
|
TP_CALLBACK_ENVIRON environment = {.Version = 1};
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
OVERLAPPED ovl = {0}, ovl2 = {0};
|
||||||
|
#else
|
||||||
OVERLAPPED ovl = {}, ovl2 = {};
|
OVERLAPPED ovl = {}, ovl2 = {};
|
||||||
|
#endif
|
||||||
HANDLE client, server, thread;
|
HANDLE client, server, thread;
|
||||||
struct io_cb_ctx userdata;
|
struct io_cb_ctx userdata;
|
||||||
char in[1], in2[1];
|
char in[1], in2[1];
|
||||||
|
|
|
@ -4748,24 +4748,29 @@ RtlSleepConditionVariableSRW(
|
||||||
//
|
//
|
||||||
// Synchronization functions
|
// Synchronization functions
|
||||||
//
|
//
|
||||||
|
NTSYSAPI
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlInitializeConditionVariable(OUT PRTL_CONDITION_VARIABLE ConditionVariable);
|
RtlInitializeConditionVariable(OUT PRTL_CONDITION_VARIABLE ConditionVariable);
|
||||||
|
|
||||||
|
NTSYSAPI
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlWakeConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable);
|
RtlWakeConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable);
|
||||||
|
|
||||||
|
NTSYSAPI
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlWakeAllConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable);
|
RtlWakeAllConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable);
|
||||||
|
|
||||||
|
NTSYSAPI
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlSleepConditionVariableCS(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable,
|
RtlSleepConditionVariableCS(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable,
|
||||||
IN OUT PRTL_CRITICAL_SECTION CriticalSection,
|
IN OUT PRTL_CRITICAL_SECTION CriticalSection,
|
||||||
IN const PLARGE_INTEGER TimeOut OPTIONAL);
|
IN const PLARGE_INTEGER TimeOut OPTIONAL);
|
||||||
|
|
||||||
|
NTSYSAPI
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlSleepConditionVariableSRW(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable,
|
RtlSleepConditionVariableSRW(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable,
|
||||||
|
|
|
@ -4495,6 +4495,12 @@ typedef enum _TP_CALLBACK_PRIORITY {
|
||||||
TP_CALLBACK_PRIORITY_COUNT = TP_CALLBACK_PRIORITY_INVALID
|
TP_CALLBACK_PRIORITY_COUNT = TP_CALLBACK_PRIORITY_INVALID
|
||||||
} TP_CALLBACK_PRIORITY;
|
} 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
|
typedef VOID
|
||||||
(NTAPI *PTP_WORK_CALLBACK)(
|
(NTAPI *PTP_WORK_CALLBACK)(
|
||||||
_Inout_ PTP_CALLBACK_INSTANCE Instance,
|
_Inout_ PTP_CALLBACK_INSTANCE Instance,
|
||||||
|
|
|
@ -8,13 +8,19 @@ add_definitions(
|
||||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||||
# Enable this again. CORE-17637
|
# Enable this again. CORE-17637
|
||||||
add_compile_options(-Wunused-result)
|
add_compile_options(-Wunused-result)
|
||||||
|
|
||||||
|
add_compile_options(-Wno-incompatible-pointer-types)
|
||||||
|
add_compile_options(-Wno-missing-braces)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
|
||||||
|
|
||||||
list(APPEND RTL_WINE_SOURCE
|
list(APPEND RTL_WINE_SOURCE
|
||||||
actctx.c
|
actctx.c
|
||||||
timerqueue.c
|
timerqueue.c
|
||||||
wait.c
|
threadpool.c
|
||||||
)
|
)
|
||||||
|
set_source_files_properties(threadpool.c PROPERTIES COMPILE_DEFINITIONS __WINESRC__)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# Silence warning C4267: 'initializing': conversion from 'size_t' to 'const int', possible loss of data
|
# 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
|
condvar.c
|
||||||
runonce.c
|
runonce.c
|
||||||
srw.c
|
srw.c
|
||||||
threadpool.c
|
|
||||||
utf8.c)
|
utf8.c)
|
||||||
|
|
||||||
add_library(rtl_vista ${SOURCE_VISTA})
|
add_library(rtl_vista ${SOURCE_VISTA})
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
|
|
||||||
/* Use intrinsics for x86 and x64 */
|
/* Use intrinsics for x86 and x64 */
|
||||||
#if defined(_M_IX86) || defined(_M_AMD64)
|
#if defined(_M_IX86) || defined(_M_AMD64)
|
||||||
|
#ifndef InterlockedCompareExchange
|
||||||
#define InterlockedCompareExchange _InterlockedCompareExchange
|
#define InterlockedCompareExchange _InterlockedCompareExchange
|
||||||
#define InterlockedIncrement _InterlockedIncrement
|
#define InterlockedIncrement _InterlockedIncrement
|
||||||
#define InterlockedDecrement _InterlockedDecrement
|
#define InterlockedDecrement _InterlockedDecrement
|
||||||
|
@ -64,5 +65,6 @@
|
||||||
#define InterlockedBitTestAndSet _interlockedbittestandset
|
#define InterlockedBitTestAndSet _interlockedbittestandset
|
||||||
#define InterlockedBitTestAndSet64 _interlockedbittestandset64
|
#define InterlockedBitTestAndSet64 _interlockedbittestandset64
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* RTL_H */
|
#endif /* RTL_H */
|
||||||
|
|
|
@ -19,6 +19,42 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
* 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 <assert.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -33,6 +69,7 @@
|
||||||
#include "ntdll_misc.h"
|
#include "ntdll_misc.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(threadpool);
|
WINE_DEFAULT_DEBUG_CHANNEL(threadpool);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Old thread pooling API
|
* Old thread pooling API
|
||||||
|
@ -47,7 +84,9 @@ struct rtl_work_item
|
||||||
#define EXPIRE_NEVER (~(ULONGLONG)0)
|
#define EXPIRE_NEVER (~(ULONGLONG)0)
|
||||||
#define TIMER_QUEUE_MAGIC 0x516d6954 /* TimQ */
|
#define TIMER_QUEUE_MAGIC 0x516d6954 /* TimQ */
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug;
|
static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug;
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
|
@ -57,15 +96,21 @@ static struct
|
||||||
old_threadpool =
|
old_threadpool =
|
||||||
{
|
{
|
||||||
NULL, /* compl_port */
|
NULL, /* compl_port */
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
{0}, /* threadpool_compl_cs */
|
||||||
|
#else
|
||||||
{ &critsect_compl_debug, -1, 0, 0, 0, 0 }, /* threadpool_compl_cs */
|
{ &critsect_compl_debug, -1, 0, 0, 0, 0 }, /* threadpool_compl_cs */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug =
|
static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug =
|
||||||
{
|
{
|
||||||
0, 0, &old_threadpool.threadpool_compl_cs,
|
0, 0, &old_threadpool.threadpool_compl_cs,
|
||||||
{ &critsect_compl_debug.ProcessLocksList, &critsect_compl_debug.ProcessLocksList },
|
{ &critsect_compl_debug.ProcessLocksList, &critsect_compl_debug.ProcessLocksList },
|
||||||
0, 0, { (DWORD_PTR)(__FILE__ ": threadpool_compl_cs") }
|
0, 0, { (DWORD_PTR)(__FILE__ ": threadpool_compl_cs") }
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct timer_queue;
|
struct timer_queue;
|
||||||
struct queue_timer
|
struct queue_timer
|
||||||
|
@ -235,8 +280,10 @@ struct threadpool_group
|
||||||
struct list members;
|
struct list members;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
/* global timerqueue object */
|
/* global timerqueue object */
|
||||||
static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug;
|
static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug;
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
|
@ -248,13 +295,22 @@ static struct
|
||||||
}
|
}
|
||||||
timerqueue =
|
timerqueue =
|
||||||
{
|
{
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
{0}, /* cs */
|
||||||
|
#else
|
||||||
{ &timerqueue_debug, -1, 0, 0, 0, 0 }, /* cs */
|
{ &timerqueue_debug, -1, 0, 0, 0, 0 }, /* cs */
|
||||||
|
#endif
|
||||||
0, /* objcount */
|
0, /* objcount */
|
||||||
FALSE, /* thread_running */
|
FALSE, /* thread_running */
|
||||||
LIST_INIT( timerqueue.pending_timers ), /* pending_timers */
|
LIST_INIT( timerqueue.pending_timers ), /* pending_timers */
|
||||||
|
#if __REACTOS__
|
||||||
|
0,
|
||||||
|
#else
|
||||||
RTL_CONDITION_VARIABLE_INIT /* update_event */
|
RTL_CONDITION_VARIABLE_INIT /* update_event */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug =
|
static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug =
|
||||||
{
|
{
|
||||||
0, 0, &timerqueue.cs,
|
0, 0, &timerqueue.cs,
|
||||||
|
@ -264,6 +320,7 @@ static RTL_CRITICAL_SECTION_DEBUG timerqueue_debug =
|
||||||
|
|
||||||
/* global waitqueue object */
|
/* global waitqueue object */
|
||||||
static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug;
|
static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug;
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
|
@ -273,17 +330,23 @@ static struct
|
||||||
}
|
}
|
||||||
waitqueue =
|
waitqueue =
|
||||||
{
|
{
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
{0}, /* cs */
|
||||||
|
#else
|
||||||
{ &waitqueue_debug, -1, 0, 0, 0, 0 }, /* cs */
|
{ &waitqueue_debug, -1, 0, 0, 0, 0 }, /* cs */
|
||||||
|
#endif
|
||||||
0, /* num_buckets */
|
0, /* num_buckets */
|
||||||
LIST_INIT( waitqueue.buckets ) /* buckets */
|
LIST_INIT( waitqueue.buckets ) /* buckets */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug =
|
static RTL_CRITICAL_SECTION_DEBUG waitqueue_debug =
|
||||||
{
|
{
|
||||||
0, 0, &waitqueue.cs,
|
0, 0, &waitqueue.cs,
|
||||||
{ &waitqueue_debug.ProcessLocksList, &waitqueue_debug.ProcessLocksList },
|
{ &waitqueue_debug.ProcessLocksList, &waitqueue_debug.ProcessLocksList },
|
||||||
0, 0, { (DWORD_PTR)(__FILE__ ": waitqueue.cs") }
|
0, 0, { (DWORD_PTR)(__FILE__ ": waitqueue.cs") }
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct waitqueue_bucket
|
struct waitqueue_bucket
|
||||||
{
|
{
|
||||||
|
@ -295,8 +358,10 @@ struct waitqueue_bucket
|
||||||
BOOL alertable;
|
BOOL alertable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
/* global I/O completion queue object */
|
/* global I/O completion queue object */
|
||||||
static RTL_CRITICAL_SECTION_DEBUG ioqueue_debug;
|
static RTL_CRITICAL_SECTION_DEBUG ioqueue_debug;
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
|
@ -308,15 +373,21 @@ static struct
|
||||||
}
|
}
|
||||||
ioqueue =
|
ioqueue =
|
||||||
{
|
{
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
.cs = {0},
|
||||||
|
#else
|
||||||
.cs = { &ioqueue_debug, -1, 0, 0, 0, 0 },
|
.cs = { &ioqueue_debug, -1, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
static RTL_CRITICAL_SECTION_DEBUG ioqueue_debug =
|
static RTL_CRITICAL_SECTION_DEBUG ioqueue_debug =
|
||||||
{
|
{
|
||||||
0, 0, &ioqueue.cs,
|
0, 0, &ioqueue.cs,
|
||||||
{ &ioqueue_debug.ProcessLocksList, &ioqueue_debug.ProcessLocksList },
|
{ &ioqueue_debug.ProcessLocksList, &ioqueue_debug.ProcessLocksList },
|
||||||
0, 0, { (DWORD_PTR)(__FILE__ ": ioqueue.cs") }
|
0, 0, { (DWORD_PTR)(__FILE__ ": ioqueue.cs") }
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline struct threadpool *impl_from_TP_POOL( TP_POOL *pool )
|
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;
|
return (struct threadpool_instance *)instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
ULONG NTAPI threadpool_worker_proc(PVOID param );
|
||||||
|
#else
|
||||||
static void CALLBACK threadpool_worker_proc( void *param );
|
static void CALLBACK threadpool_worker_proc( void *param );
|
||||||
|
#endif
|
||||||
static void tp_object_submit( struct threadpool_object *object, BOOL signaled );
|
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_execute( struct threadpool_object *object, BOOL wait_thread );
|
||||||
static void tp_object_prepare_shutdown( struct threadpool_object *object );
|
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)
|
static void set_thread_name(const WCHAR *name)
|
||||||
{
|
{
|
||||||
|
#ifndef __REACTOS__ // This is impossible on non vista+
|
||||||
THREAD_NAME_INFORMATION info;
|
THREAD_NAME_INFORMATION info;
|
||||||
|
|
||||||
RtlInitUnicodeString(&info.ThreadName, name);
|
RtlInitUnicodeString(&info.ThreadName, name);
|
||||||
NtSetInformationThread(GetCurrentThread(), ThreadNameInformation, &info, sizeof(info));
|
NtSetInformationThread(GetCurrentThread(), ThreadNameInformation, &info, sizeof(info));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
static void CALLBACK process_rtl_work_item( TP_CALLBACK_INSTANCE *instance, void *userdata )
|
static void CALLBACK process_rtl_work_item( TP_CALLBACK_INSTANCE *instance, void *userdata )
|
||||||
{
|
{
|
||||||
struct rtl_work_item *item = userdata;
|
struct rtl_work_item *item = userdata;
|
||||||
|
@ -472,7 +550,11 @@ static DWORD CALLBACK iocp_poller(LPVOID Arg)
|
||||||
PRTL_OVERLAPPED_COMPLETION_ROUTINE callback;
|
PRTL_OVERLAPPED_COMPLETION_ROUTINE callback;
|
||||||
LPVOID overlapped;
|
LPVOID overlapped;
|
||||||
IO_STATUS_BLOCK iosb;
|
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 );
|
NTSTATUS res = NtRemoveIoCompletion( cport, (PULONG_PTR)&callback, (PULONG_PTR)&overlapped, &iosb, NULL );
|
||||||
|
#endif
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
ERR("NtRemoveIoCompletion failed: 0x%lx\n", 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 );
|
return NtSetInformationFile( FileHandle, &iosb, &info, sizeof(info), FileCompletionInformation );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline PLARGE_INTEGER get_nt_timeout( PLARGE_INTEGER pTime, ULONG timeout )
|
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;
|
return pTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************** Timer Queue Impl **************************/
|
/************************** Timer Queue Impl **************************/
|
||||||
|
|
||||||
static void queue_remove_timer(struct queue_timer *t)
|
static void queue_remove_timer(struct queue_timer *t)
|
||||||
|
@ -705,7 +787,11 @@ static ULONG queue_get_timeout(struct timer_queue *q)
|
||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
ULONG NTAPI timer_queue_thread_proc(PVOID p)
|
||||||
|
#else
|
||||||
static void WINAPI timer_queue_thread_proc(LPVOID p)
|
static void WINAPI timer_queue_thread_proc(LPVOID p)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct timer_queue *q = p;
|
struct timer_queue *q = p;
|
||||||
ULONG timeout_ms;
|
ULONG timeout_ms;
|
||||||
|
@ -746,6 +832,9 @@ static void WINAPI timer_queue_thread_proc(LPVOID p)
|
||||||
q->magic = 0;
|
q->magic = 0;
|
||||||
RtlFreeHeap(GetProcessHeap(), 0, q);
|
RtlFreeHeap(GetProcessHeap(), 0, q);
|
||||||
RtlExitUserThread( 0 );
|
RtlExitUserThread( 0 );
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void queue_destroy_timer(struct queue_timer *t)
|
static void queue_destroy_timer(struct queue_timer *t)
|
||||||
|
@ -1052,7 +1141,11 @@ NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer,
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* timerqueue_thread_proc (internal)
|
* timerqueue_thread_proc (internal)
|
||||||
*/
|
*/
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
ULONG NTAPI timerqueue_thread_proc(PVOID param )
|
||||||
|
#else
|
||||||
static void CALLBACK timerqueue_thread_proc( void *param )
|
static void CALLBACK timerqueue_thread_proc( void *param )
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
ULONGLONG timeout_lower, timeout_upper, new_timeout;
|
ULONGLONG timeout_lower, timeout_upper, new_timeout;
|
||||||
struct threadpool_object *other_timer;
|
struct threadpool_object *other_timer;
|
||||||
|
@ -1139,6 +1232,9 @@ static void CALLBACK timerqueue_thread_proc( void *param )
|
||||||
|
|
||||||
TRACE( "terminating timer queue thread\n" );
|
TRACE( "terminating timer queue thread\n" );
|
||||||
RtlExitUserThread( 0 );
|
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)
|
* waitqueue_thread_proc (internal)
|
||||||
*/
|
*/
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
void NTAPI waitqueue_thread_proc(PVOID param )
|
||||||
|
#else
|
||||||
static void CALLBACK waitqueue_thread_proc( void *param )
|
static void CALLBACK waitqueue_thread_proc( void *param )
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct threadpool_object *objects[MAXIMUM_WAITQUEUE_OBJECTS];
|
struct threadpool_object *objects[MAXIMUM_WAITQUEUE_OBJECTS];
|
||||||
HANDLE handles[MAXIMUM_WAITQUEUE_OBJECTS + 1];
|
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,
|
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)
|
if (status == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
list_add_tail( &waitqueue.buckets, &bucket->bucket_entry );
|
list_add_tail( &waitqueue.buckets, &bucket->bucket_entry );
|
||||||
|
@ -1512,12 +1612,20 @@ static void tp_waitqueue_unlock( struct threadpool_object *wait )
|
||||||
RtlLeaveCriticalSection( &waitqueue.cs );
|
RtlLeaveCriticalSection( &waitqueue.cs );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
ULONG NTAPI ioqueue_thread_proc(PVOID param )
|
||||||
|
#else
|
||||||
static void CALLBACK ioqueue_thread_proc( void *param )
|
static void CALLBACK ioqueue_thread_proc( void *param )
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct io_completion *completion;
|
struct io_completion *completion;
|
||||||
struct threadpool_object *io;
|
struct threadpool_object *io;
|
||||||
IO_STATUS_BLOCK iosb;
|
IO_STATUS_BLOCK iosb;
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
PVOID key, value;
|
||||||
|
#else
|
||||||
ULONG_PTR key, value;
|
ULONG_PTR key, value;
|
||||||
|
#endif
|
||||||
BOOL destroy, skip;
|
BOOL destroy, skip;
|
||||||
NTSTATUS status;
|
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 = &io->u.io.completions[io->u.io.completion_count++];
|
||||||
completion->iosb = iosb;
|
completion->iosb = iosb;
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
completion->cvalue = (ULONG_PTR)value;
|
||||||
|
#else
|
||||||
completion->cvalue = value;
|
completion->cvalue = value;
|
||||||
|
#endif
|
||||||
|
|
||||||
tp_object_submit( io, FALSE );
|
tp_object_submit( io, FALSE );
|
||||||
}
|
}
|
||||||
|
@ -1606,6 +1718,10 @@ static void CALLBACK ioqueue_thread_proc( void *param )
|
||||||
TRACE( "terminating I/O completion thread\n" );
|
TRACE( "terminating I/O completion thread\n" );
|
||||||
|
|
||||||
RtlExitUserThread( 0 );
|
RtlExitUserThread( 0 );
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS tp_ioqueue_lock( struct threadpool_object *io, HANDLE file )
|
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;
|
FILE_COMPLETION_INFORMATION info;
|
||||||
IO_STATUS_BLOCK iosb;
|
IO_STATUS_BLOCK iosb;
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
info.Port = ioqueue.port;
|
||||||
|
info.Key = io;
|
||||||
|
#else
|
||||||
info.CompletionPort = ioqueue.port;
|
info.CompletionPort = ioqueue.port;
|
||||||
info.CompletionKey = (ULONG_PTR)io;
|
info.CompletionKey = (ULONG_PTR)io;
|
||||||
|
#endif
|
||||||
|
|
||||||
status = NtSetInformationFile( file, &iosb, &info, sizeof(info), FileCompletionInformation );
|
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 )
|
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 );
|
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
|
||||||
|
#endif
|
||||||
struct threadpool *pool;
|
struct threadpool *pool;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -1675,8 +1800,13 @@ static NTSTATUS tp_threadpool_alloc( struct threadpool **out )
|
||||||
pool->objcount = 0;
|
pool->objcount = 0;
|
||||||
pool->shutdown = FALSE;
|
pool->shutdown = FALSE;
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
RtlInitializeCriticalSection( &pool->cs );
|
||||||
|
#else
|
||||||
RtlInitializeCriticalSectionEx( &pool->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
|
RtlInitializeCriticalSectionEx( &pool->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
|
||||||
|
|
||||||
pool->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool.cs");
|
pool->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool.cs");
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(pool->pools); ++i)
|
for (i = 0; i < ARRAY_SIZE(pool->pools); ++i)
|
||||||
list_init( &pool->pools[i] );
|
list_init( &pool->pools[i] );
|
||||||
|
@ -1728,8 +1858,9 @@ static BOOL tp_threadpool_release( struct threadpool *pool )
|
||||||
assert( !pool->objcount );
|
assert( !pool->objcount );
|
||||||
for (i = 0; i < ARRAY_SIZE(pool->pools); ++i)
|
for (i = 0; i < ARRAY_SIZE(pool->pools); ++i)
|
||||||
assert( list_empty( &pool->pools[i] ) );
|
assert( list_empty( &pool->pools[i] ) );
|
||||||
|
#ifndef __REACTOS__
|
||||||
pool->cs.DebugInfo->Spare[0] = 0;
|
pool->cs.DebugInfo->Spare[0] = 0;
|
||||||
|
#endif
|
||||||
RtlDeleteCriticalSection( &pool->cs );
|
RtlDeleteCriticalSection( &pool->cs );
|
||||||
|
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, pool );
|
RtlFreeHeap( GetProcessHeap(), 0, pool );
|
||||||
|
@ -1750,6 +1881,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON
|
||||||
|
|
||||||
if (environment)
|
if (environment)
|
||||||
{
|
{
|
||||||
|
#ifndef __REACTOS__ //Windows 7 stuff
|
||||||
/* Validate environment parameters. */
|
/* Validate environment parameters. */
|
||||||
if (environment->Version == 3)
|
if (environment->Version == 3)
|
||||||
{
|
{
|
||||||
|
@ -1765,7 +1897,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
pool = (struct threadpool *)environment->Pool;
|
pool = (struct threadpool *)environment->Pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1786,7 +1918,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON
|
||||||
|
|
||||||
pool = default_threadpool;
|
pool = default_threadpool;
|
||||||
}
|
}
|
||||||
|
|
||||||
RtlEnterCriticalSection( &pool->cs );
|
RtlEnterCriticalSection( &pool->cs );
|
||||||
|
|
||||||
/* Make sure that the threadpool has at least one thread. */
|
/* 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->refcount = 1;
|
||||||
group->shutdown = FALSE;
|
group->shutdown = FALSE;
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
RtlInitializeCriticalSection( &group->cs );
|
||||||
|
#else
|
||||||
RtlInitializeCriticalSectionEx( &group->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
|
RtlInitializeCriticalSectionEx( &group->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
|
||||||
|
|
||||||
group->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool_group.cs");
|
group->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threadpool_group.cs");
|
||||||
|
#endif
|
||||||
|
|
||||||
list_init( &group->members );
|
list_init( &group->members );
|
||||||
|
|
||||||
|
@ -1875,7 +2012,9 @@ static BOOL tp_group_release( struct threadpool_group *group )
|
||||||
assert( group->shutdown );
|
assert( group->shutdown );
|
||||||
assert( list_empty( &group->members ) );
|
assert( list_empty( &group->members ) );
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
group->cs.DebugInfo->Spare[0] = 0;
|
group->cs.DebugInfo->Spare[0] = 0;
|
||||||
|
#endif
|
||||||
RtlDeleteCriticalSection( &group->cs );
|
RtlDeleteCriticalSection( &group->cs );
|
||||||
|
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, group );
|
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->finalization_callback = environment->FinalizationCallback;
|
||||||
object->may_run_long = environment->u.s.LongFunction != 0;
|
object->may_run_long = environment->u.s.LongFunction != 0;
|
||||||
object->race_dll = environment->RaceDll;
|
object->race_dll = environment->RaceDll;
|
||||||
|
#ifndef __REACTOS__ //Windows 7 stuff
|
||||||
if (environment->Version == 3)
|
if (environment->Version == 3)
|
||||||
{
|
{
|
||||||
TP_CALLBACK_ENVIRON_V3 *environment_v3 = (TP_CALLBACK_ENVIRON_V3 *)environment;
|
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;
|
object->priority = environment_v3->CallbackPriority;
|
||||||
assert( object->priority < ARRAY_SIZE(pool->pools) );
|
assert( object->priority < ARRAY_SIZE(pool->pools) );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (environment->ActivationContext)
|
if (environment->ActivationContext)
|
||||||
FIXME( "activation context not supported yet\n" );
|
FIXME( "activation context not supported yet\n" );
|
||||||
|
|
||||||
|
@ -2328,7 +2468,11 @@ skip_cleanup:
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* threadpool_worker_proc (internal)
|
* threadpool_worker_proc (internal)
|
||||||
*/
|
*/
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
ULONG NTAPI threadpool_worker_proc(PVOID param )
|
||||||
|
#else
|
||||||
static void CALLBACK threadpool_worker_proc( void *param )
|
static void CALLBACK threadpool_worker_proc( void *param )
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct threadpool *pool = param;
|
struct threadpool *pool = param;
|
||||||
LARGE_INTEGER timeout;
|
LARGE_INTEGER timeout;
|
||||||
|
@ -2382,6 +2526,9 @@ static void CALLBACK threadpool_worker_proc( void *param )
|
||||||
TRACE( "terminating worker thread for pool %p\n", pool );
|
TRACE( "terminating worker thread for pool %p\n", pool );
|
||||||
tp_threadpool_release( pool );
|
tp_threadpool_release( pool );
|
||||||
RtlExitUserThread( 0 );
|
RtlExitUserThread( 0 );
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -3355,3 +3502,16 @@ NTSTATUS WINAPI RtlDeregisterWait(HANDLE WaitHandle)
|
||||||
{
|
{
|
||||||
return RtlDeregisterWaitEx(WaitHandle, NULL);
|
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
|
||||||
|
|
|
@ -64,405 +64,6 @@ struct timer_queue
|
||||||
#define EXPIRE_NEVER (~(ULONGLONG) 0)
|
#define EXPIRE_NEVER (~(ULONGLONG) 0)
|
||||||
#define TIMER_QUEUE_MAGIC 0x516d6954 /* TimQ */
|
#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
|
NTSTATUS
|
||||||
WINAPI
|
WINAPI
|
||||||
RtlSetTimer(
|
RtlSetTimer(
|
||||||
|
@ -483,100 +84,6 @@ RtlSetTimer(
|
||||||
Flags);
|
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
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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 */
|
|
Loading…
Add table
Add a link
Reference in a new issue