2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Rtl user wait functions
7 * Alex Ionescu (alex@relsoft.net)
12 /* INCLUDES *****************************************************************/
19 typedef struct _RTLP_WAIT
22 BOOLEAN CallbackInProgress
;
25 HANDLE CompletionEvent
;
27 WAITORTIMERCALLBACKFUNC Callback
;
30 } RTLP_WAIT
, *PRTLP_WAIT
;
32 /* PRIVATE FUNCTIONS *******************************************************/
34 static inline PLARGE_INTEGER
get_nt_timeout( PLARGE_INTEGER pTime
, ULONG timeout
)
36 if (timeout
== INFINITE
) return NULL
;
37 pTime
->QuadPart
= (ULONGLONG
)timeout
* -10000;
43 Wait_thread_proc(LPVOID Arg
)
45 PRTLP_WAIT Wait
= (PRTLP_WAIT
) Arg
;
47 BOOLEAN alertable
= (Wait
->Flags
& WT_EXECUTEINIOTHREAD
) ? TRUE
: FALSE
;
48 HANDLE handles
[2] = { Wait
->Object
, Wait
->CancelEvent
};
49 LARGE_INTEGER timeout
;
50 HANDLE completion_event
;
56 Status
= NtWaitForMultipleObjects( 2,
60 get_nt_timeout( &timeout
, Wait
->Milliseconds
) );
62 if (Status
== STATUS_WAIT_0
|| Status
== STATUS_TIMEOUT
)
64 BOOLEAN TimerOrWaitFired
;
66 if (Status
== STATUS_WAIT_0
)
68 // TRACE( "object %p signaled, calling callback %p with context %p\n",
69 // Wait->Object, Wait->Callback,
71 TimerOrWaitFired
= FALSE
;
75 // TRACE( "wait for object %p timed out, calling callback %p with context %p\n",
76 // Wait->Object, Wait->Callback,
78 TimerOrWaitFired
= TRUE
;
80 Wait
->CallbackInProgress
= TRUE
;
81 Wait
->Callback( Wait
->Context
, TimerOrWaitFired
);
82 Wait
->CallbackInProgress
= FALSE
;
84 if (Wait
->Flags
& WT_EXECUTEONLYONCE
)
91 completion_event
= Wait
->CompletionEvent
;
92 if (completion_event
) NtSetEvent( completion_event
, NULL
);
94 if (InterlockedIncrement( &Wait
->DeleteCount
) == 2 )
96 NtClose( Wait
->CancelEvent
);
97 RtlFreeHeap( RtlGetProcessHeap(), 0, Wait
);
102 /* FUNCTIONS ***************************************************************/
105 /***********************************************************************
108 * Registers a wait for a handle to become signaled.
111 * NewWaitObject [I] Handle to the new wait object. Use RtlDeregisterWait() to free it.
112 * Object [I] Object to wait to become signaled.
113 * Callback [I] Callback function to execute when the wait times out or the handle is signaled.
114 * Context [I] Context to pass to the callback function when it is executed.
115 * Milliseconds [I] Number of milliseconds to wait before timing out.
116 * Flags [I] Flags. See notes.
119 * Success: STATUS_SUCCESS.
120 * Failure: Any NTSTATUS code.
123 * Flags can be one or more of the following:
124 *|WT_EXECUTEDEFAULT - Executes the work item in a non-I/O worker thread.
125 *|WT_EXECUTEINIOTHREAD - Executes the work item in an I/O worker thread.
126 *|WT_EXECUTEINPERSISTENTTHREAD - Executes the work item in a thread that is persistent.
127 *|WT_EXECUTELONGFUNCTION - Hints that the execution can take a long time.
128 *|WT_TRANSFER_IMPERSONATION - Executes the function with the current access token.
132 RtlRegisterWait(PHANDLE NewWaitObject
,
134 WAITORTIMERCALLBACKFUNC Callback
,
142 //TRACE( "(%p, %p, %p, %p, %d, 0x%x)\n", NewWaitObject, Object, Callback, Context, Milliseconds, Flags );
144 Wait
= RtlAllocateHeap( RtlGetProcessHeap(), 0, sizeof(RTLP_WAIT
) );
146 return STATUS_NO_MEMORY
;
148 Wait
->Object
= Object
;
149 Wait
->Callback
= Callback
;
150 Wait
->Context
= Context
;
151 Wait
->Milliseconds
= Milliseconds
;
153 Wait
->CallbackInProgress
= FALSE
;
154 Wait
->DeleteCount
= 0;
155 Wait
->CompletionEvent
= NULL
;
157 Status
= NtCreateEvent( &Wait
->CancelEvent
,
163 if (Status
!= STATUS_SUCCESS
)
165 RtlFreeHeap( RtlGetProcessHeap(), 0, Wait
);
169 Status
= RtlQueueWorkItem( Wait_thread_proc
,
171 Flags
& ~WT_EXECUTEONLYONCE
);
173 if (Status
!= STATUS_SUCCESS
)
175 NtClose( Wait
->CancelEvent
);
176 RtlFreeHeap( RtlGetProcessHeap(), 0, Wait
);
180 *NewWaitObject
= Wait
;
184 /***********************************************************************
185 * RtlDeregisterWaitEx
187 * Cancels a wait operation and frees the resources associated with calling
191 * WaitObject [I] Handle to the wait object to free.
194 * Success: STATUS_SUCCESS.
195 * Failure: Any NTSTATUS code.
199 RtlDeregisterWaitEx(HANDLE WaitHandle
,
200 HANDLE CompletionEvent
)
202 PRTLP_WAIT Wait
= (PRTLP_WAIT
) WaitHandle
;
203 NTSTATUS Status
= STATUS_SUCCESS
;
205 //TRACE( "(%p)\n", WaitHandle );
207 NtSetEvent( Wait
->CancelEvent
, NULL
);
208 if (Wait
->CallbackInProgress
)
210 if (CompletionEvent
!= NULL
)
212 if (CompletionEvent
== INVALID_HANDLE_VALUE
)
214 Status
= NtCreateEvent( &CompletionEvent
,
220 if (Status
!= STATUS_SUCCESS
)
223 (void)InterlockedExchangePointer( &Wait
->CompletionEvent
, CompletionEvent
);
225 if (Wait
->CallbackInProgress
)
226 NtWaitForSingleObject( CompletionEvent
, FALSE
, NULL
);
228 NtClose( CompletionEvent
);
232 (void)InterlockedExchangePointer( &Wait
->CompletionEvent
, CompletionEvent
);
234 if (Wait
->CallbackInProgress
)
235 Status
= STATUS_PENDING
;
239 Status
= STATUS_PENDING
;
242 if (InterlockedIncrement( &Wait
->DeleteCount
) == 2 )
244 Status
= STATUS_SUCCESS
;
245 NtClose( Wait
->CancelEvent
);
246 RtlFreeHeap( RtlGetProcessHeap(), 0, Wait
);
252 /***********************************************************************
255 * Cancels a wait operation and frees the resources associated with calling
259 * WaitObject [I] Handle to the wait object to free.
262 * Success: STATUS_SUCCESS.
263 * Failure: Any NTSTATUS code.
267 RtlDeregisterWait(HANDLE WaitHandle
)
269 return RtlDeregisterWaitEx(WaitHandle
, NULL
);