[CSRSS/CSRSRV]
[reactos.git] / subsystems / win32 / csrsrv / wait.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsystems/win32/csrss/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, 0, 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->UserWaitList.Flink = NULL;
79 WaitBlock->UserWaitList.Blink = NULL;
80 WaitBlock->WaitList = WaitBlock->UserWaitList;
81
82 /* Copy the message */
83 RtlMoveMemory(&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 /* Remove it from the User Wait List */
161 if (WaitBlock->UserWaitList.Flink)
162 {
163 RemoveEntryList(&WaitBlock->UserWaitList);
164 }
165
166 /* Dereference teh thread */
167 CsrDereferenceThread(WaitBlock->WaitThread);
168
169 /* Free the wait block */
170 RtlFreeHeap(CsrHeap, 0, WaitBlock);
171 }
172 else
173 {
174 /* The wait is complete, but the thread is being kept alive */
175 WaitBlock->WaitFunction = NULL;
176 }
177
178 /* The wait suceeded */
179 return TRUE;
180 }
181
182 /* The wait failed */
183 return FALSE;
184 }
185
186 /* PUBLIC FUNCTIONS **********************************************************/
187
188 /*++
189 * @name CsrCreateWait
190 * @implemented NT4
191 *
192 * The CsrCreateWait routine creates a CSR Wait.
193 *
194 * @param WaitList
195 * Pointer to a list entry of the waits to associate.
196 *
197 * @param WaitFunction
198 * Pointer to the function that will handle this wait.
199 *
200 * @param CsrWaitThread
201 * Pointer to the CSR Thread that will perform the wait.
202 *
203 * @param WaitApiMessage
204 * Pointer to the CSR API Message associated to this wait.
205 *
206 * @param WaitContext
207 * Pointer to a user-defined parameter associated to this wait.
208 *
209 * @param UserWaitList
210 * Pointer to a list entry of the user-defined waits to associate.
211 *
212 * @return TRUE in case of success, FALSE otherwise.
213 *
214 * @remarks None.
215 *
216 *--*/
217 BOOLEAN
218 NTAPI
219 CsrCreateWait(IN PLIST_ENTRY WaitList,
220 IN CSR_WAIT_FUNCTION WaitFunction,
221 IN PCSR_THREAD CsrWaitThread,
222 IN OUT PCSR_API_MESSAGE WaitApiMessage,
223 IN PVOID WaitContext,
224 IN PLIST_ENTRY UserWaitList OPTIONAL)
225 {
226 PCSR_WAIT_BLOCK WaitBlock;
227
228 /* Initialize the wait */
229 if (!CsrInitializeWait(WaitFunction,
230 CsrWaitThread,
231 WaitApiMessage,
232 WaitContext,
233 &WaitBlock))
234 {
235 return FALSE;
236 }
237
238 /* Acquire the Wait Lock */
239 CsrAcquireWaitLock();
240
241 /* Make sure the thread wasn't destroyed */
242 if (CsrWaitThread->Flags & CsrThreadTerminated)
243 {
244 /* Fail the wait */
245 RtlFreeHeap(CsrHeap, 0, WaitBlock);
246 CsrReleaseWaitLock();
247 return FALSE;
248 }
249
250 /* Insert the wait in the queue */
251 InsertTailList(WaitList, &WaitBlock->WaitList);
252
253 /* Insert the User Wait too, if one was given */
254 if (UserWaitList) InsertTailList(UserWaitList, &WaitBlock->UserWaitList);
255
256 /* Return */
257 CsrReleaseWaitLock();
258 return TRUE;
259 }
260
261 /*++
262 * @name CsrDereferenceWait
263 * @implemented NT4
264 *
265 * The CsrDereferenceWait routine dereferences a CSR Wait Block.
266 *
267 * @param WaitList
268 * Pointer to the Wait List associated to the wait.
269
270 * @return None.
271 *
272 * @remarks None.
273 *
274 *--*/
275 VOID
276 NTAPI
277 CsrDereferenceWait(IN PLIST_ENTRY WaitList)
278 {
279 PLIST_ENTRY NextEntry;
280 PCSR_WAIT_BLOCK WaitBlock;
281
282 /* Acquire the Process and Wait Locks */
283 CsrAcquireProcessLock();
284 CsrAcquireWaitLock();
285
286 /* Set the list pointers */
287 NextEntry = WaitList->Flink;
288
289 /* Start the loop */
290 while (NextEntry != WaitList)
291 {
292 /* Get the wait block */
293 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
294
295 /* Move to the next entry */
296 NextEntry = NextEntry->Flink;
297
298 /* Check if there's no Wait Routine */
299 if (!WaitBlock->WaitFunction)
300 {
301 /* Remove it from the Wait List */
302 if (WaitBlock->WaitList.Flink)
303 {
304 RemoveEntryList(&WaitBlock->WaitList);
305 }
306
307 /* Remove it from the User Wait List */
308 if (WaitBlock->UserWaitList.Flink)
309 {
310 RemoveEntryList(&WaitBlock->UserWaitList);
311 }
312
313 /* Dereference the thread waiting on it */
314 CsrDereferenceThread(WaitBlock->WaitThread);
315
316 /* Free the block */
317 RtlFreeHeap(CsrHeap, 0, WaitBlock);
318 }
319 }
320
321 /* Release the locks */
322 CsrReleaseWaitLock();
323 CsrReleaseProcessLock();
324 }
325
326 /*++
327 * @name CsrMoveSatisfiedWait
328 * @implemented NT5
329 *
330 * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
331 * to another list entry.
332 *
333 * @param NewEntry
334 * Pointer to a list entry where the satisfied waits will be added.
335 *
336 * @param WaitList
337 * Pointer to a list entry to analyze for satisfied waits.
338 *
339 * @return None.
340 *
341 * @remarks None.
342 *
343 *--*/
344 VOID
345 NTAPI
346 CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry,
347 IN PLIST_ENTRY WaitList)
348 {
349 PLIST_ENTRY NextEntry;
350 PCSR_WAIT_BLOCK WaitBlock;
351
352 /* Acquire the Wait Lock */
353 CsrAcquireWaitLock();
354
355 /* Set the List pointers */
356 NextEntry = WaitList->Flink;
357
358 /* Start looping */
359 while (NextEntry != WaitList)
360 {
361 /* Get the Wait block */
362 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
363
364 /* Go to the next entry */
365 NextEntry = NextEntry->Flink;
366
367 /* Check if there is a Wait Callback */
368 if (WaitBlock->WaitFunction)
369 {
370 /* Remove it from the Wait Block Queue */
371 RemoveEntryList(&WaitBlock->WaitList);
372
373 /* Insert the new entry */
374 InsertTailList(&WaitBlock->WaitList, NewEntry);
375 }
376 }
377
378 /* Release the wait lock */
379 CsrReleaseWaitLock();
380 }
381
382 /*++
383 * @name CsrNotifyWait
384 * @implemented NT4
385 *
386 * The CsrNotifyWait notifies a CSR Wait Block.
387 *
388 * @param WaitList
389 * Pointer to the list entry for this wait.
390 *
391 * @param WaitType
392 * Type of the wait to perform, either WaitAny or WaitAll.
393 *
394 * @param WaitArgument[1-2]
395 * User-defined argument to pass on to the wait function.
396 *
397 * @return TRUE in case of success, FALSE otherwise.
398 *
399 * @remarks None.
400 *
401 *--*/
402 BOOLEAN
403 NTAPI
404 CsrNotifyWait(IN PLIST_ENTRY WaitList,
405 IN ULONG WaitType,
406 IN PVOID WaitArgument1,
407 IN PVOID WaitArgument2)
408 {
409 PLIST_ENTRY NextEntry;
410 PCSR_WAIT_BLOCK WaitBlock;
411 BOOLEAN NotifySuccess = FALSE;
412
413 /* Acquire the Wait Lock */
414 CsrAcquireWaitLock();
415
416 /* Set the List pointers */
417 NextEntry = WaitList->Flink;
418
419 /* Start looping */
420 while (NextEntry != WaitList)
421 {
422 /* Get the Wait block */
423 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
424
425 /* Go to the next entry */
426 NextEntry = NextEntry->Flink;
427
428 /* Check if there is a Wait Callback */
429 if (WaitBlock->WaitFunction)
430 {
431 /* Notify the Waiter */
432 NotifySuccess |= CsrNotifyWaitBlock(WaitBlock,
433 WaitList,
434 WaitArgument1,
435 WaitArgument2,
436 0,
437 FALSE);
438
439 /* We've already done a wait, so leave unless this is a Wait All */
440 if (WaitType != WaitAll) break;
441 }
442 }
443
444 /* Release the wait lock and return */
445 CsrReleaseWaitLock();
446 return NotifySuccess;
447 }
448
449 /* EOF */