2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/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
, HEAP_ZERO_MEMORY
, 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
->WaitList
.Flink
= NULL
;
79 WaitBlock
->WaitList
.Blink
= NULL
;
81 /* Copy the message */
82 RtlCopyMemory(&WaitBlock
->WaitApiMessage
,
84 WaitApiMessage
->Header
.u1
.s1
.TotalLength
);
86 /* Return the block */
87 *NewWaitBlock
= WaitBlock
;
92 * @name CsrNotifyWaitBlock
94 * The CsrNotifyWaitBlock routine calls the wait function for a registered
95 * CSR Wait Block, and replies to the attached CSR API Message, if any.
98 * Pointer to the CSR Wait Block.
101 * Pointer to the wait list for this wait.
103 * @param WaitArgument[1-2]
104 * User-defined values to pass to the wait function.
107 * Wait flags for this wait.
109 * @param DereferenceThread
110 * Specifies whether the CSR Thread should be dereferenced at the
113 * @return TRUE in case of success, FALSE otherwise.
115 * @remarks After a wait block is notified, the wait function becomes invalid.
120 CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock
,
121 IN PLIST_ENTRY WaitList
,
122 IN PVOID WaitArgument1
,
123 IN PVOID WaitArgument2
,
125 IN BOOLEAN DereferenceThread
)
127 /* Call the wait function */
128 if (WaitBlock
->WaitFunction(WaitList
,
129 WaitBlock
->WaitThread
,
130 &WaitBlock
->WaitApiMessage
,
131 WaitBlock
->WaitContext
,
136 /* The wait is done, clear the block */
137 WaitBlock
->WaitThread
->WaitBlock
= NULL
;
139 /* Check for captured arguments */
140 if (WaitBlock
->WaitApiMessage
.CsrCaptureData
)
143 CsrReleaseCapturedArguments(&WaitBlock
->WaitApiMessage
);
146 /* Reply to the port */
147 NtReplyPort(WaitBlock
->WaitThread
->Process
->ClientPort
,
148 &WaitBlock
->WaitApiMessage
.Header
);
150 /* Check if we should dereference the thread */
151 if (DereferenceThread
)
153 /* Remove it from the Wait List */
154 if (WaitBlock
->WaitList
.Flink
)
156 RemoveEntryList(&WaitBlock
->WaitList
);
159 /* Dereference the thread */
160 CsrDereferenceThread(WaitBlock
->WaitThread
);
162 /* Free the wait block */
163 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
167 /* The wait is complete, but the thread is being kept alive */
168 WaitBlock
->WaitFunction
= NULL
;
171 /* The wait succeeded */
175 /* The wait failed */
179 /* PUBLIC FUNCTIONS ***********************************************************/
182 * @name CsrCreateWait
185 * The CsrCreateWait routine creates a CSR Wait.
188 * Pointer to a wait list in which the wait will be added.
190 * @param WaitFunction
191 * Pointer to the function that will handle this wait.
193 * @param CsrWaitThread
194 * Pointer to the CSR Thread that will perform the wait.
196 * @param WaitApiMessage
197 * Pointer to the CSR API Message associated to this wait.
200 * Pointer to a user-defined parameter associated to this wait.
202 * @return TRUE in case of success, FALSE otherwise.
209 CsrCreateWait(IN PLIST_ENTRY WaitList
,
210 IN CSR_WAIT_FUNCTION WaitFunction
,
211 IN PCSR_THREAD CsrWaitThread
,
212 IN OUT PCSR_API_MESSAGE WaitApiMessage
,
213 IN PVOID WaitContext
)
215 PCSR_WAIT_BLOCK WaitBlock
;
217 /* Initialize the wait */
218 if (!CsrInitializeWait(WaitFunction
,
227 /* Acquire the Wait Lock */
228 CsrAcquireWaitLock();
230 /* Make sure the thread wasn't destroyed */
231 if (CsrWaitThread
->Flags
& CsrThreadTerminated
)
234 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
235 CsrReleaseWaitLock();
239 /* Associate the newly created wait to the waiting thread */
240 CsrWaitThread
->WaitBlock
= WaitBlock
;
242 /* Insert the wait in the queue */
243 InsertTailList(WaitList
, &WaitBlock
->WaitList
);
246 CsrReleaseWaitLock();
251 * @name CsrDereferenceWait
254 * The CsrDereferenceWait routine dereferences a CSR Wait Block.
257 * Pointer to the Wait List associated to the wait.
266 CsrDereferenceWait(IN PLIST_ENTRY WaitList
)
268 PLIST_ENTRY NextEntry
;
269 PCSR_WAIT_BLOCK WaitBlock
;
271 /* Acquire the Process and Wait Locks */
272 CsrAcquireProcessLock();
273 CsrAcquireWaitLock();
275 /* Set the list pointers */
276 NextEntry
= WaitList
->Flink
;
279 while (NextEntry
!= WaitList
)
281 /* Get the wait block */
282 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
284 /* Move to the next entry */
285 NextEntry
= NextEntry
->Flink
;
287 /* Check if there's no Wait Routine (satisfied wait) */
288 if (WaitBlock
->WaitFunction
== NULL
)
290 /* Remove it from the Wait List */
291 if (WaitBlock
->WaitList
.Flink
)
293 RemoveEntryList(&WaitBlock
->WaitList
);
296 /* Dereference the thread waiting on it */
297 CsrDereferenceThread(WaitBlock
->WaitThread
);
300 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
304 /* Release the locks */
305 CsrReleaseWaitLock();
306 CsrReleaseProcessLock();
310 * @name CsrMoveSatisfiedWait
313 * The CsrMoveSatisfiedWait routine moves satisfied waits from
314 * a wait list to another list.
316 * @param DestinationList
317 * Pointer to a list in which the satisfied waits will be added.
320 * Pointer to the wait list whose satisfied wait blocks
321 * will be moved away.
330 CsrMoveSatisfiedWait(IN PLIST_ENTRY DestinationList
,
331 IN PLIST_ENTRY WaitList
)
333 PLIST_ENTRY NextEntry
;
334 PCSR_WAIT_BLOCK WaitBlock
;
336 /* Acquire the Wait Lock */
337 CsrAcquireWaitLock();
339 /* Set the List pointers */
340 NextEntry
= WaitList
->Flink
;
343 while (NextEntry
!= WaitList
)
345 /* Get the Wait block */
346 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
348 /* Go to the next entry */
349 NextEntry
= NextEntry
->Flink
;
351 /* Check if there's no Wait Routine (satisfied wait) */
352 if (WaitBlock
->WaitFunction
== NULL
)
354 /* Remove it from the Wait Block Queue */
355 RemoveEntryList(&WaitBlock
->WaitList
);
357 /* Insert the wait into the destination list */
358 InsertTailList(DestinationList
, &WaitBlock
->WaitList
);
362 /* Release the wait lock */
363 CsrReleaseWaitLock();
367 * @name CsrNotifyWait
370 * The CsrNotifyWait routine notifies CSR Wait Blocks.
373 * Pointer to the wait list whose wait blocks will be notified.
376 * Type of the wait to perform, either WaitAny or WaitAll.
378 * @param WaitArgument[1-2]
379 * User-defined argument to pass on to the wait function.
381 * @return TRUE in case of success, FALSE otherwise.
388 CsrNotifyWait(IN PLIST_ENTRY WaitList
,
390 IN PVOID WaitArgument1
,
391 IN PVOID WaitArgument2
)
393 PLIST_ENTRY NextEntry
;
394 PCSR_WAIT_BLOCK WaitBlock
;
395 BOOLEAN NotifySuccess
= FALSE
;
397 /* Acquire the Wait Lock */
398 CsrAcquireWaitLock();
400 /* Set the List pointers */
401 NextEntry
= WaitList
->Flink
;
404 while (NextEntry
!= WaitList
)
406 /* Get the Wait block */
407 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
409 /* Go to the next entry */
410 NextEntry
= NextEntry
->Flink
;
412 /* Check if there is a Wait Routine */
413 if (WaitBlock
->WaitFunction
!= NULL
)
415 /* Notify the Waiter */
416 NotifySuccess
|= CsrNotifyWaitBlock(WaitBlock
,
423 /* We've already done a wait, so leave unless this is a Wait All */
424 if (WaitType
!= WaitAll
) break;
428 /* Release the wait lock and return */
429 CsrReleaseWaitLock();
430 return NotifySuccess
;