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
) != 0;
48 HANDLE handles
[2] = { Wait
->CancelEvent
, Wait
->Object
};
49 LARGE_INTEGER timeout
;
50 HANDLE completion_event
;
56 Status
= NtWaitForMultipleObjects( 2,
60 get_nt_timeout( &timeout
, Wait
->Milliseconds
) );
62 if (Status
== STATUS_WAIT_1
|| Status
== STATUS_TIMEOUT
)
64 BOOLEAN TimerOrWaitFired
;
66 if (Status
== STATUS_WAIT_1
)
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
)
87 else if (Status
!= STATUS_USER_APC
)
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 Flags
= Flags
& (WT_EXECUTEINIOTHREAD
| WT_EXECUTEINPERSISTENTTHREAD
|
170 WT_EXECUTELONGFUNCTION
| WT_TRANSFER_IMPERSONATION
);
172 Status
= RtlQueueWorkItem( Wait_thread_proc
,
176 if (Status
!= STATUS_SUCCESS
)
178 NtClose( Wait
->CancelEvent
);
179 RtlFreeHeap( RtlGetProcessHeap(), 0, Wait
);
183 *NewWaitObject
= Wait
;
187 /***********************************************************************
188 * RtlDeregisterWaitEx
190 * Cancels a wait operation and frees the resources associated with calling
194 * WaitObject [I] Handle to the wait object to free.
197 * Success: STATUS_SUCCESS.
198 * Failure: Any NTSTATUS code.
202 RtlDeregisterWaitEx(HANDLE WaitHandle
,
203 HANDLE CompletionEvent
)
205 PRTLP_WAIT Wait
= (PRTLP_WAIT
) WaitHandle
;
206 NTSTATUS Status
= STATUS_SUCCESS
;
208 //TRACE( "(%p)\n", WaitHandle );
210 NtSetEvent( Wait
->CancelEvent
, NULL
);
211 if (Wait
->CallbackInProgress
)
213 if (CompletionEvent
!= NULL
)
215 if (CompletionEvent
== INVALID_HANDLE_VALUE
)
217 Status
= NtCreateEvent( &CompletionEvent
,
223 if (Status
!= STATUS_SUCCESS
)
226 (void)InterlockedExchangePointer( &Wait
->CompletionEvent
, CompletionEvent
);
228 if (Wait
->CallbackInProgress
)
229 NtWaitForSingleObject( CompletionEvent
, FALSE
, NULL
);
231 NtClose( CompletionEvent
);
235 (void)InterlockedExchangePointer( &Wait
->CompletionEvent
, CompletionEvent
);
237 if (Wait
->CallbackInProgress
)
238 Status
= STATUS_PENDING
;
242 Status
= STATUS_PENDING
;
245 if (InterlockedIncrement( &Wait
->DeleteCount
) == 2 )
247 Status
= STATUS_SUCCESS
;
248 NtClose( Wait
->CancelEvent
);
249 RtlFreeHeap( RtlGetProcessHeap(), 0, Wait
);
255 /***********************************************************************
258 * Cancels a wait operation and frees the resources associated with calling
262 * WaitObject [I] Handle to the wait object to free.
265 * Success: STATUS_SUCCESS.
266 * Failure: Any NTSTATUS code.
270 RtlDeregisterWait(HANDLE WaitHandle
)
272 return RtlDeregisterWaitEx(WaitHandle
, NULL
);