xref: /reactos/subsystems/csr/csrsrv/wait.c (revision 84344399)
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 NotifyAll
376  *        Whether or not we must notify all the waits.
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 BOOLEAN NotifyAll,
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             /*
424              * We've already done a wait, so leave unless
425              * we want to notify all the waits...
426              */
427             if (!NotifyAll) break;
428         }
429     }
430 
431     /* Release the wait lock and return */
432     CsrReleaseWaitLock();
433     return NotifySuccess;
434 }
435 
436 /* EOF */
437