1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel 4 * FILE: ntoskrnl/ex/rundown.c 5 * PURPOSE: Rundown and Cache-Aware Rundown Protection 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Thomas Weidenmueller 8 * Pierre Schweitzer 9 */ 10 11 /* INCLUDES *****************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* FUNCTIONS *****************************************************************/ 18 19 /*++ 20 * @name ExfAcquireRundownProtection 21 * @implemented NT5.1 22 * 23 * The ExfAcquireRundownProtection routine acquires rundown protection for 24 * the specified descriptor. 25 * 26 * @param RunRef 27 * Pointer to a rundown reference descriptor. 28 * 29 * @return TRUE if access to the protected structure was granted, FALSE otherwise. 30 * 31 * @remarks Callers of ExfAcquireRundownProtection can be running at any IRQL. 32 * 33 *--*/ 34 BOOLEAN 35 FASTCALL 36 ExfAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef) 37 { 38 ULONG_PTR Value = RunRef->Count, NewValue; 39 40 /* Loop until successfully incremented the counter */ 41 for (;;) 42 { 43 /* Make sure a rundown is not active */ 44 if (Value & EX_RUNDOWN_ACTIVE) return FALSE; 45 46 /* Add a reference */ 47 NewValue = Value + EX_RUNDOWN_COUNT_INC; 48 49 /* Change the value */ 50 NewValue = ExpChangeRundown(RunRef, NewValue, Value); 51 if (NewValue == Value) return TRUE; 52 53 /* Update it */ 54 Value = NewValue; 55 } 56 } 57 58 /*++ 59 * @name ExfAcquireRundownProtectionEx 60 * @implemented NT5.2 61 * 62 * The ExfAcquireRundownProtectionEx routine acquires multiple rundown 63 * protection references for the specified descriptor. 64 * 65 * @param RunRef 66 * Pointer to a rundown reference descriptor. 67 * 68 * @param Count 69 * Number of times to reference the descriptor. 70 * 71 * @return TRUE if access to the protected structure was granted, FALSE otherwise. 72 * 73 * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL. 74 * 75 *--*/ 76 BOOLEAN 77 FASTCALL 78 ExfAcquireRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef, 79 IN ULONG Count) 80 { 81 ULONG_PTR Value = RunRef->Count, NewValue; 82 83 /* Loop until successfully incremented the counter */ 84 for (;;) 85 { 86 /* Make sure a rundown is not active */ 87 if (Value & EX_RUNDOWN_ACTIVE) return FALSE; 88 89 /* Add references */ 90 NewValue = Value + EX_RUNDOWN_COUNT_INC * Count; 91 92 /* Change the value */ 93 NewValue = ExpChangeRundown(RunRef, NewValue, Value); 94 if (NewValue == Value) return TRUE; 95 96 /* Update the value */ 97 Value = NewValue; 98 } 99 } 100 101 /*++ 102 * @name ExfInitializeRundownProtection 103 * @implemented NT5.1 104 * 105 * The ExfInitializeRundownProtection routine initializes a rundown 106 * protection descriptor. 107 * 108 * @param RunRef 109 * Pointer to a rundown reference descriptor. 110 * 111 * @return None. 112 * 113 * @remarks Callers of ExfInitializeRundownProtection can be running at any IRQL. 114 * 115 *--*/ 116 VOID 117 FASTCALL 118 ExfInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef) 119 { 120 /* Set the count to zero */ 121 RunRef->Count = 0; 122 } 123 124 /*++ 125 * @name ExfReInitializeRundownProtection 126 * @implemented NT5.1 127 * 128 * The ExfReInitializeRundownProtection routine re-initializes a rundown 129 * protection descriptor. 130 * 131 * @param RunRef 132 * Pointer to a rundown reference descriptor. 133 * 134 * @return None. 135 * 136 * @remarks Callers of ExfReInitializeRundownProtection can be running at any IRQL. 137 * 138 *--*/ 139 VOID 140 FASTCALL 141 ExfReInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef) 142 { 143 PAGED_CODE(); 144 145 /* Sanity check */ 146 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0); 147 148 /* Reset the count */ 149 ExpSetRundown(RunRef, 0); 150 } 151 152 /*++ 153 * @name ExfRundownCompleted 154 * @implemented NT5.1 155 * 156 * The ExfRundownCompleted routine completes the rundown of the specified 157 * descriptor by setting the active bit. 158 * 159 * @param RunRef 160 * Pointer to a rundown reference descriptor. 161 * 162 * @return None. 163 * 164 * @remarks Callers of ExfRundownCompleted must be running at IRQL <= APC_LEVEL. 165 * 166 *--*/ 167 VOID 168 FASTCALL 169 ExfRundownCompleted(IN PEX_RUNDOWN_REF RunRef) 170 { 171 PAGED_CODE(); 172 173 /* Sanity check */ 174 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0); 175 176 /* Mark the counter as active */ 177 ExpSetRundown(RunRef, EX_RUNDOWN_ACTIVE); 178 } 179 180 /*++ 181 * @name ExfReleaseRundownProtection 182 * @implemented NT5.1 183 * 184 * The ExfReleaseRundownProtection routine releases the rundown protection 185 * reference for the specified descriptor. 186 * 187 * @param RunRef 188 * Pointer to a rundown reference descriptor. 189 * 190 * @return None. 191 * 192 * @remarks Callers of ExfReleaseRundownProtection can be running at any IRQL. 193 * 194 *--*/ 195 VOID 196 FASTCALL 197 ExfReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef) 198 { 199 ULONG_PTR Value = RunRef->Count, NewValue; 200 PEX_RUNDOWN_WAIT_BLOCK WaitBlock; 201 202 /* Loop until successfully incremented the counter */ 203 for (;;) 204 { 205 /* Check if rundown is not active */ 206 if (!(Value & EX_RUNDOWN_ACTIVE)) 207 { 208 /* Sanity check */ 209 ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1)); 210 211 /* Get the new value */ 212 NewValue = Value - EX_RUNDOWN_COUNT_INC; 213 214 /* Change the value */ 215 NewValue = ExpChangeRundown(RunRef, NewValue, Value); 216 if (NewValue == Value) break; 217 218 /* Update value */ 219 Value = NewValue; 220 } 221 else 222 { 223 /* Get the wait block */ 224 WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE); 225 ASSERT((WaitBlock->Count > 0) || (KeNumberProcessors > 1)); 226 227 /* Remove the one count */ 228 if (!InterlockedDecrementSizeT(&WaitBlock->Count)) 229 { 230 /* We're down to 0 now, so signal the event */ 231 KeSetEvent(&WaitBlock->WakeEvent, IO_NO_INCREMENT, FALSE); 232 } 233 234 /* We're all done */ 235 break; 236 } 237 } 238 } 239 240 /*++ 241 * @name ExfReleaseRundownProtectionEx 242 * @implemented NT5.2 243 * 244 * The ExfReleaseRundownProtectionEx routine releases multiple rundown 245 * protection references for the specified descriptor. 246 * 247 * @param RunRef 248 * Pointer to a rundown reference descriptor. 249 * 250 * @param Count 251 * Number of times to dereference the descriptor. 252 * 253 * @return None. 254 * 255 * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL. 256 * 257 *--*/ 258 VOID 259 FASTCALL 260 ExfReleaseRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef, 261 IN ULONG Count) 262 { 263 ULONG_PTR Value = RunRef->Count, NewValue; 264 PEX_RUNDOWN_WAIT_BLOCK WaitBlock; 265 266 /* Loop until successfully incremented the counter */ 267 for (;;) 268 { 269 /* Check if rundown is not active */ 270 if (!(Value & EX_RUNDOWN_ACTIVE)) 271 { 272 /* Sanity check */ 273 ASSERT((Value >= EX_RUNDOWN_COUNT_INC * Count) || 274 (KeNumberProcessors > 1)); 275 276 /* Get the new value */ 277 NewValue = Value - EX_RUNDOWN_COUNT_INC * Count; 278 279 /* Change the value */ 280 NewValue = ExpChangeRundown(RunRef, NewValue, Value); 281 if (NewValue == Value) break; 282 283 /* Update value */ 284 Value = NewValue; 285 } 286 else 287 { 288 /* Get the wait block */ 289 WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE); 290 ASSERT((WaitBlock->Count >= Count) || (KeNumberProcessors > 1)); 291 292 /* Remove the counts */ 293 if (InterlockedExchangeAddSizeT(&WaitBlock->Count, 294 -(LONG)Count) == (LONG)Count) 295 { 296 /* We're down to 0 now, so signal the event */ 297 KeSetEvent(&WaitBlock->WakeEvent, IO_NO_INCREMENT, FALSE); 298 } 299 300 /* We're all done */ 301 break; 302 } 303 } 304 } 305 306 /*++ 307 * @name ExfWaitForRundownProtectionRelease 308 * @implemented NT5.1 309 * 310 * The ExfWaitForRundownProtectionRelease routine waits until the specified 311 * rundown descriptor has been released. 312 * 313 * @param RunRef 314 * Pointer to a rundown reference descriptor. 315 * 316 * @return None. 317 * 318 * @remarks Callers of ExfWaitForRundownProtectionRelease must be running 319 * at IRQL <= APC_LEVEL. 320 * 321 *--*/ 322 VOID 323 FASTCALL 324 ExfWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef) 325 { 326 ULONG_PTR Value, Count, NewValue; 327 EX_RUNDOWN_WAIT_BLOCK WaitBlock; 328 PEX_RUNDOWN_WAIT_BLOCK WaitBlockPointer; 329 PKEVENT Event; 330 PAGED_CODE(); 331 332 /* Set the active bit */ 333 Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0); 334 if ((Value == 0) || (Value == EX_RUNDOWN_ACTIVE)) return; 335 336 /* No event for now */ 337 Event = NULL; 338 WaitBlockPointer = (PEX_RUNDOWN_WAIT_BLOCK)((ULONG_PTR)&WaitBlock | 339 EX_RUNDOWN_ACTIVE); 340 341 /* Start waitblock set loop */ 342 for (;;) 343 { 344 /* Save the count */ 345 Count = Value >> EX_RUNDOWN_COUNT_SHIFT; 346 347 /* If the count is over one and we don't have en event yet, create it */ 348 if ((Count) && !(Event)) 349 { 350 /* Initialize the event */ 351 KeInitializeEvent(&WaitBlock.WakeEvent, 352 SynchronizationEvent, 353 FALSE); 354 355 /* Set the pointer */ 356 Event = &WaitBlock.WakeEvent; 357 } 358 359 /* Set the count */ 360 WaitBlock.Count = Count; 361 362 /* Now set the pointer */ 363 NewValue = ExpChangeRundown(RunRef, (ULONG_PTR)WaitBlockPointer, Value); 364 if (NewValue == Value) break; 365 366 /* Loop again */ 367 Value = NewValue; 368 ASSERT((Value & EX_RUNDOWN_ACTIVE) == 0); 369 } 370 371 /* If the count was 0, we're done */ 372 if (!Count) return; 373 374 /* Wait for whoever needs to release to notify us */ 375 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); 376 ASSERT(WaitBlock.Count == 0); 377 } 378 379 /* 380 * @implemented NT5.2 381 */ 382 BOOLEAN 383 FASTCALL 384 ExfAcquireRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) 385 { 386 PEX_RUNDOWN_REF RunRef; 387 388 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber()); 389 return _ExAcquireRundownProtection(RunRef); 390 } 391 392 /* 393 * @implemented NT5.2 394 */ 395 BOOLEAN 396 FASTCALL 397 ExfAcquireRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware, 398 IN ULONG Count) 399 { 400 PEX_RUNDOWN_REF RunRef; 401 402 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber()); 403 return ExfAcquireRundownProtectionEx(RunRef, Count); 404 } 405 406 /* 407 * @implemented NT5.2 408 */ 409 VOID 410 FASTCALL 411 ExfReleaseRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) 412 { 413 PEX_RUNDOWN_REF RunRef; 414 415 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber()); 416 _ExReleaseRundownProtection(RunRef); 417 } 418 419 /* 420 * @implemented NT5.2 421 */ 422 VOID 423 FASTCALL 424 ExfReleaseRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware, 425 IN ULONG Count) 426 { 427 PEX_RUNDOWN_REF RunRef; 428 429 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber()); 430 ExfReleaseRundownProtectionEx(RunRef, Count); 431 } 432 433 /* 434 * @implemented NT5.2 435 */ 436 VOID 437 FASTCALL 438 ExfWaitForRundownProtectionReleaseCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) 439 { 440 PEX_RUNDOWN_REF RunRef; 441 EX_RUNDOWN_WAIT_BLOCK WaitBlock; 442 PEX_RUNDOWN_WAIT_BLOCK WaitBlockPointer; 443 ULONG ProcCount, Current, Value, OldValue, TotalCount; 444 445 ProcCount = RunRefCacheAware->Number; 446 /* No proc, nothing to do */ 447 if (ProcCount == 0) 448 { 449 return; 450 } 451 452 TotalCount = 0; 453 WaitBlock.Count = 0; 454 WaitBlockPointer = (PEX_RUNDOWN_WAIT_BLOCK)((ULONG_PTR)&WaitBlock | 455 EX_RUNDOWN_ACTIVE); 456 /* We will check all our runrefs */ 457 for (Current = 0; Current < ProcCount; ++Current) 458 { 459 /* Get the runref for the proc */ 460 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Current); 461 /* Loop for setting the wait block */ 462 do 463 { 464 Value = RunRef->Count; 465 ASSERT((Value & EX_RUNDOWN_ACTIVE) == 0); 466 467 /* Remove old value and set our waitblock instead */ 468 OldValue = ExpChangeRundown(RunRef, WaitBlockPointer, Value); 469 if (OldValue == Value) 470 { 471 break; 472 } 473 474 Value = OldValue; 475 } 476 while (TRUE); 477 478 /* Count the deleted values */ 479 TotalCount += Value; 480 } 481 482 /* Sanity check: we didn't overflow */ 483 ASSERT((LONG)TotalCount >= 0); 484 if (TotalCount != 0) 485 { 486 /* Init the waitblock event */ 487 KeInitializeEvent(&WaitBlock.WakeEvent, 488 SynchronizationEvent, 489 FALSE); 490 491 /* Do we have to wait? If so, go ahead! */ 492 if (InterlockedExchangeAddSizeT(&WaitBlock.Count, 493 (LONG)TotalCount >> EX_RUNDOWN_COUNT_SHIFT) == 494 -(LONG)(TotalCount >> EX_RUNDOWN_COUNT_SHIFT)) 495 { 496 KeWaitForSingleObject(&WaitBlock.WakeEvent, Executive, KernelMode, FALSE, NULL); 497 } 498 } 499 } 500 501 /* 502 * @implemented NT5.2 503 */ 504 VOID 505 FASTCALL 506 ExfRundownCompletedCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) 507 { 508 PEX_RUNDOWN_REF RunRef; 509 ULONG ProcCount, Current; 510 511 ProcCount = RunRefCacheAware->Number; 512 /* No proc, nothing to do */ 513 if (ProcCount == 0) 514 { 515 return; 516 } 517 518 /* We will mark all our runrefs active */ 519 for (Current = 0; Current < ProcCount; ++Current) 520 { 521 /* Get the runref for the proc */ 522 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Current); 523 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0); 524 525 ExpSetRundown(RunRef, EX_RUNDOWN_ACTIVE); 526 } 527 } 528 529 /* 530 * @implemented NT5.2 531 */ 532 VOID 533 FASTCALL 534 ExfReInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) 535 { 536 PEX_RUNDOWN_REF RunRef; 537 ULONG ProcCount, Current; 538 539 ProcCount = RunRefCacheAware->Number; 540 /* No proc, nothing to do */ 541 if (ProcCount == 0) 542 { 543 return; 544 } 545 546 /* We will mark all our runrefs inactive */ 547 for (Current = 0; Current < ProcCount; ++Current) 548 { 549 /* Get the runref for the proc */ 550 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Current); 551 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0); 552 553 ExpSetRundown(RunRef, 0); 554 } 555 } 556 557 /* 558 * @implemented NT5.2 559 */ 560 PEX_RUNDOWN_REF_CACHE_AWARE 561 NTAPI 562 ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType, 563 IN ULONG Tag) 564 { 565 PEX_RUNDOWN_REF RunRef; 566 PVOID PoolToFree, RunRefs; 567 ULONG RunRefSize, Count, Align; 568 PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware; 569 570 PAGED_CODE(); 571 572 /* Allocate the master structure */ 573 RunRefCacheAware = ExAllocatePoolWithTag(PoolType, sizeof(EX_RUNDOWN_REF_CACHE_AWARE), Tag); 574 if (RunRefCacheAware == NULL) 575 { 576 return NULL; 577 } 578 579 /* Compute the size of each runref */ 580 RunRefCacheAware->Number = KeNumberProcessors; 581 if (KeNumberProcessors <= 1) 582 { 583 RunRefSize = sizeof(EX_RUNDOWN_REF); 584 } 585 else 586 { 587 Align = KeGetRecommendedSharedDataAlignment(); 588 RunRefSize = Align; 589 ASSERT((RunRefSize & (RunRefSize - 1)) == 0); 590 } 591 592 /* It must at least hold a EX_RUNDOWN_REF structure */ 593 ASSERT(sizeof(EX_RUNDOWN_REF) <= RunRefSize); 594 RunRefCacheAware->RunRefSize = RunRefSize; 595 596 /* Allocate our runref pool */ 597 PoolToFree = ExAllocatePoolWithTag(PoolType, RunRefSize * RunRefCacheAware->Number, Tag); 598 if (PoolToFree == NULL) 599 { 600 ExFreePoolWithTag(RunRefCacheAware, Tag); 601 return NULL; 602 } 603 604 /* On SMP, check for alignment */ 605 if (RunRefCacheAware->Number > 1 && (ULONG_PTR)PoolToFree & (Align - 1)) 606 { 607 /* Not properly aligned, do it again! */ 608 ExFreePoolWithTag(PoolToFree, Tag); 609 610 /* Allocate a bigger buffer to be able to align properly */ 611 PoolToFree = ExAllocatePoolWithTag(PoolType, RunRefSize * (RunRefCacheAware->Number + 1), Tag); 612 if (PoolToFree == NULL) 613 { 614 ExFreePoolWithTag(RunRefCacheAware, Tag); 615 return NULL; 616 } 617 618 RunRefs = (PVOID)ALIGN_UP_BY(PoolToFree, Align); 619 } 620 else 621 { 622 RunRefs = PoolToFree; 623 } 624 625 RunRefCacheAware->RunRefs = RunRefs; 626 RunRefCacheAware->PoolToFree = PoolToFree; 627 628 /* And initialize runref */ 629 if (RunRefCacheAware->Number != 0) 630 { 631 for (Count = 0; Count < RunRefCacheAware->Number; ++Count) 632 { 633 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Count); 634 _ExInitializeRundownProtection(RunRef); 635 } 636 } 637 638 return RunRefCacheAware; 639 } 640 641 /* 642 * @implemented NT5.2 643 */ 644 VOID 645 NTAPI 646 ExFreeCacheAwareRundownProtection(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) 647 { 648 PAGED_CODE(); 649 650 /* 651 * This is to be called for RunRefCacheAware that were allocated with 652 * ExAllocateCacheAwareRundownProtection and not for user-allocated 653 * ones 654 */ 655 ASSERT(RunRefCacheAware->PoolToFree != (PVOID)0xBADCA11); 656 657 /* We don't know the tag that as used for allocation */ 658 ExFreePoolWithTag(RunRefCacheAware->PoolToFree, 0); 659 ExFreePoolWithTag(RunRefCacheAware, 0); 660 } 661 662 /* 663 * @implemented NT5.2 664 */ 665 VOID 666 NTAPI 667 ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware, 668 IN SIZE_T Size) 669 { 670 PVOID Pool; 671 PEX_RUNDOWN_REF RunRef; 672 ULONG Count, RunRefSize, Align; 673 674 PAGED_CODE(); 675 676 /* Get the user allocate pool for runrefs */ 677 Pool = (PVOID)((ULONG_PTR)RunRefCacheAware + sizeof(EX_RUNDOWN_REF_CACHE_AWARE)); 678 679 /* By default a runref is structure-sized */ 680 RunRefSize = sizeof(EX_RUNDOWN_REF); 681 682 /* 683 * If we just have enough room for a single runref, deduce were on a single 684 * processor machine 685 */ 686 if (Size == sizeof(EX_RUNDOWN_REF_CACHE_AWARE) + sizeof(EX_RUNDOWN_REF)) 687 { 688 Count = 1; 689 } 690 else 691 { 692 /* Get alignment constraint */ 693 Align = KeGetRecommendedSharedDataAlignment(); 694 695 /* How many runrefs given the alignment? */ 696 RunRefSize = Align; 697 Count = ((Size - sizeof(EX_RUNDOWN_REF_CACHE_AWARE)) / Align) - 1; 698 Pool = (PVOID)ALIGN_UP_BY(Pool, Align); 699 } 700 701 /* Initialize the structure */ 702 RunRefCacheAware->RunRefs = Pool; 703 RunRefCacheAware->RunRefSize = RunRefSize; 704 RunRefCacheAware->Number = Count; 705 706 /* There is no allocated pool! */ 707 RunRefCacheAware->PoolToFree = (PVOID)0xBADCA11u; 708 709 /* Initialize runref */ 710 if (RunRefCacheAware->Number != 0) 711 { 712 for (Count = 0; Count < RunRefCacheAware->Number; ++Count) 713 { 714 RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Count); 715 _ExInitializeRundownProtection(RunRef); 716 } 717 } 718 } 719 720 /* 721 * @implemented NT5.2 722 */ 723 SIZE_T 724 NTAPI 725 ExSizeOfRundownProtectionCacheAware(VOID) 726 { 727 SIZE_T Size; 728 729 PAGED_CODE(); 730 731 /* Compute the needed size for runrefs */ 732 if (KeNumberProcessors <= 1) 733 { 734 Size = sizeof(EX_RUNDOWN_REF); 735 } 736 else 737 { 738 /* We +1, to have enough room for alignment */ 739 Size = (KeNumberProcessors + 1) * KeGetRecommendedSharedDataAlignment(); 740 } 741 742 /* Return total size (master structure and runrefs) */ 743 return Size + sizeof(EX_RUNDOWN_REF_CACHE_AWARE); 744 } 745 746