Author: jimtabor Date: Sat Mar 29 01:41:30 2008 New Revision: 32779
URL: http://svn.reactos.org/svn/reactos?rev=32779&view=rev Log: Phase 2: - Implement RtlRegisterWait and RtlDeregisterWait/Ex. Move the function to new file wait.c. Ported from Wine source. - Completely untested. - good luck!
Added: trunk/reactos/lib/rtl/wait.c - copied, changed from r32778, trunk/reactos/lib/rtl/thread.c Modified: trunk/reactos/lib/rtl/rtl.rbuild trunk/reactos/lib/rtl/thread.c
Modified: trunk/reactos/lib/rtl/rtl.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/rtl.rbuild?rev=3277... ============================================================================== --- trunk/reactos/lib/rtl/rtl.rbuild [iso-8859-1] (original) +++ trunk/reactos/lib/rtl/rtl.rbuild [iso-8859-1] Sat Mar 29 01:41:30 2008 @@ -91,6 +91,7 @@ <file>unicodeprefix.c</file> <file>vectoreh.c</file> <file>version.c</file> + <file>wait.c</file> <file>workitem.c</file> <pch>rtl.h</pch> </module>
Modified: trunk/reactos/lib/rtl/thread.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/thread.c?rev=32779&... ============================================================================== --- trunk/reactos/lib/rtl/thread.c [iso-8859-1] (original) +++ trunk/reactos/lib/rtl/thread.c [iso-8859-1] Sat Mar 29 01:41:30 2008 @@ -275,82 +275,4 @@ }
-/*********************************************************************** - * 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) -{ - return STATUS_SUCCESS; -} - -/*********************************************************************** - * 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) -{ - return STATUS_SUCCESS; -} - -/*********************************************************************** - * 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 */
Copied: trunk/reactos/lib/rtl/wait.c (from r32778, trunk/reactos/lib/rtl/thread.c) URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/wait.c?p2=trunk/rea... ============================================================================== --- trunk/reactos/lib/rtl/thread.c [iso-8859-1] (original) +++ trunk/reactos/lib/rtl/wait.c [iso-8859-1] Sat Mar 29 01:41:30 2008 @@ -1,8 +1,8 @@ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries - * PURPOSE: Rtl user thread functions - * FILE: lib/rtl/thread.c + * PURPOSE: Rtl user wait functions + * FILE: lib/rtl/wait.c * PROGRAMERS: * Alex Ionescu (alex@relsoft.net) * Eric Kohl @@ -16,263 +16,90 @@ #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 *******************************************************/
-NTSTATUS +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 -RtlpCreateUserStack(IN HANDLE hProcess, - IN SIZE_T StackReserve OPTIONAL, - IN SIZE_T StackCommit OPTIONAL, - IN ULONG StackZeroBits OPTIONAL, - OUT PINITIAL_TEB InitialTeb) -{ +Wait_thread_proc(LPVOID Arg) +{ + PRTLP_WAIT Wait = (PRTLP_WAIT) Arg; NTSTATUS Status; - SYSTEM_BASIC_INFORMATION SystemBasicInfo; - PIMAGE_NT_HEADERS Headers; - ULONG_PTR Stack = 0; - BOOLEAN UseGuard = FALSE; - ULONG Dummy, GuardPageSize; - - /* Get some memory information */ - Status = ZwQuerySystemInformation(SystemBasicInformation, - &SystemBasicInfo, - sizeof(SYSTEM_BASIC_INFORMATION), - NULL); - if (!NT_SUCCESS(Status)) return Status; - - /* Use the Image Settings if we are dealing with the current Process */ - if (hProcess == NtCurrentProcess()) - { - /* Get the Image Headers */ - Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); - - /* If we didn't get the parameters, find them ourselves */ - if (!StackReserve) StackReserve = Headers->OptionalHeader. - SizeOfStackReserve; - if (!StackCommit) StackCommit = Headers->OptionalHeader. - SizeOfStackCommit; - } - else - { - /* Use the System Settings if needed */ - if (!StackReserve) StackReserve = SystemBasicInfo.AllocationGranularity; - if (!StackCommit) StackCommit = SystemBasicInfo.PageSize; - } - - /* Align everything to Page Size */ - StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity); - StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize); - - // FIXME: Remove once Guard Page support is here - #if 1 - StackCommit = StackReserve; - #endif - - /* Reserve memory for the stack */ - Status = ZwAllocateVirtualMemory(hProcess, - (PVOID*)&Stack, - StackZeroBits, - &StackReserve, - MEM_RESERVE, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) return Status; - - /* Now set up some basic Initial TEB Parameters */ - InitialTeb->PreviousStackBase = NULL; - InitialTeb->PreviousStackLimit = NULL; - InitialTeb->AllocatedStackBase = (PVOID)Stack; - InitialTeb->StackBase = (PVOID)(Stack + StackReserve); - - /* Update the Stack Position */ - Stack += StackReserve - StackCommit; - - /* Check if we will need a guard page */ - if (StackReserve > StackCommit) - { - /* Remove a page to set as guard page */ - Stack -= SystemBasicInfo.PageSize; - StackCommit += SystemBasicInfo.PageSize; - UseGuard = TRUE; - } - - /* Allocate memory for the stack */ - Status = ZwAllocateVirtualMemory(hProcess, - (PVOID*)&Stack, - 0, - &StackCommit, - MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) return Status; - - /* Now set the current Stack Limit */ - InitialTeb->StackLimit = (PVOID)Stack; - - /* Create a guard page */ - if (UseGuard) - { - /* Attempt maximum space possible */ - GuardPageSize = SystemBasicInfo.PageSize; - Status = ZwProtectVirtualMemory(hProcess, - (PVOID*)&Stack, - &GuardPageSize, - PAGE_GUARD | PAGE_READWRITE, - &Dummy); - if (!NT_SUCCESS(Status)) return Status; - - /* Update the Stack Limit keeping in mind the Guard Page */ - InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit - - GuardPageSize); - } - - /* We are done! */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -RtlpFreeUserStack(IN HANDLE Process, - IN PINITIAL_TEB InitialTeb) -{ - SIZE_T Dummy = 0; - NTSTATUS Status; - - /* Free the Stack */ - Status = ZwFreeVirtualMemory(Process, - &InitialTeb->AllocatedStackBase, - &Dummy, - MEM_RELEASE); - - /* Clear the initial TEB */ - RtlZeroMemory(InitialTeb, sizeof(INITIAL_TEB)); - return Status; -} + BOOLEAN alertable = (Wait->Flags & WT_EXECUTEINIOTHREAD) ? TRUE : FALSE; + HANDLE handles[2] = { Wait->Object, Wait->CancelEvent }; + LARGE_INTEGER timeout; + HANDLE completion_event; + +// TRACE("\n"); + + while (TRUE) + { + Status = NtWaitForMultipleObjects( 2, + handles, + FALSE, + alertable, + get_nt_timeout( &timeout, Wait->Milliseconds ) ); + + if (Status == STATUS_WAIT_0 || Status == STATUS_TIMEOUT) + { + BOOLEAN TimerOrWaitFired; + + if (Status == STATUS_WAIT_0) + { + // 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 + 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 ***************************************************************/ - -/* - @implemented -*/ -NTSTATUS -NTAPI -RtlCreateUserThread(IN HANDLE ProcessHandle, - IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, - IN BOOLEAN CreateSuspended, - IN ULONG StackZeroBits OPTIONAL, - IN SIZE_T StackReserve OPTIONAL, - IN SIZE_T StackCommit OPTIONAL, - IN PTHREAD_START_ROUTINE StartAddress, - IN PVOID Parameter OPTIONAL, - OUT PHANDLE ThreadHandle OPTIONAL, - OUT PCLIENT_ID ClientId OPTIONAL) -{ - NTSTATUS Status; - HANDLE Handle; - CLIENT_ID ThreadCid; - INITIAL_TEB InitialTeb; - OBJECT_ATTRIBUTES ObjectAttributes; - CONTEXT Context; - - /* First, we'll create the Stack */ - Status = RtlpCreateUserStack(ProcessHandle, - StackReserve, - StackCommit, - StackZeroBits, - &InitialTeb); - if (!NT_SUCCESS(Status)) return Status; - - /* Next, we'll set up the Initial Context */ - RtlInitializeContext(ProcessHandle, - &Context, - Parameter, - StartAddress, - InitialTeb.StackBase); - - /* We are now ready to create the Kernel Thread Object */ - InitializeObjectAttributes(&ObjectAttributes, - NULL, - 0, - NULL, - SecurityDescriptor); - Status = ZwCreateThread(&Handle, - THREAD_ALL_ACCESS, - &ObjectAttributes, - ProcessHandle, - &ThreadCid, - &Context, - &InitialTeb, - CreateSuspended); - if (!NT_SUCCESS(Status)) - { - /* Free the stack */ - RtlpFreeUserStack(ProcessHandle, &InitialTeb); - } - else - { - /* Return thread data */ - if (ThreadHandle) *ThreadHandle = Handle; - if (ClientId) *ClientId = ThreadCid; - } - - /* Return success or the previous failure */ - return Status; -} - -/* - * @implemented - */ -VOID -NTAPI -RtlExitUserThread(NTSTATUS Status) -{ - /* Call the Loader and tell him to notify the DLLs */ - LdrShutdownThread(); - - /* Shut us down */ - NtCurrentTeb()->FreeStackOnTermination = TRUE; - NtTerminateThread(NtCurrentThread(), Status); -} - -/* - @implemented -*/ -VOID -NTAPI -RtlFreeUserThreadStack(HANDLE ProcessHandle, - HANDLE ThreadHandle) -{ - NTSTATUS Status; - THREAD_BASIC_INFORMATION ThreadBasicInfo; - SIZE_T Dummy, Size = 0; - PVOID StackLocation; - - /* Query the Basic Info */ - Status = NtQueryInformationThread(ThreadHandle, - ThreadBasicInformation, - &ThreadBasicInfo, - sizeof(THREAD_BASIC_INFORMATION), - NULL); - if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return; - - /* Get the deallocation stack */ - Status = NtReadVirtualMemory(ProcessHandle, - &((PTEB)ThreadBasicInfo.TebBaseAddress)-> - DeallocationStack, - &StackLocation, - sizeof(PVOID), - &Dummy); - if (!NT_SUCCESS(Status) || !StackLocation) return; - - /* Free it */ - NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE); -} - -PTEB -NTAPI -_NtCurrentTeb(VOID) -{ - /* Return the TEB */ - return NtCurrentTeb(); -}
/*********************************************************************** @@ -309,7 +136,49 @@ ULONG Milliseconds, ULONG Flags) { - return STATUS_SUCCESS; + 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, + TRUE, + FALSE ); + + if (Status != STATUS_SUCCESS) + { + RtlFreeHeap( RtlGetProcessHeap(), 0, Wait ); + return Status; + } + + Status = RtlQueueWorkItem( Wait_thread_proc, + Wait, + Flags & ~WT_EXECUTEONLYONCE ); + + if (Status != STATUS_SUCCESS) + { + NtClose( Wait->CancelEvent ); + RtlFreeHeap( RtlGetProcessHeap(), 0, Wait ); + return Status; + } + + *NewWaitObject = Wait; + return Status; }
/*********************************************************************** @@ -330,7 +199,54 @@ RtlDeregisterWaitEx(HANDLE WaitHandle, HANDLE CompletionEvent) { - return STATUS_SUCCESS; + 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, + TRUE, + 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; }
/***********************************************************************