[CSRSRV]
[reactos.git] / subsystems / win32 / csrsrv / wait.c
1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "srv.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* DATA ***********************************************************************/
18
19 RTL_CRITICAL_SECTION CsrWaitListsLock;
20
21 /* PRIVATE FUNCTIONS **********************************************************/
22
23 /*++
24 * @name CsrInitializeWait
25 *
26 * The CsrInitializeWait routine initializes a CSR Wait Object.
27 *
28 * @param WaitFunction
29 * Pointer to the function that will handle this wait.
30 *
31 * @param CsrWaitThread
32 * Pointer to the CSR Thread that will perform the wait.
33 *
34 * @param WaitApiMessage
35 * Pointer to the CSR API Message associated to this wait.
36 *
37 * @param WaitContext
38 * Pointer to a user-defined parameter associated to this wait.
39 *
40 * @param NewWaitBlock
41 * Pointed to the initialized CSR Wait Block for this wait.
42 *
43 * @return TRUE in case of success, FALSE otherwise.
44 *
45 * @remarks None.
46 *
47 *--*/
48 BOOLEAN
49 NTAPI
50 CsrInitializeWait(IN CSR_WAIT_FUNCTION WaitFunction,
51 IN PCSR_THREAD CsrWaitThread,
52 IN OUT PCSR_API_MESSAGE WaitApiMessage,
53 IN PVOID WaitContext,
54 OUT PCSR_WAIT_BLOCK *NewWaitBlock)
55 {
56 ULONG Size;
57 PCSR_WAIT_BLOCK WaitBlock;
58
59 /* Calculate the size of the wait block */
60 Size = sizeof(CSR_WAIT_BLOCK) -
61 sizeof(WaitBlock->WaitApiMessage) +
62 WaitApiMessage->Header.u1.s1.TotalLength;
63
64 /* Allocate the Wait Block */
65 WaitBlock = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size);
66 if (!WaitBlock)
67 {
68 /* Fail */
69 WaitApiMessage->Status = STATUS_NO_MEMORY;
70 return FALSE;
71 }
72
73 /* Initialize it */
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;
82
83 /* Copy the message */
84 RtlMoveMemory(&WaitBlock->WaitApiMessage,
85 WaitApiMessage,
86 WaitApiMessage->Header.u1.s1.TotalLength);
87
88 /* Return the block */
89 *NewWaitBlock = WaitBlock;
90 return TRUE;
91 }
92
93 /*++
94 * @name CsrNotifyWaitBlock
95 *
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.
98 *
99 * @param WaitBlock
100 * Pointer to the CSR Wait Block
101 *
102 * @param WaitList
103 * Pointer to the wait list for this wait.
104 *
105 * @param WaitArgument[1-2]
106 * User-defined values to pass to the wait function.
107 *
108 * @param WaitFlags
109 * Wait flags for this wait.
110 *
111 * @param DereferenceThread
112 * Specifies whether the CSR Thread should be dereferenced at the
113 * end of this wait.
114 *
115 * @return TRUE in case of success, FALSE otherwise.
116 *
117 * @remarks After a wait block is notified, the wait function becomes invalid.
118 *
119 *--*/
120 BOOLEAN
121 NTAPI
122 CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
123 IN PLIST_ENTRY WaitList,
124 IN PVOID WaitArgument1,
125 IN PVOID WaitArgument2,
126 IN ULONG WaitFlags,
127 IN BOOLEAN DereferenceThread)
128 {
129 /* Call the wait function */
130 if (WaitBlock->WaitFunction(WaitList,
131 WaitBlock->WaitThread,
132 &WaitBlock->WaitApiMessage,
133 WaitBlock->WaitContext,
134 WaitArgument1,
135 WaitArgument2,
136 WaitFlags))
137 {
138 /* The wait is done, clear the block */
139 WaitBlock->WaitThread->WaitBlock = NULL;
140
141 /* Check for captured arguments */
142 if (WaitBlock->WaitApiMessage.CsrCaptureData)
143 {
144 /* Release them */
145 CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage);
146 }
147
148 /* Reply to the port */
149 NtReplyPort(WaitBlock->WaitThread->Process->ClientPort,
150 (PPORT_MESSAGE)&WaitBlock->WaitApiMessage);
151
152 /* Check if we should dereference the thread */
153 if (DereferenceThread)
154 {
155 /* Remove it from the Wait List */
156 if (WaitBlock->WaitList.Flink)
157 {
158 RemoveEntryList(&WaitBlock->WaitList);
159 }
160
161 /* Remove it from the User Wait List */
162 if (WaitBlock->UserWaitList.Flink)
163 {
164 RemoveEntryList(&WaitBlock->UserWaitList);
165 }
166
167 /* Dereference the thread */
168 CsrDereferenceThread(WaitBlock->WaitThread);
169
170 /* Free the wait block */
171 RtlFreeHeap(CsrHeap, 0, WaitBlock);
172 }
173 else
174 {
175 /* The wait is complete, but the thread is being kept alive */
176 WaitBlock->WaitFunction = NULL;
177 }
178
179 /* The wait succeeded */
180 return TRUE;
181 }
182
183 /* The wait failed */
184 return FALSE;
185 }
186
187 /* PUBLIC FUNCTIONS ***********************************************************/
188
189 /*++
190 * @name CsrCreateWait
191 * @implemented NT4
192 *
193 * The CsrCreateWait routine creates a CSR Wait.
194 *
195 * @param WaitList
196 * Pointer to a list entry of the waits to associate.
197 *
198 * @param WaitFunction
199 * Pointer to the function that will handle this wait.
200 *
201 * @param CsrWaitThread
202 * Pointer to the CSR Thread that will perform the wait.
203 *
204 * @param WaitApiMessage
205 * Pointer to the CSR API Message associated to this wait.
206 *
207 * @param WaitContext
208 * Pointer to a user-defined parameter associated to this wait.
209 *
210 * @param UserWaitList
211 * Pointer to a list entry of the user-defined waits to associate.
212 *
213 * @return TRUE in case of success, FALSE otherwise.
214 *
215 * @remarks None.
216 *
217 *--*/
218 BOOLEAN
219 NTAPI
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)
226 {
227 PCSR_WAIT_BLOCK WaitBlock;
228
229 /* Initialize the wait */
230 if (!CsrInitializeWait(WaitFunction,
231 CsrWaitThread,
232 WaitApiMessage,
233 WaitContext,
234 &WaitBlock))
235 {
236 return FALSE;
237 }
238
239 /* Acquire the Wait Lock */
240 CsrAcquireWaitLock();
241
242 /* Make sure the thread wasn't destroyed */
243 if (CsrWaitThread->Flags & CsrThreadTerminated)
244 {
245 /* Fail the wait */
246 CsrWaitThread->WaitBlock = NULL;
247 RtlFreeHeap(CsrHeap, 0, WaitBlock);
248 CsrReleaseWaitLock();
249 return FALSE;
250 }
251
252 /* Insert the wait in the queue */
253 InsertTailList(WaitList, &WaitBlock->WaitList);
254
255 /* Insert the User Wait too, if one was given */
256 if (UserWaitList) InsertTailList(UserWaitList, &WaitBlock->UserWaitList);
257
258 /* Return */
259 CsrReleaseWaitLock();
260 return TRUE;
261 }
262
263 /*++
264 * @name CsrDereferenceWait
265 * @implemented NT4
266 *
267 * The CsrDereferenceWait routine dereferences a CSR Wait Block.
268 *
269 * @param WaitList
270 * Pointer to the Wait List associated to the wait.
271
272 * @return None.
273 *
274 * @remarks None.
275 *
276 *--*/
277 VOID
278 NTAPI
279 CsrDereferenceWait(IN PLIST_ENTRY WaitList)
280 {
281 PLIST_ENTRY NextEntry;
282 PCSR_WAIT_BLOCK WaitBlock;
283
284 /* Acquire the Process and Wait Locks */
285 CsrAcquireProcessLock();
286 CsrAcquireWaitLock();
287
288 /* Set the list pointers */
289 NextEntry = WaitList->Flink;
290
291 /* Start the loop */
292 while (NextEntry != WaitList)
293 {
294 /* Get the wait block */
295 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
296
297 /* Move to the next entry */
298 NextEntry = NextEntry->Flink;
299
300 /* Check if there's no Wait Routine (satisfied wait) */
301 if (WaitBlock->WaitFunction == NULL)
302 {
303 /* Remove it from the Wait List */
304 if (WaitBlock->WaitList.Flink)
305 {
306 RemoveEntryList(&WaitBlock->WaitList);
307 }
308
309 /* Remove it from the User Wait List */
310 if (WaitBlock->UserWaitList.Flink)
311 {
312 RemoveEntryList(&WaitBlock->UserWaitList);
313 }
314
315 /* Dereference the thread waiting on it */
316 CsrDereferenceThread(WaitBlock->WaitThread);
317
318 /* Free the block */
319 RtlFreeHeap(CsrHeap, 0, WaitBlock);
320 }
321 }
322
323 /* Release the locks */
324 CsrReleaseWaitLock();
325 CsrReleaseProcessLock();
326 }
327
328 /*++
329 * @name CsrMoveSatisfiedWait
330 * @implemented NT5
331 *
332 * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
333 * to another list entry.
334 *
335 * @param NewEntry
336 * Pointer to a list entry where the satisfied waits will be added.
337 *
338 * @param WaitList
339 * Pointer to a list entry to analyze for satisfied waits.
340 *
341 * @return None.
342 *
343 * @remarks None.
344 *
345 *--*/
346 VOID
347 NTAPI
348 CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry,
349 IN PLIST_ENTRY WaitList)
350 {
351 PLIST_ENTRY NextEntry;
352 PCSR_WAIT_BLOCK WaitBlock;
353
354 /* Acquire the Wait Lock */
355 CsrAcquireWaitLock();
356
357 /* Set the List pointers */
358 NextEntry = WaitList->Flink;
359
360 /* Start looping */
361 while (NextEntry != WaitList)
362 {
363 /* Get the Wait block */
364 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
365
366 /* Go to the next entry */
367 NextEntry = NextEntry->Flink;
368
369 /* Check if there's no Wait Routine (satisfied wait) */
370 if (WaitBlock->WaitFunction == NULL)
371 {
372 /* Remove it from the Wait Block Queue */
373 RemoveEntryList(&WaitBlock->WaitList);
374
375 /* Insert the new entry */
376 InsertTailList(&WaitBlock->WaitList, NewEntry);
377 }
378 }
379
380 /* Release the wait lock */
381 CsrReleaseWaitLock();
382 }
383
384 /*++
385 * @name CsrNotifyWait
386 * @implemented NT4
387 *
388 * The CsrNotifyWait notifies a CSR Wait Block.
389 *
390 * @param WaitList
391 * Pointer to the list entry for this wait.
392 *
393 * @param WaitType
394 * Type of the wait to perform, either WaitAny or WaitAll.
395 *
396 * @param WaitArgument[1-2]
397 * User-defined argument to pass on to the wait function.
398 *
399 * @return TRUE in case of success, FALSE otherwise.
400 *
401 * @remarks None.
402 *
403 *--*/
404 BOOLEAN
405 NTAPI
406 CsrNotifyWait(IN PLIST_ENTRY WaitList,
407 IN ULONG WaitType,
408 IN PVOID WaitArgument1,
409 IN PVOID WaitArgument2)
410 {
411 PLIST_ENTRY NextEntry;
412 PCSR_WAIT_BLOCK WaitBlock;
413 BOOLEAN NotifySuccess = FALSE;
414
415 /* Acquire the Wait Lock */
416 CsrAcquireWaitLock();
417
418 /* Set the List pointers */
419 NextEntry = WaitList->Flink;
420
421 /* Start looping */
422 while (NextEntry != WaitList)
423 {
424 /* Get the Wait block */
425 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
426
427 /* Go to the next entry */
428 NextEntry = NextEntry->Flink;
429
430 /* Check if there is a Wait Routine */
431 if (WaitBlock->WaitFunction != NULL)
432 {
433 /* Notify the Waiter */
434 NotifySuccess |= CsrNotifyWaitBlock(WaitBlock,
435 WaitList,
436 WaitArgument1,
437 WaitArgument2,
438 0,
439 FALSE);
440
441 /* We've already done a wait, so leave unless this is a Wait All */
442 if (WaitType != WaitAll) break;
443 }
444 }
445
446 /* Release the wait lock and return */
447 CsrReleaseWaitLock();
448 return NotifySuccess;
449 }
450
451 /* EOF */