2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsystems/win32/csrss/csrsrv/wait.c
5 * PURPOSE: CSR Server DLL Wait Implementation
6 * PROGRAMMERS: Emanuele Aliberti
7 * Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES ******************************************************************/
17 /* DATA **********************************************************************/
19 RTL_CRITICAL_SECTION CsrWaitListsLock
;
21 /* PRIVATE FUNCTIONS *********************************************************/
24 * @name CsrInitializeWait
26 * The CsrInitializeWait routine initializes a CSR Wait Object.
29 * Pointer to the function that will handle this wait.
31 * @param CsrWaitThread
32 * Pointer to the CSR Thread that will perform the wait.
34 * @param WaitApiMessage
35 * Pointer to the CSR API Message associated to this wait.
38 * Pointer to a user-defined parameter associated to this wait.
41 * Pointed to the initialized CSR Wait Block for this wait.
43 * @return TRUE in case of success, FALSE otherwise.
50 CsrInitializeWait(IN CSR_WAIT_FUNCTION WaitFunction
,
51 IN PCSR_THREAD CsrWaitThread
,
52 IN OUT PCSR_API_MESSAGE WaitApiMessage
,
54 OUT PCSR_WAIT_BLOCK
*NewWaitBlock
)
57 PCSR_WAIT_BLOCK WaitBlock
;
59 /* Calculate the size of the wait block */
60 Size
= sizeof(CSR_WAIT_BLOCK
) -
61 sizeof(WaitBlock
->WaitApiMessage
) +
62 WaitApiMessage
->Header
.u1
.s1
.TotalLength
;
64 /* Allocate the Wait Block */
65 WaitBlock
= RtlAllocateHeap(CsrHeap
, 0, Size
);
69 WaitApiMessage
->Status
= STATUS_NO_MEMORY
;
74 WaitBlock
->Size
= Size
;
75 WaitBlock
->WaitThread
= CsrWaitThread
;
76 WaitBlock
->WaitContext
= WaitContext
;
77 WaitBlock
->WaitFunction
= WaitFunction
;
78 WaitBlock
->UserWaitList
.Flink
= NULL
;
79 WaitBlock
->UserWaitList
.Blink
= NULL
;
80 WaitBlock
->WaitList
= WaitBlock
->UserWaitList
;
82 /* Copy the message */
83 RtlMoveMemory(&WaitBlock
->WaitApiMessage
,
85 WaitApiMessage
->Header
.u1
.s1
.TotalLength
);
87 /* Return the block */
88 *NewWaitBlock
= WaitBlock
;
93 * @name CsrNotifyWaitBlock
95 * The CsrNotifyWaitBlock routine calls the wait function for a registered
96 * CSR Wait Block, and replies to the attached CSR API Message, if any.
99 * Pointer to the CSR Wait Block
102 * Pointer to the wait list for this wait.
104 * @param WaitArgument[1-2]
105 * User-defined values to pass to the wait function.
108 * Wait flags for this wait.
110 * @param DereferenceThread
111 * Specifies whether the CSR Thread should be dereferenced at the
114 * @return TRUE in case of success, FALSE otherwise.
116 * @remarks After a wait block is notified, the wait function becomes invalid.
121 CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock
,
122 IN PLIST_ENTRY WaitList
,
123 IN PVOID WaitArgument1
,
124 IN PVOID WaitArgument2
,
126 IN BOOLEAN DereferenceThread
)
128 /* Call the wait function */
129 if ((WaitBlock
->WaitFunction
)(WaitList
,
130 WaitBlock
->WaitThread
,
131 &WaitBlock
->WaitApiMessage
,
132 WaitBlock
->WaitContext
,
137 /* The wait is done, clear the block */
138 WaitBlock
->WaitThread
->WaitBlock
= NULL
;
140 /* Check for captured arguments */
141 if (WaitBlock
->WaitApiMessage
.CsrCaptureData
)
144 CsrReleaseCapturedArguments(&WaitBlock
->WaitApiMessage
);
147 /* Reply to the port */
148 NtReplyPort(WaitBlock
->WaitThread
->Process
->ClientPort
,
149 (PPORT_MESSAGE
)&WaitBlock
->WaitApiMessage
);
151 /* Check if we should dereference the thread */
152 if (DereferenceThread
)
154 /* Remove it from the Wait List */
155 if (WaitBlock
->WaitList
.Flink
)
157 RemoveEntryList(&WaitBlock
->WaitList
);
160 /* Remove it from the User Wait List */
161 if (WaitBlock
->UserWaitList
.Flink
)
163 RemoveEntryList(&WaitBlock
->UserWaitList
);
166 /* Dereference teh thread */
167 CsrDereferenceThread(WaitBlock
->WaitThread
);
169 /* Free the wait block */
170 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
174 /* The wait is complete, but the thread is being kept alive */
175 WaitBlock
->WaitFunction
= NULL
;
178 /* The wait suceeded */
182 /* The wait failed */
186 /* PUBLIC FUNCTIONS **********************************************************/
189 * @name CsrCreateWait
192 * The CsrCreateWait routine creates a CSR Wait.
195 * Pointer to a list entry of the waits to associate.
197 * @param WaitFunction
198 * Pointer to the function that will handle this wait.
200 * @param CsrWaitThread
201 * Pointer to the CSR Thread that will perform the wait.
203 * @param WaitApiMessage
204 * Pointer to the CSR API Message associated to this wait.
207 * Pointer to a user-defined parameter associated to this wait.
209 * @param UserWaitList
210 * Pointer to a list entry of the user-defined waits to associate.
212 * @return TRUE in case of success, FALSE otherwise.
219 CsrCreateWait(IN PLIST_ENTRY WaitList
,
220 IN CSR_WAIT_FUNCTION WaitFunction
,
221 IN PCSR_THREAD CsrWaitThread
,
222 IN OUT PCSR_API_MESSAGE WaitApiMessage
,
223 IN PVOID WaitContext
,
224 IN PLIST_ENTRY UserWaitList OPTIONAL
)
226 PCSR_WAIT_BLOCK WaitBlock
;
228 /* Initialize the wait */
229 if (!CsrInitializeWait(WaitFunction
,
238 /* Acquire the Wait Lock */
239 CsrAcquireWaitLock();
241 /* Make sure the thread wasn't destroyed */
242 if (CsrWaitThread
->Flags
& CsrThreadTerminated
)
245 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
246 CsrReleaseWaitLock();
250 /* Insert the wait in the queue */
251 InsertTailList(WaitList
, &WaitBlock
->WaitList
);
253 /* Insert the User Wait too, if one was given */
254 if (UserWaitList
) InsertTailList(UserWaitList
, &WaitBlock
->UserWaitList
);
257 CsrReleaseWaitLock();
262 * @name CsrDereferenceWait
265 * The CsrDereferenceWait routine dereferences a CSR Wait Block.
268 * Pointer to the Wait List associated to the wait.
277 CsrDereferenceWait(IN PLIST_ENTRY WaitList
)
279 PLIST_ENTRY NextEntry
;
280 PCSR_WAIT_BLOCK WaitBlock
;
282 /* Acquire the Process and Wait Locks */
283 CsrAcquireProcessLock();
284 CsrAcquireWaitLock();
286 /* Set the list pointers */
287 NextEntry
= WaitList
->Flink
;
290 while (NextEntry
!= WaitList
)
292 /* Get the wait block */
293 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
295 /* Move to the next entry */
296 NextEntry
= NextEntry
->Flink
;
298 /* Check if there's no Wait Routine */
299 if (!WaitBlock
->WaitFunction
)
301 /* Remove it from the Wait List */
302 if (WaitBlock
->WaitList
.Flink
)
304 RemoveEntryList(&WaitBlock
->WaitList
);
307 /* Remove it from the User Wait List */
308 if (WaitBlock
->UserWaitList
.Flink
)
310 RemoveEntryList(&WaitBlock
->UserWaitList
);
313 /* Dereference the thread waiting on it */
314 CsrDereferenceThread(WaitBlock
->WaitThread
);
317 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
321 /* Release the locks */
322 CsrReleaseWaitLock();
323 CsrReleaseProcessLock();
327 * @name CsrMoveSatisfiedWait
330 * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
331 * to another list entry.
334 * Pointer to a list entry where the satisfied waits will be added.
337 * Pointer to a list entry to analyze for satisfied waits.
346 CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry
,
347 IN PLIST_ENTRY WaitList
)
349 PLIST_ENTRY NextEntry
;
350 PCSR_WAIT_BLOCK WaitBlock
;
352 /* Acquire the Wait Lock */
353 CsrAcquireWaitLock();
355 /* Set the List pointers */
356 NextEntry
= WaitList
->Flink
;
359 while (NextEntry
!= WaitList
)
361 /* Get the Wait block */
362 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
364 /* Go to the next entry */
365 NextEntry
= NextEntry
->Flink
;
367 /* Check if there is a Wait Callback */
368 if (WaitBlock
->WaitFunction
)
370 /* Remove it from the Wait Block Queue */
371 RemoveEntryList(&WaitBlock
->WaitList
);
373 /* Insert the new entry */
374 InsertTailList(&WaitBlock
->WaitList
, NewEntry
);
378 /* Release the wait lock */
379 CsrReleaseWaitLock();
383 * @name CsrNotifyWait
386 * The CsrNotifyWait notifies a CSR Wait Block.
389 * Pointer to the list entry for this wait.
392 * Type of the wait to perform, either WaitAny or WaitAll.
394 * @param WaitArgument[1-2]
395 * User-defined argument to pass on to the wait function.
397 * @return TRUE in case of success, FALSE otherwise.
404 CsrNotifyWait(IN PLIST_ENTRY WaitList
,
406 IN PVOID WaitArgument1
,
407 IN PVOID WaitArgument2
)
409 PLIST_ENTRY NextEntry
;
410 PCSR_WAIT_BLOCK WaitBlock
;
411 BOOLEAN NotifySuccess
= FALSE
;
413 /* Acquire the Wait Lock */
414 CsrAcquireWaitLock();
416 /* Set the List pointers */
417 NextEntry
= WaitList
->Flink
;
420 while (NextEntry
!= WaitList
)
422 /* Get the Wait block */
423 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
425 /* Go to the next entry */
426 NextEntry
= NextEntry
->Flink
;
428 /* Check if there is a Wait Callback */
429 if (WaitBlock
->WaitFunction
)
431 /* Notify the Waiter */
432 NotifySuccess
|= CsrNotifyWaitBlock(WaitBlock
,
439 /* We've already done a wait, so leave unless this is a Wait All */
440 if (WaitType
!= WaitAll
) break;
444 /* Release the wait lock and return */
445 CsrReleaseWaitLock();
446 return NotifySuccess
;