Registry entries for shell folders
[reactos.git] / reactos / subsys / csr / csrsrv / wait.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsys/csr/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 othwerwise.
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 if (!(WaitBlock = RtlAllocateHeap(CsrHeap, 0, Size)))
66 {
67 /* Fail */
68 WaitApiMessage->Status = STATUS_NO_MEMORY;
69 return FALSE;
70 }
71
72 /* Initialize it */
73 WaitBlock->Size = Size;
74 WaitBlock->WaitThread = CsrWaitThread;
75 WaitBlock->WaitContext = WaitContext;
76 WaitBlock->WaitFunction = WaitFunction;
77 InitializeListHead(&WaitBlock->UserWaitList);
78 InitializeListHead(&WaitBlock->WaitList);
79
80 /* Copy the message */
81 RtlMoveMemory(&WaitBlock->WaitApiMessage,
82 WaitApiMessage,
83 WaitApiMessage->Header.u1.s1.TotalLength);
84
85 /* Return the block */
86 *NewWaitBlock = WaitBlock;
87 return TRUE;
88 }
89
90 /*++
91 * @name CsrNotifyWaitBlock
92 *
93 * The CsrNotifyWaitBlock routine calls the wait function for a registered
94 * CSR Wait Block, and replies to the attached CSR API Message, if any.
95 *
96 * @param WaitBlock
97 * Pointer to the CSR Wait Block
98 *
99 * @param WaitList
100 * Pointer to the wait list for this wait.
101 *
102 * @param WaitArgument[1-2]
103 * User-defined values to pass to the wait function.
104 *
105 * @param WaitFlags
106 * Wait flags for this wait.
107 *
108 * @param DereferenceThread
109 * Specifies whether the CSR Thread should be dereferenced at the
110 * end of this wait.
111 *
112 * @return TRUE in case of success, FALSE otherwise.
113 *
114 * @remarks After a wait block is notified, the wait function becomes invalid.
115 *
116 *--*/
117 BOOLEAN
118 NTAPI
119 CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
120 IN PLIST_ENTRY WaitList,
121 IN PVOID WaitArgument1,
122 IN PVOID WaitArgument2,
123 IN ULONG WaitFlags,
124 IN BOOLEAN DereferenceThread)
125 {
126 /* Call the wait function */
127 if ((WaitBlock->WaitFunction)(WaitList,
128 WaitBlock->WaitThread,
129 &WaitBlock->WaitApiMessage,
130 WaitBlock->WaitContext,
131 WaitArgument1,
132 WaitArgument2,
133 WaitFlags))
134 {
135 /* The wait is done, clear the block */
136 WaitBlock->WaitThread->WaitBlock = NULL;
137
138 /* Check for captured arguments */
139 if (WaitBlock->WaitApiMessage.CsrCaptureData)
140 {
141 /* Release them */
142 CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage);
143 }
144
145 /* Reply to the port */
146 NtReplyPort(WaitBlock->WaitThread->Process->ClientPort,
147 (PPORT_MESSAGE)&WaitBlock->WaitApiMessage);
148
149 /* Check if we should dereference the thread */
150 if (DereferenceThread)
151 {
152 /* Remove it from the Wait List */
153 if (WaitBlock->WaitList.Flink)
154 {
155 RemoveEntryList(&WaitBlock->WaitList);
156 }
157
158 /* Remove it from the User Wait List */
159 if (WaitBlock->UserWaitList.Flink)
160 {
161 RemoveEntryList(&WaitBlock->UserWaitList);
162 }
163
164 /* Dereference teh thread */
165 CsrDereferenceThread(WaitBlock->WaitThread);
166
167 /* Free the wait block */
168 RtlFreeHeap(CsrHeap, 0, WaitBlock);
169 }
170 else
171 {
172 /* The wait is complete, but the thread is being kept alive */
173 WaitBlock->WaitFunction = NULL;
174 }
175
176 /* The wait suceeded*/
177 return TRUE;
178 }
179
180 /* The wait failed */
181 return FALSE;
182 }
183
184 /* PUBLIC FUNCTIONS **********************************************************/
185
186 /*++
187 * @name CsrCreateWait
188 * @implemented NT4
189 *
190 * The CsrCreateWait routine creates a CSR Wait.
191 *
192 * @param WaitList
193 * Pointer to a list entry of the waits to associate.
194 *
195 * @param WaitFunction
196 * Pointer to the function that will handle this wait.
197 *
198 * @param CsrWaitThread
199 * Pointer to the CSR Thread that will perform the wait.
200 *
201 * @param WaitApiMessage
202 * Pointer to the CSR API Message associated to this wait.
203 *
204 * @param WaitContext
205 * Pointer to a user-defined parameter associated to this wait.
206 *
207 * @param UserWaitList
208 * Pointer to a list entry of the user-defined waits to associate.
209 *
210 * @return TRUE in case of success, FALSE otherwise.
211 *
212 * @remarks None.
213 *
214 *--*/
215 BOOLEAN
216 NTAPI
217 CsrCreateWait(IN PLIST_ENTRY WaitList,
218 IN CSR_WAIT_FUNCTION WaitFunction,
219 IN PCSR_THREAD CsrWaitThread,
220 IN OUT PCSR_API_MESSAGE WaitApiMessage,
221 IN PVOID WaitContext,
222 IN PLIST_ENTRY UserWaitList OPTIONAL)
223 {
224 PCSR_WAIT_BLOCK WaitBlock;
225
226 /* Initialize the wait */
227 if (!CsrInitializeWait(WaitFunction,
228 CsrWaitThread,
229 WaitApiMessage,
230 WaitContext,
231 &WaitBlock))
232 {
233 return FALSE;
234 }
235
236 /* Acquire the Wait Lock */
237 CsrAcquireWaitLock();
238
239 /* Make sure the thread wasn't destroyed */
240 if (CsrWaitThread && (CsrWaitThread->Flags & CsrThreadTerminated))
241 {
242 /* Fail the wait */
243 CsrWaitThread->WaitBlock = NULL;
244 RtlFreeHeap(CsrHeap, 0, WaitBlock);
245 CsrReleaseWaitLock();
246 return FALSE;
247 }
248
249 /* Insert the wait in the queue */
250 InsertTailList(WaitList, &WaitBlock->WaitList);
251
252 /* Insert the User Wait too, if one was given */
253 if (UserWaitList) InsertTailList(UserWaitList, &WaitBlock->UserWaitList);
254
255 /* Return */
256 CsrReleaseWaitLock();
257 return TRUE;
258 }
259
260 /*++
261 * @name CsrDereferenceWait
262 * @implemented NT4
263 *
264 * The CsrDereferenceWait routine derefences a CSR Wait Block.
265 *
266 * @param WaitList
267 * Pointer to the Wait List associated to the wait.
268
269 * @return None.
270 *
271 * @remarks None.
272 *
273 *--*/
274 VOID
275 NTAPI
276 CsrDereferenceWait(IN PLIST_ENTRY WaitList)
277 {
278 PLIST_ENTRY ListHead, NextEntry;
279 PCSR_WAIT_BLOCK WaitBlock;
280
281 /* Acquire the Process and Wait Locks */
282 CsrAcquireProcessLock();
283 CsrAcquireWaitLock();
284
285 /* Set the list pointers */
286 ListHead = WaitList;
287 NextEntry = ListHead->Flink;
288
289 /* Start the loop */
290 while (NextEntry != ListHead)
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 ListHead, NextEntry;
350 PCSR_WAIT_BLOCK WaitBlock;
351
352 /* Acquire the Wait Lock */
353 CsrAcquireWaitLock();
354
355 /* Set the List pointers */
356 ListHead = WaitList;
357 NextEntry = ListHead->Flink;
358
359 /* Start looping */
360 while (NextEntry != ListHead)
361 {
362 /* Get the Wait block */
363 WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
364
365 /* Go to the next entry */
366 NextEntry = NextEntry->Flink;
367
368 /* Check if there is a Wait Callback */
369 if (WaitBlock->WaitFunction)
370 {
371 /* Remove it from the Wait Block Queue */
372 RemoveEntryList(&WaitBlock->WaitList);
373
374 /* Insert the new entry */
375 InsertTailList(&WaitBlock->WaitList, NewEntry);
376 }
377 }
378
379 /* Release the wait lock */
380 CsrReleaseWaitLock();
381 }
382
383 /*++
384 * @name CsrNotifyWait
385 * @implemented NT4
386 *
387 * The CsrNotifyWait notifies a CSR Wait Block.
388 *
389 * @param WaitList
390 * Pointer to the list entry for this wait.
391 *
392 * @param WaitType
393 * Type of the wait to perform, either WaitAny or WaitAll.
394 *
395 * @param WaitArgument[1-2]
396 * User-defined argument to pass on to the wait function.
397 *
398 * @return TRUE in case of success, FALSE othwerwise.
399 *
400 * @remarks None.
401 *
402 *--*/
403 BOOLEAN
404 NTAPI
405 CsrNotifyWait(IN PLIST_ENTRY WaitList,
406 IN ULONG WaitType,
407 IN PVOID WaitArgument1,
408 IN PVOID WaitArgument2)
409 {
410 PLIST_ENTRY ListHead, NextEntry;
411 PCSR_WAIT_BLOCK WaitBlock;
412 BOOLEAN NotifySuccess = FALSE;
413
414 /* Acquire the Wait Lock */
415 CsrAcquireWaitLock();
416
417 /* Set the List pointers */
418 ListHead = WaitList;
419 NextEntry = ListHead->Flink;
420
421 /* Start looping */
422 while (NextEntry != ListHead)
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 Callback */
431 if (WaitBlock->WaitFunction)
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 */