Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276/* * 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 VOIDNTAPIWait_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. */NTSTATUSNTAPIRtlRegisterWait(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. */NTSTATUSNTAPIRtlDeregisterWaitEx(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. */NTSTATUSNTAPIRtlDeregisterWait(HANDLE WaitHandle){ return RtlDeregisterWaitEx(WaitHandle, NULL);}
/* EOF */