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