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 CsrWaitThread
->WaitBlock
= WaitBlock
;
77 WaitBlock
->WaitContext
= WaitContext
;
78 WaitBlock
->WaitFunction
= WaitFunction
;
79 WaitBlock
->WaitList
.Flink
= NULL
;
80 WaitBlock
->WaitList
.Blink
= NULL
;
82 /* Copy the message */
83 RtlCopyMemory(&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 /* Dereference the thread */
161 CsrDereferenceThread(WaitBlock
->WaitThread
);
163 /* Free the wait block */
164 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
168 /* The wait is complete, but the thread is being kept alive */
169 WaitBlock
->WaitFunction
= NULL
;
172 /* The wait succeeded */
176 /* The wait failed */
180 /* PUBLIC FUNCTIONS ***********************************************************/
183 * @name CsrCreateWait
186 * The CsrCreateWait routine creates a CSR Wait.
189 * Pointer to a list entry of the waits to associate.
191 * @param WaitFunction
192 * Pointer to the function that will handle this wait.
194 * @param CsrWaitThread
195 * Pointer to the CSR Thread that will perform the wait.
197 * @param WaitApiMessage
198 * Pointer to the CSR API Message associated to this wait.
201 * Pointer to a user-defined parameter associated to this wait.
203 * @return TRUE in case of success, FALSE otherwise.
210 CsrCreateWait(IN PLIST_ENTRY WaitList
,
211 IN CSR_WAIT_FUNCTION WaitFunction
,
212 IN PCSR_THREAD CsrWaitThread
,
213 IN OUT PCSR_API_MESSAGE WaitApiMessage
,
214 IN PVOID WaitContext
)
216 PCSR_WAIT_BLOCK WaitBlock
;
218 /* Initialize the wait */
219 if (!CsrInitializeWait(WaitFunction
,
228 /* Acquire the Wait Lock */
229 CsrAcquireWaitLock();
231 /* Make sure the thread wasn't destroyed */
232 if (CsrWaitThread
->Flags
& CsrThreadTerminated
)
235 CsrWaitThread
->WaitBlock
= NULL
;
236 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
237 CsrReleaseWaitLock();
241 /* Insert the wait in the queue */
242 InsertTailList(WaitList
, &WaitBlock
->WaitList
);
245 CsrReleaseWaitLock();
250 * @name CsrDereferenceWait
253 * The CsrDereferenceWait routine dereferences a CSR Wait Block.
256 * Pointer to the Wait List associated to the wait.
265 CsrDereferenceWait(IN PLIST_ENTRY WaitList
)
267 PLIST_ENTRY NextEntry
;
268 PCSR_WAIT_BLOCK WaitBlock
;
270 /* Acquire the Process and Wait Locks */
271 CsrAcquireProcessLock();
272 CsrAcquireWaitLock();
274 /* Set the list pointers */
275 NextEntry
= WaitList
->Flink
;
278 while (NextEntry
!= WaitList
)
280 /* Get the wait block */
281 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
283 /* Move to the next entry */
284 NextEntry
= NextEntry
->Flink
;
286 /* Check if there's no Wait Routine (satisfied wait) */
287 if (WaitBlock
->WaitFunction
== NULL
)
289 /* Remove it from the Wait List */
290 if (WaitBlock
->WaitList
.Flink
)
292 RemoveEntryList(&WaitBlock
->WaitList
);
295 /* Dereference the thread waiting on it */
296 CsrDereferenceThread(WaitBlock
->WaitThread
);
299 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
303 /* Release the locks */
304 CsrReleaseWaitLock();
305 CsrReleaseProcessLock();
309 * @name CsrMoveSatisfiedWait
312 * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
313 * to another list entry.
316 * Pointer to a list entry where the satisfied waits will be added.
319 * Pointer to a list entry to analyze for satisfied waits.
328 CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry
,
329 IN PLIST_ENTRY WaitList
)
331 PLIST_ENTRY NextEntry
;
332 PCSR_WAIT_BLOCK WaitBlock
;
334 /* Acquire the Wait Lock */
335 CsrAcquireWaitLock();
337 /* Set the List pointers */
338 NextEntry
= WaitList
->Flink
;
341 while (NextEntry
!= WaitList
)
343 /* Get the Wait block */
344 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
346 /* Go to the next entry */
347 NextEntry
= NextEntry
->Flink
;
349 /* Check if there's no Wait Routine (satisfied wait) */
350 if (WaitBlock
->WaitFunction
== NULL
)
352 /* Remove it from the Wait Block Queue */
353 RemoveEntryList(&WaitBlock
->WaitList
);
355 /* Insert the new entry */
356 InsertTailList(&WaitBlock
->WaitList
, NewEntry
);
360 /* Release the wait lock */
361 CsrReleaseWaitLock();
365 * @name CsrNotifyWait
368 * The CsrNotifyWait notifies a CSR Wait Block.
371 * Pointer to the list entry for this wait.
374 * Type of the wait to perform, either WaitAny or WaitAll.
376 * @param WaitArgument[1-2]
377 * User-defined argument to pass on to the wait function.
379 * @return TRUE in case of success, FALSE otherwise.
386 CsrNotifyWait(IN PLIST_ENTRY WaitList
,
388 IN PVOID WaitArgument1
,
389 IN PVOID WaitArgument2
)
391 PLIST_ENTRY NextEntry
;
392 PCSR_WAIT_BLOCK WaitBlock
;
393 BOOLEAN NotifySuccess
= FALSE
;
395 /* Acquire the Wait Lock */
396 CsrAcquireWaitLock();
398 /* Set the List pointers */
399 NextEntry
= WaitList
->Flink
;
402 while (NextEntry
!= WaitList
)
404 /* Get the Wait block */
405 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
407 /* Go to the next entry */
408 NextEntry
= NextEntry
->Flink
;
410 /* Check if there is a Wait Routine */
411 if (WaitBlock
->WaitFunction
!= NULL
)
413 /* Notify the Waiter */
414 NotifySuccess
|= CsrNotifyWaitBlock(WaitBlock
,
421 /* We've already done a wait, so leave unless this is a Wait All */
422 if (WaitType
!= WaitAll
) break;
426 /* Release the wait lock and return */
427 CsrReleaseWaitLock();
428 return NotifySuccess
;