Forgot this one.
[reactos.git] / reactos / 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 WaitBlock->WaitContext = WaitContext;
77 WaitBlock->WaitFunction = WaitFunction;
78 WaitBlock->WaitList.Flink = NULL;
79 WaitBlock->WaitList.Blink = NULL;
80
81 /* Copy the message */
82 RtlCopyMemory(&WaitBlock->WaitApiMessage,
83 WaitApiMessage,
84 WaitApiMessage->Header.u1.s1.TotalLength);
85
86 /* Return the block */
87 *NewWaitBlock = WaitBlock;
88 return TRUE;
89 }
90
91 /*++
92 * @name CsrNotifyWaitBlock
93 *
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.
96 *
97 * @param WaitBlock
98 * Pointer to the CSR Wait Block.
99 *
100 * @param WaitList
101 * Pointer to the wait list for this wait.
102 *
103 * @param WaitArgument[1-2]
104 * User-defined values to pass to the wait function.
105 *
106 * @param WaitFlags
107 * Wait flags for this wait.
108 *
109 * @param DereferenceThread
110 * Specifies whether the CSR Thread should be dereferenced at the
111 * end of this wait.
112 *
113 * @return TRUE in case of success, FALSE otherwise.
114 *
115 * @remarks After a wait block is notified, the wait function becomes invalid.
116 *
117 *--*/
118 BOOLEAN
119 NTAPI
120 CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
121 IN PLIST_ENTRY WaitList,
122 IN PVOID WaitArgument1,
123 IN PVOID WaitArgument2,
124 IN ULONG WaitFlags,
125 IN BOOLEAN DereferenceThread)
126 {
127 /* Call the wait function */
128 if (WaitBlock->WaitFunction(WaitList,
129 WaitBlock->WaitThread,
130 &WaitBlock->WaitApiMessage,
131 WaitBlock->WaitContext,
132 WaitArgument1,
133 WaitArgument2,
134 WaitFlags))
135 {
136 /* The wait is done, clear the block */
137 WaitBlock->WaitThread->WaitBlock = NULL;
138
139 /* Check for captured arguments */
140 if (WaitBlock->WaitApiMessage.CsrCaptureData)
141 {
142 /* Release them */
143 CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage);
144 }
145
146 /* Reply to the port */
147 NtReplyPort(WaitBlock->WaitThread->Process->ClientPort,
148 &WaitBlock->WaitApiMessage.Header);
149
150 /* Check if we should dereference the thread */
151 if (DereferenceThread)
152 {
153 /* Remove it from the Wait List */
154 if (WaitBlock->WaitList.Flink)
155 {
156 RemoveEntryList(&WaitBlock->WaitList);
157 }
158
159 /* Dereference the thread */
160 CsrDereferenceThread(WaitBlock->WaitThread);
161
162 /* Free the wait block */
163 RtlFreeHeap(CsrHeap, 0, WaitBlock);
164 }
165 else
166 {
167 /* The wait is complete, but the thread is being kept alive */
168 WaitBlock->WaitFunction = NULL;
169 }
170
171 /* The wait succeeded */
172 return TRUE;
173 }
174
175 /* The wait failed */
176 return FALSE;
177 }
178
179 /* PUBLIC FUNCTIONS ***********************************************************/
180
181 /*++
182 * @name CsrCreateWait
183 * @implemented NT4
184 *
185 * The CsrCreateWait routine creates a CSR Wait.
186 *
187 * @param WaitList
188 * Pointer to a wait list in which the wait will be added.
189 *
190 * @param WaitFunction
191 * Pointer to the function that will handle this wait.
192 *
193 * @param CsrWaitThread
194 * Pointer to the CSR Thread that will perform the wait.
195 *
196 * @param WaitApiMessage
197 * Pointer to the CSR API Message associated to this wait.
198 *
199 * @param WaitContext
200 * Pointer to a user-defined parameter associated to this wait.
201 *
202 * @return TRUE in case of success, FALSE otherwise.
203 *
204 * @remarks None.
205 *
206 *--*/
207 BOOLEAN
208 NTAPI
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)
214 {
215 PCSR_WAIT_BLOCK WaitBlock;
216
217 /* Initialize the wait */
218 if (!CsrInitializeWait(WaitFunction,
219 CsrWaitThread,
220 WaitApiMessage,
221 WaitContext,
222 &WaitBlock))
223 {
224 return FALSE;
225 }
226
227 /* Acquire the Wait Lock */
228 CsrAcquireWaitLock();
229
230 /* Make sure the thread wasn't destroyed */
231 if (CsrWaitThread->Flags & CsrThreadTerminated)
232 {
233 /* Fail the wait */
234 RtlFreeHeap(CsrHeap, 0, WaitBlock);
235 CsrReleaseWaitLock();
236 return FALSE;
237 }
238
239 /* Associate the newly created wait to the waiting thread */
240 CsrWaitThread->WaitBlock = WaitBlock;
241
242 /* Insert the wait in the queue */
243 InsertTailList(WaitList, &WaitBlock->WaitList);
244
245 /* Return */
246 CsrReleaseWaitLock();
247 return TRUE;
248 }
249
250 /*++
251 * @name CsrDereferenceWait
252 * @implemented NT4
253 *
254 * The CsrDereferenceWait routine dereferences a CSR Wait Block.
255 *
256 * @param WaitList
257 * Pointer to the Wait List associated to the wait.
258
259 * @return None.
260 *
261 * @remarks None.
262 *
263 *--*/
264 VOID
265 NTAPI
266 CsrDereferenceWait(IN PLIST_ENTRY WaitList)
267 {
268 PLIST_ENTRY NextEntry;
269 PCSR_WAIT_BLOCK WaitBlock;
270
271 /* Acquire the Process and Wait Locks */
272 CsrAcquireProcessLock();
273 CsrAcquireWaitLock();
274
275 /* Set the list pointers */
276 NextEntry = WaitList->Flink;
277
278 /* Start the loop */
279 while (NextEntry != WaitList)
280 {
281 /* Get the wait block */
282 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
283
284 /* Move to the next entry */
285 NextEntry = NextEntry->Flink;
286
287 /* Check if there's no Wait Routine (satisfied wait) */
288 if (WaitBlock->WaitFunction == NULL)
289 {
290 /* Remove it from the Wait List */
291 if (WaitBlock->WaitList.Flink)
292 {
293 RemoveEntryList(&WaitBlock->WaitList);
294 }
295
296 /* Dereference the thread waiting on it */
297 CsrDereferenceThread(WaitBlock->WaitThread);
298
299 /* Free the block */
300 RtlFreeHeap(CsrHeap, 0, WaitBlock);
301 }
302 }
303
304 /* Release the locks */
305 CsrReleaseWaitLock();
306 CsrReleaseProcessLock();
307 }
308
309 /*++
310 * @name CsrMoveSatisfiedWait
311 * @implemented NT5
312 *
313 * The CsrMoveSatisfiedWait routine moves satisfied waits from
314 * a wait list to another list.
315 *
316 * @param DestinationList
317 * Pointer to a list in which the satisfied waits will be added.
318 *
319 * @param WaitList
320 * Pointer to the wait list whose satisfied wait blocks
321 * will be moved away.
322 *
323 * @return None.
324 *
325 * @remarks None.
326 *
327 *--*/
328 VOID
329 NTAPI
330 CsrMoveSatisfiedWait(IN PLIST_ENTRY DestinationList,
331 IN PLIST_ENTRY WaitList)
332 {
333 PLIST_ENTRY NextEntry;
334 PCSR_WAIT_BLOCK WaitBlock;
335
336 /* Acquire the Wait Lock */
337 CsrAcquireWaitLock();
338
339 /* Set the List pointers */
340 NextEntry = WaitList->Flink;
341
342 /* Start looping */
343 while (NextEntry != WaitList)
344 {
345 /* Get the Wait block */
346 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
347
348 /* Go to the next entry */
349 NextEntry = NextEntry->Flink;
350
351 /* Check if there's no Wait Routine (satisfied wait) */
352 if (WaitBlock->WaitFunction == NULL)
353 {
354 /* Remove it from the Wait Block Queue */
355 RemoveEntryList(&WaitBlock->WaitList);
356
357 /* Insert the wait into the destination list */
358 InsertTailList(DestinationList, &WaitBlock->WaitList);
359 }
360 }
361
362 /* Release the wait lock */
363 CsrReleaseWaitLock();
364 }
365
366 /*++
367 * @name CsrNotifyWait
368 * @implemented NT4
369 *
370 * The CsrNotifyWait routine notifies CSR Wait Blocks.
371 *
372 * @param WaitList
373 * Pointer to the wait list whose wait blocks will be notified.
374 *
375 * @param WaitType
376 * Type of the wait to perform, either WaitAny or WaitAll.
377 *
378 * @param WaitArgument[1-2]
379 * User-defined argument to pass on to the wait function.
380 *
381 * @return TRUE in case of success, FALSE otherwise.
382 *
383 * @remarks None.
384 *
385 *--*/
386 BOOLEAN
387 NTAPI
388 CsrNotifyWait(IN PLIST_ENTRY WaitList,
389 IN ULONG WaitType,
390 IN PVOID WaitArgument1,
391 IN PVOID WaitArgument2)
392 {
393 PLIST_ENTRY NextEntry;
394 PCSR_WAIT_BLOCK WaitBlock;
395 BOOLEAN NotifySuccess = FALSE;
396
397 /* Acquire the Wait Lock */
398 CsrAcquireWaitLock();
399
400 /* Set the List pointers */
401 NextEntry = WaitList->Flink;
402
403 /* Start looping */
404 while (NextEntry != WaitList)
405 {
406 /* Get the Wait block */
407 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
408
409 /* Go to the next entry */
410 NextEntry = NextEntry->Flink;
411
412 /* Check if there is a Wait Routine */
413 if (WaitBlock->WaitFunction != NULL)
414 {
415 /* Notify the Waiter */
416 NotifySuccess |= CsrNotifyWaitBlock(WaitBlock,
417 WaitList,
418 WaitArgument1,
419 WaitArgument2,
420 0,
421 FALSE);
422
423 /* We've already done a wait, so leave unless this is a Wait All */
424 if (WaitType != WaitAll) break;
425 }
426 }
427
428 /* Release the wait lock and return */
429 CsrReleaseWaitLock();
430 return NotifySuccess;
431 }
432
433 /* EOF */