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
->UserWaitList
.Flink
= NULL
;
80 WaitBlock
->UserWaitList
.Blink
= NULL
;
81 WaitBlock
->WaitList
= WaitBlock
->UserWaitList
;
83 /* Copy the message */
84 RtlMoveMemory(&WaitBlock
->WaitApiMessage
,
86 WaitApiMessage
->Header
.u1
.s1
.TotalLength
);
88 /* Return the block */
89 *NewWaitBlock
= WaitBlock
;
94 * @name CsrNotifyWaitBlock
96 * The CsrNotifyWaitBlock routine calls the wait function for a registered
97 * CSR Wait Block, and replies to the attached CSR API Message, if any.
100 * Pointer to the CSR Wait Block
103 * Pointer to the wait list for this wait.
105 * @param WaitArgument[1-2]
106 * User-defined values to pass to the wait function.
109 * Wait flags for this wait.
111 * @param DereferenceThread
112 * Specifies whether the CSR Thread should be dereferenced at the
115 * @return TRUE in case of success, FALSE otherwise.
117 * @remarks After a wait block is notified, the wait function becomes invalid.
122 CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock
,
123 IN PLIST_ENTRY WaitList
,
124 IN PVOID WaitArgument1
,
125 IN PVOID WaitArgument2
,
127 IN BOOLEAN DereferenceThread
)
129 /* Call the wait function */
130 if (WaitBlock
->WaitFunction(WaitList
,
131 WaitBlock
->WaitThread
,
132 &WaitBlock
->WaitApiMessage
,
133 WaitBlock
->WaitContext
,
138 /* The wait is done, clear the block */
139 WaitBlock
->WaitThread
->WaitBlock
= NULL
;
141 /* Check for captured arguments */
142 if (WaitBlock
->WaitApiMessage
.CsrCaptureData
)
145 CsrReleaseCapturedArguments(&WaitBlock
->WaitApiMessage
);
148 /* Reply to the port */
149 NtReplyPort(WaitBlock
->WaitThread
->Process
->ClientPort
,
150 (PPORT_MESSAGE
)&WaitBlock
->WaitApiMessage
);
152 /* Check if we should dereference the thread */
153 if (DereferenceThread
)
155 /* Remove it from the Wait List */
156 if (WaitBlock
->WaitList
.Flink
)
158 RemoveEntryList(&WaitBlock
->WaitList
);
161 /* Remove it from the User Wait List */
162 if (WaitBlock
->UserWaitList
.Flink
)
164 RemoveEntryList(&WaitBlock
->UserWaitList
);
167 /* Dereference the thread */
168 CsrDereferenceThread(WaitBlock
->WaitThread
);
170 /* Free the wait block */
171 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
175 /* The wait is complete, but the thread is being kept alive */
176 WaitBlock
->WaitFunction
= NULL
;
179 /* The wait succeeded */
183 /* The wait failed */
187 /* PUBLIC FUNCTIONS ***********************************************************/
190 * @name CsrCreateWait
193 * The CsrCreateWait routine creates a CSR Wait.
196 * Pointer to a list entry of the waits to associate.
198 * @param WaitFunction
199 * Pointer to the function that will handle this wait.
201 * @param CsrWaitThread
202 * Pointer to the CSR Thread that will perform the wait.
204 * @param WaitApiMessage
205 * Pointer to the CSR API Message associated to this wait.
208 * Pointer to a user-defined parameter associated to this wait.
210 * @param UserWaitList
211 * Pointer to a list entry of the user-defined waits to associate.
213 * @return TRUE in case of success, FALSE otherwise.
220 CsrCreateWait(IN PLIST_ENTRY WaitList
,
221 IN CSR_WAIT_FUNCTION WaitFunction
,
222 IN PCSR_THREAD CsrWaitThread
,
223 IN OUT PCSR_API_MESSAGE WaitApiMessage
,
224 IN PVOID WaitContext
,
225 IN PLIST_ENTRY UserWaitList OPTIONAL
)
227 PCSR_WAIT_BLOCK WaitBlock
;
229 /* Initialize the wait */
230 if (!CsrInitializeWait(WaitFunction
,
239 /* Acquire the Wait Lock */
240 CsrAcquireWaitLock();
242 /* Make sure the thread wasn't destroyed */
243 if (CsrWaitThread
->Flags
& CsrThreadTerminated
)
246 CsrWaitThread
->WaitBlock
= NULL
;
247 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
248 CsrReleaseWaitLock();
252 /* Insert the wait in the queue */
253 InsertTailList(WaitList
, &WaitBlock
->WaitList
);
255 /* Insert the User Wait too, if one was given */
256 if (UserWaitList
) InsertTailList(UserWaitList
, &WaitBlock
->UserWaitList
);
259 CsrReleaseWaitLock();
264 * @name CsrDereferenceWait
267 * The CsrDereferenceWait routine dereferences a CSR Wait Block.
270 * Pointer to the Wait List associated to the wait.
279 CsrDereferenceWait(IN PLIST_ENTRY WaitList
)
281 PLIST_ENTRY NextEntry
;
282 PCSR_WAIT_BLOCK WaitBlock
;
284 /* Acquire the Process and Wait Locks */
285 CsrAcquireProcessLock();
286 CsrAcquireWaitLock();
288 /* Set the list pointers */
289 NextEntry
= WaitList
->Flink
;
292 while (NextEntry
!= WaitList
)
294 /* Get the wait block */
295 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
297 /* Move to the next entry */
298 NextEntry
= NextEntry
->Flink
;
300 /* Check if there's no Wait Routine (satisfied wait) */
301 if (WaitBlock
->WaitFunction
== NULL
)
303 /* Remove it from the Wait List */
304 if (WaitBlock
->WaitList
.Flink
)
306 RemoveEntryList(&WaitBlock
->WaitList
);
309 /* Remove it from the User Wait List */
310 if (WaitBlock
->UserWaitList
.Flink
)
312 RemoveEntryList(&WaitBlock
->UserWaitList
);
315 /* Dereference the thread waiting on it */
316 CsrDereferenceThread(WaitBlock
->WaitThread
);
319 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
323 /* Release the locks */
324 CsrReleaseWaitLock();
325 CsrReleaseProcessLock();
329 * @name CsrMoveSatisfiedWait
332 * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
333 * to another list entry.
336 * Pointer to a list entry where the satisfied waits will be added.
339 * Pointer to a list entry to analyze for satisfied waits.
348 CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry
,
349 IN PLIST_ENTRY WaitList
)
351 PLIST_ENTRY NextEntry
;
352 PCSR_WAIT_BLOCK WaitBlock
;
354 /* Acquire the Wait Lock */
355 CsrAcquireWaitLock();
357 /* Set the List pointers */
358 NextEntry
= WaitList
->Flink
;
361 while (NextEntry
!= WaitList
)
363 /* Get the Wait block */
364 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
366 /* Go to the next entry */
367 NextEntry
= NextEntry
->Flink
;
369 /* Check if there's no Wait Routine (satisfied wait) */
370 if (WaitBlock
->WaitFunction
== NULL
)
372 /* Remove it from the Wait Block Queue */
373 RemoveEntryList(&WaitBlock
->WaitList
);
375 /* Insert the new entry */
376 InsertTailList(&WaitBlock
->WaitList
, NewEntry
);
380 /* Release the wait lock */
381 CsrReleaseWaitLock();
385 * @name CsrNotifyWait
388 * The CsrNotifyWait notifies a CSR Wait Block.
391 * Pointer to the list entry for this wait.
394 * Type of the wait to perform, either WaitAny or WaitAll.
396 * @param WaitArgument[1-2]
397 * User-defined argument to pass on to the wait function.
399 * @return TRUE in case of success, FALSE otherwise.
406 CsrNotifyWait(IN PLIST_ENTRY WaitList
,
408 IN PVOID WaitArgument1
,
409 IN PVOID WaitArgument2
)
411 PLIST_ENTRY NextEntry
;
412 PCSR_WAIT_BLOCK WaitBlock
;
413 BOOLEAN NotifySuccess
= FALSE
;
415 /* Acquire the Wait Lock */
416 CsrAcquireWaitLock();
418 /* Set the List pointers */
419 NextEntry
= WaitList
->Flink
;
422 while (NextEntry
!= WaitList
)
424 /* Get the Wait block */
425 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
427 /* Go to the next entry */
428 NextEntry
= NextEntry
->Flink
;
430 /* Check if there is a Wait Routine */
431 if (WaitBlock
->WaitFunction
!= NULL
)
433 /* Notify the Waiter */
434 NotifySuccess
|= CsrNotifyWaitBlock(WaitBlock
,
441 /* We've already done a wait, so leave unless this is a Wait All */
442 if (WaitType
!= WaitAll
) break;
446 /* Release the wait lock and return */
447 CsrReleaseWaitLock();
448 return NotifySuccess
;