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