2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsys/csr/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 othwerwise.
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 if (!(WaitBlock
= RtlAllocateHeap(CsrHeap
, 0, Size
)))
68 WaitApiMessage
->Status
= STATUS_NO_MEMORY
;
73 WaitBlock
->Size
= Size
;
74 WaitBlock
->WaitThread
= CsrWaitThread
;
75 WaitBlock
->WaitContext
= WaitContext
;
76 WaitBlock
->WaitFunction
= WaitFunction
;
77 InitializeListHead(&WaitBlock
->UserWaitList
);
78 InitializeListHead(&WaitBlock
->WaitList
);
80 /* Copy the message */
81 RtlMoveMemory(&WaitBlock
->WaitApiMessage
,
83 WaitApiMessage
->Header
.u1
.s1
.TotalLength
);
85 /* Return the block */
86 *NewWaitBlock
= WaitBlock
;
91 * @name CsrNotifyWaitBlock
93 * The CsrNotifyWaitBlock routine calls the wait function for a registered
94 * CSR Wait Block, and replies to the attached CSR API Message, if any.
97 * Pointer to the CSR Wait Block
100 * Pointer to the wait list for this wait.
102 * @param WaitArgument[1-2]
103 * User-defined values to pass to the wait function.
106 * Wait flags for this wait.
108 * @param DereferenceThread
109 * Specifies whether the CSR Thread should be dereferenced at the
112 * @return TRUE in case of success, FALSE otherwise.
114 * @remarks After a wait block is notified, the wait function becomes invalid.
119 CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock
,
120 IN PLIST_ENTRY WaitList
,
121 IN PVOID WaitArgument1
,
122 IN PVOID WaitArgument2
,
124 IN BOOLEAN DereferenceThread
)
126 /* Call the wait function */
127 if ((WaitBlock
->WaitFunction
)(WaitList
,
128 WaitBlock
->WaitThread
,
129 &WaitBlock
->WaitApiMessage
,
130 WaitBlock
->WaitContext
,
135 /* The wait is done, clear the block */
136 WaitBlock
->WaitThread
->WaitBlock
= NULL
;
138 /* Check for captured arguments */
139 if (WaitBlock
->WaitApiMessage
.CsrCaptureData
)
142 CsrReleaseCapturedArguments(&WaitBlock
->WaitApiMessage
);
145 /* Reply to the port */
146 NtReplyPort(WaitBlock
->WaitThread
->Process
->ClientPort
,
147 (PPORT_MESSAGE
)&WaitBlock
->WaitApiMessage
);
149 /* Check if we should dereference the thread */
150 if (DereferenceThread
)
152 /* Remove it from the Wait List */
153 if (WaitBlock
->WaitList
.Flink
)
155 RemoveEntryList(&WaitBlock
->WaitList
);
158 /* Remove it from the User Wait List */
159 if (WaitBlock
->UserWaitList
.Flink
)
161 RemoveEntryList(&WaitBlock
->UserWaitList
);
164 /* Dereference teh thread */
165 CsrDereferenceThread(WaitBlock
->WaitThread
);
167 /* Free the wait block */
168 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
172 /* The wait is complete, but the thread is being kept alive */
173 WaitBlock
->WaitFunction
= NULL
;
176 /* The wait suceeded*/
180 /* The wait failed */
184 /* PUBLIC FUNCTIONS **********************************************************/
187 * @name CsrCreateWait
190 * The CsrCreateWait routine creates a CSR Wait.
193 * Pointer to a list entry of the waits to associate.
195 * @param WaitFunction
196 * Pointer to the function that will handle this wait.
198 * @param CsrWaitThread
199 * Pointer to the CSR Thread that will perform the wait.
201 * @param WaitApiMessage
202 * Pointer to the CSR API Message associated to this wait.
205 * Pointer to a user-defined parameter associated to this wait.
207 * @param UserWaitList
208 * Pointer to a list entry of the user-defined waits to associate.
210 * @return TRUE in case of success, FALSE otherwise.
217 CsrCreateWait(IN PLIST_ENTRY WaitList
,
218 IN CSR_WAIT_FUNCTION WaitFunction
,
219 IN PCSR_THREAD CsrWaitThread
,
220 IN OUT PCSR_API_MESSAGE WaitApiMessage
,
221 IN PVOID WaitContext
,
222 IN PLIST_ENTRY UserWaitList OPTIONAL
)
224 PCSR_WAIT_BLOCK WaitBlock
;
226 /* Initialize the wait */
227 if (!CsrInitializeWait(WaitFunction
,
236 /* Acquire the Wait Lock */
237 CsrAcquireWaitLock();
239 /* Make sure the thread wasn't destroyed */
240 if (CsrWaitThread
&& (CsrWaitThread
->Flags
& CsrThreadTerminated
))
243 CsrWaitThread
->WaitBlock
= NULL
;
244 RtlFreeHeap(CsrHeap
, 0, WaitBlock
);
245 CsrReleaseWaitLock();
249 /* Insert the wait in the queue */
250 InsertTailList(WaitList
, &WaitBlock
->WaitList
);
252 /* Insert the User Wait too, if one was given */
253 if (UserWaitList
) InsertTailList(UserWaitList
, &WaitBlock
->UserWaitList
);
256 CsrReleaseWaitLock();
261 * @name CsrDereferenceWait
264 * The CsrDereferenceWait routine derefences a CSR Wait Block.
267 * Pointer to the Wait List associated to the wait.
276 CsrDereferenceWait(IN PLIST_ENTRY WaitList
)
278 PLIST_ENTRY ListHead
, NextEntry
;
279 PCSR_WAIT_BLOCK WaitBlock
;
281 /* Acquire the Process and Wait Locks */
282 CsrAcquireProcessLock();
283 CsrAcquireWaitLock();
285 /* Set the list pointers */
287 NextEntry
= ListHead
->Flink
;
290 while (NextEntry
!= ListHead
)
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 ListHead
, NextEntry
;
350 PCSR_WAIT_BLOCK WaitBlock
;
352 /* Acquire the Wait Lock */
353 CsrAcquireWaitLock();
355 /* Set the List pointers */
357 NextEntry
= ListHead
->Flink
;
360 while (NextEntry
!= ListHead
)
362 /* Get the Wait block */
363 WaitBlock
= CONTAINING_RECORD(NextEntry
, CSR_WAIT_BLOCK
, WaitList
);
365 /* Go to the next entry */
366 NextEntry
= NextEntry
->Flink
;
368 /* Check if there is a Wait Callback */
369 if (WaitBlock
->WaitFunction
)
371 /* Remove it from the Wait Block Queue */
372 RemoveEntryList(&WaitBlock
->WaitList
);
374 /* Insert the new entry */
375 InsertTailList(&WaitBlock
->WaitList
, NewEntry
);
379 /* Release the wait lock */
380 CsrReleaseWaitLock();
384 * @name CsrNotifyWait
387 * The CsrNotifyWait notifies a CSR Wait Block.
390 * Pointer to the list entry for this wait.
393 * Type of the wait to perform, either WaitAny or WaitAll.
395 * @param WaitArgument[1-2]
396 * User-defined argument to pass on to the wait function.
398 * @return TRUE in case of success, FALSE othwerwise.
405 CsrNotifyWait(IN PLIST_ENTRY WaitList
,
407 IN PVOID WaitArgument1
,
408 IN PVOID WaitArgument2
)
410 PLIST_ENTRY ListHead
, NextEntry
;
411 PCSR_WAIT_BLOCK WaitBlock
;
412 BOOLEAN NotifySuccess
= FALSE
;
414 /* Acquire the Wait Lock */
415 CsrAcquireWaitLock();
417 /* Set the List pointers */
419 NextEntry
= ListHead
->Flink
;
422 while (NextEntry
!= ListHead
)
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 Callback */
431 if (WaitBlock
->WaitFunction
)
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
;