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=327…
==============================================================================
--- 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/re…
==============================================================================
--- 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(a)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;
}
/***********************************************************************