Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

resource.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989-1993 Microsoft Corporation 00004 00005 Module Name: 00006 00007 Resource.c 00008 00009 Abstract: 00010 00011 This module implements the executive functions to acquire and release 00012 a shared resource. 00013 00014 Author: 00015 00016 Mark Lucovsky (markl) 04-Aug-1989 00017 00018 Environment: 00019 00020 These routines are statically linked in the caller's executable and 00021 are callable in only from user mode. They make use of Nt system 00022 services. 00023 00024 Revision History: 00025 00026 --*/ 00027 00028 #include <ntos.h> 00029 #include <ntrtl.h> 00030 #include <nturtl.h> 00031 #include <heap.h> 00032 #include "ldrp.h" 00033 00034 // 00035 // Define the desired access for semaphores. 00036 // 00037 00038 #define DESIRED_EVENT_ACCESS \ 00039 (EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE) 00040 00041 #define DESIRED_SEMAPHORE_ACCESS \ 00042 (SEMAPHORE_QUERY_STATE | SEMAPHORE_MODIFY_STATE | SYNCHRONIZE) 00043 00044 VOID RtlDumpResource( IN PRTL_RESOURCE Resource ); 00045 00046 extern BOOLEAN LdrpShutdownInProgress; 00047 extern HANDLE LdrpShutdownThreadId; 00048 00049 VOID 00050 RtlpInitDeferedCriticalSection( VOID ); 00051 RTL_CRITICAL_SECTION DeferedCriticalSection; 00052 00053 #if DBG 00054 BOOLEAN 00055 ProtectHandle( 00056 HANDLE hObject 00057 ) 00058 { 00059 NTSTATUS Status; 00060 OBJECT_HANDLE_FLAG_INFORMATION HandleInfo; 00061 00062 Status = NtQueryObject( hObject, 00063 ObjectHandleFlagInformation, 00064 &HandleInfo, 00065 sizeof( HandleInfo ), 00066 NULL 00067 ); 00068 if (NT_SUCCESS( Status )) { 00069 HandleInfo.ProtectFromClose = TRUE; 00070 00071 Status = NtSetInformationObject( hObject, 00072 ObjectHandleFlagInformation, 00073 &HandleInfo, 00074 sizeof( HandleInfo ) 00075 ); 00076 if (NT_SUCCESS( Status )) { 00077 return TRUE; 00078 } 00079 } 00080 00081 return FALSE; 00082 } 00083 00084 00085 BOOLEAN 00086 UnProtectHandle( 00087 HANDLE hObject 00088 ) 00089 { 00090 NTSTATUS Status; 00091 OBJECT_HANDLE_FLAG_INFORMATION HandleInfo; 00092 00093 Status = NtQueryObject( hObject, 00094 ObjectHandleFlagInformation, 00095 &HandleInfo, 00096 sizeof( HandleInfo ), 00097 NULL 00098 ); 00099 if (NT_SUCCESS( Status )) { 00100 HandleInfo.ProtectFromClose = FALSE; 00101 00102 Status = NtSetInformationObject( hObject, 00103 ObjectHandleFlagInformation, 00104 &HandleInfo, 00105 sizeof( HandleInfo ) 00106 ); 00107 if (NT_SUCCESS( Status )) { 00108 return TRUE; 00109 } 00110 } 00111 00112 return FALSE; 00113 } 00114 #endif // DBG 00115 00116 RTL_CRITICAL_SECTION_DEBUG RtlpStaticDebugInfo[ 64 ]; 00117 PRTL_CRITICAL_SECTION_DEBUG RtlpDebugInfoFreeList; 00118 BOOLEAN RtlpCritSectInitialized; 00119 00120 PRTL_CRITICAL_SECTION_DEBUG 00121 RtlpChainDebugInfo( 00122 IN PVOID BaseAddress, 00123 IN ULONG Size 00124 ) 00125 { 00126 PRTL_CRITICAL_SECTION_DEBUG p, p1; 00127 00128 if (Size = Size / sizeof( RTL_CRITICAL_SECTION_DEBUG )) { 00129 p = (PRTL_CRITICAL_SECTION_DEBUG)BaseAddress + Size - 1; 00130 *(PRTL_CRITICAL_SECTION_DEBUG *)p = NULL; 00131 while (--Size) { 00132 p1 = p - 1; 00133 *(PRTL_CRITICAL_SECTION_DEBUG *)p1 = p; 00134 p = p1; 00135 } 00136 } 00137 00138 return p; 00139 } 00140 00141 00142 PVOID 00143 RtlpAllocateDebugInfo( VOID ); 00144 00145 VOID 00146 RtlpFreeDebugInfo( 00147 IN PVOID DebugInfo 00148 ); 00149 00150 PVOID 00151 RtlpAllocateDebugInfo( VOID ) 00152 { 00153 PRTL_CRITICAL_SECTION_DEBUG p; 00154 PPEB Peb; 00155 00156 00157 if (RtlpCritSectInitialized) { 00158 RtlEnterCriticalSection(&DeferedCriticalSection); 00159 } 00160 try { 00161 p = RtlpDebugInfoFreeList; 00162 if (p == NULL) { 00163 Peb = NtCurrentPeb(); 00164 p = RtlAllocateHeap(Peb->ProcessHeap,0,PAGE_SIZE-HEAP_GRANULARITY); 00165 if ( !p ) { 00166 KdPrint(( "NTDLL: Unable to allocate debug information from heap\n")); 00167 } 00168 else { 00169 p = RtlpChainDebugInfo( p, PAGE_SIZE-HEAP_GRANULARITY ); 00170 } 00171 } 00172 00173 if (p != NULL) { 00174 RtlpDebugInfoFreeList = *(PRTL_CRITICAL_SECTION_DEBUG *)p; 00175 } 00176 } 00177 finally { 00178 if (RtlpCritSectInitialized) { 00179 RtlLeaveCriticalSection(&DeferedCriticalSection); 00180 } 00181 } 00182 00183 return p; 00184 } 00185 00186 00187 VOID 00188 RtlpFreeDebugInfo( 00189 IN PVOID DebugInfo 00190 ) 00191 { 00192 RtlEnterCriticalSection(&DeferedCriticalSection); 00193 try { 00194 RtlZeroMemory( DebugInfo, sizeof( RTL_CRITICAL_SECTION_DEBUG ) ); 00195 *(PRTL_CRITICAL_SECTION_DEBUG *)DebugInfo = RtlpDebugInfoFreeList; 00196 RtlpDebugInfoFreeList = (PRTL_CRITICAL_SECTION_DEBUG)DebugInfo; 00197 } 00198 finally { 00199 RtlLeaveCriticalSection(&DeferedCriticalSection); 00200 } 00201 00202 return; 00203 } 00204 00205 VOID 00206 RtlpCreateCriticalSectionSem( 00207 IN PRTL_CRITICAL_SECTION CriticalSection 00208 ); 00209 00210 VOID 00211 RtlpInitDeferedCriticalSection( VOID ) 00212 { 00213 00214 InitializeListHead( &RtlCriticalSectionList ); 00215 00216 if (sizeof( RTL_CRITICAL_SECTION_DEBUG ) != sizeof( RTL_RESOURCE_DEBUG )) { 00217 DbgPrint( "NTDLL: Critical Section & Resource Debug Info length mismatch.\n" ); 00218 return; 00219 } 00220 00221 RtlpDebugInfoFreeList = RtlpChainDebugInfo( RtlpStaticDebugInfo, 00222 sizeof( RtlpStaticDebugInfo ) 00223 ); 00224 00225 RtlInitializeCriticalSectionAndSpinCount( &RtlCriticalSectionLock, 1000 ); 00226 RtlInitializeCriticalSectionAndSpinCount( &DeferedCriticalSection, 1000 ); 00227 00228 RtlpCreateCriticalSectionSem(&DeferedCriticalSection); 00229 00230 RtlpCritSectInitialized = TRUE; 00231 return; 00232 } 00233 00234 00235 BOOLEAN 00236 NtdllOkayToLockRoutine( 00237 IN PVOID Lock 00238 ) 00239 { 00240 return TRUE; 00241 } 00242 00243 00244 00245 00246 VOID 00247 RtlInitializeResource( 00248 IN PRTL_RESOURCE Resource 00249 ) 00250 00251 /*++ 00252 00253 Routine Description: 00254 00255 This routine initializes the input resource variable 00256 00257 Arguments: 00258 00259 Resource - Supplies the resource variable being initialized 00260 00261 Return Value: 00262 00263 None 00264 00265 --*/ 00266 00267 { 00268 NTSTATUS Status; 00269 PRTL_RESOURCE_DEBUG ResourceDebugInfo; 00270 00271 // 00272 // Initialize the lock fields, the count indicates how many are waiting 00273 // to enter or are in the critical section, LockSemaphore is the object 00274 // to wait on when entering the critical section. SpinLock is used 00275 // for the add interlock instruction. 00276 // 00277 00278 Status = RtlInitializeCriticalSectionAndSpinCount( &Resource->CriticalSection, 1000 ); 00279 if ( !NT_SUCCESS(Status) ){ 00280 RtlRaiseStatus(Status); 00281 } 00282 00283 Resource->CriticalSection.DebugInfo->Type = RTL_RESOURCE_TYPE; 00284 ResourceDebugInfo = (PRTL_RESOURCE_DEBUG) 00285 RtlpAllocateDebugInfo(); 00286 00287 if (ResourceDebugInfo == NULL) { 00288 RtlRaiseStatus(STATUS_NO_MEMORY); 00289 } 00290 00291 ResourceDebugInfo->ContentionCount = 0; 00292 Resource->DebugInfo = ResourceDebugInfo; 00293 00294 // 00295 // Initialize flags so there is a default value. 00296 // (Some apps may set RTL_RESOURCE_FLAGS_LONG_TERM to affect timeouts.) 00297 // 00298 00299 Resource->Flags = 0; 00300 00301 00302 // 00303 // Initialize the shared and exclusive waiting counters and semaphore. 00304 // The counters indicate how many are waiting for access to the resource 00305 // and the semaphores are used to wait on the resource. Note that 00306 // the semaphores can also indicate the number waiting for a resource 00307 // however there is a race condition in the alogrithm on the acquire 00308 // side if count if not updated before the critical section is exited. 00309 // 00310 00311 Status = NtCreateSemaphore( 00312 &Resource->SharedSemaphore, 00313 DESIRED_SEMAPHORE_ACCESS, 00314 NULL, 00315 0, 00316 MAXLONG 00317 ); 00318 if ( !NT_SUCCESS(Status) ){ 00319 RtlRaiseStatus(Status); 00320 } 00321 00322 Resource->NumberOfWaitingShared = 0; 00323 00324 Status = NtCreateSemaphore( 00325 &Resource->ExclusiveSemaphore, 00326 DESIRED_SEMAPHORE_ACCESS, 00327 NULL, 00328 0, 00329 MAXLONG 00330 ); 00331 if ( !NT_SUCCESS(Status) ){ 00332 RtlRaiseStatus(Status); 00333 } 00334 00335 Resource->NumberOfWaitingExclusive = 0; 00336 00337 // 00338 // Initialize the current state of the resource 00339 // 00340 00341 Resource->NumberOfActive = 0; 00342 00343 Resource->ExclusiveOwnerThread = NULL; 00344 00345 return; 00346 } 00347 00348 00349 BOOLEAN 00350 RtlAcquireResourceShared( 00351 IN PRTL_RESOURCE Resource, 00352 IN BOOLEAN Wait 00353 ) 00354 00355 /*++ 00356 00357 Routine Description: 00358 00359 The routine acquires the resource for shared access. Upon return from 00360 the procedure the resource is acquired for shared access. 00361 00362 Arguments: 00363 00364 Resource - Supplies the resource to acquire 00365 00366 Wait - Indicates if the call is allowed to wait for the resource 00367 to become available for must return immediately 00368 00369 Return Value: 00370 00371 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 00372 00373 --*/ 00374 00375 { 00376 NTSTATUS Status; 00377 ULONG TimeoutCount = 0; 00378 PLARGE_INTEGER TimeoutTime = &RtlpTimeout; 00379 // 00380 // Enter the critical section 00381 // 00382 00383 RtlEnterCriticalSection(&Resource->CriticalSection); 00384 00385 // 00386 // If it is not currently acquired for exclusive use then we can acquire 00387 // the resource for shared access. Note that this can potentially 00388 // starve an exclusive waiter however, this is necessary given the 00389 // ability to recursively acquire the resource shared. Otherwise we 00390 // might/will reach a deadlock situation where a thread tries to acquire 00391 // the resource recusively shared but is blocked by an exclusive waiter. 00392 // 00393 // The test to reanable not starving an exclusive waiter is: 00394 // 00395 // if ((Resource->NumberOfWaitingExclusive == 0) && 00396 // (Resource->NumberOfActive >= 0)) { 00397 // 00398 00399 if (Resource->NumberOfActive >= 0) { 00400 00401 // 00402 // The resource is ours, so indicate that we have it and 00403 // exit the critical section 00404 // 00405 00406 Resource->NumberOfActive += 1; 00407 00408 RtlLeaveCriticalSection(&Resource->CriticalSection); 00409 00410 // 00411 // Otherwise check to see if this thread is the one currently holding 00412 // exclusive access to the resource. And if it is then we change 00413 // this shared request to an exclusive recusive request and grant 00414 // access to the resource. 00415 // 00416 00417 } else if (Resource->ExclusiveOwnerThread == NtCurrentTeb()->ClientId.UniqueThread) { 00418 00419 // 00420 // The resource is ours (recusively) so indicate that we have it 00421 // and exit the critial section 00422 // 00423 00424 Resource->NumberOfActive -= 1; 00425 00426 RtlLeaveCriticalSection(&Resource->CriticalSection); 00427 00428 // 00429 // Otherwise we'll have to wait for access. 00430 // 00431 00432 } else { 00433 00434 // 00435 // Check if we are allowed to wait or must return immedately, and 00436 // indicate that we didn't acquire the resource 00437 // 00438 00439 if (!Wait) { 00440 00441 RtlLeaveCriticalSection(&Resource->CriticalSection); 00442 00443 return FALSE; 00444 00445 } 00446 00447 // 00448 // Otherwise we need to wait to acquire the resource. 00449 // To wait we will increment the number of waiting shared, 00450 // release the lock, and wait on the shared semaphore 00451 // 00452 00453 Resource->NumberOfWaitingShared += 1; 00454 Resource->DebugInfo->ContentionCount++; 00455 00456 RtlLeaveCriticalSection(&Resource->CriticalSection); 00457 00458 rewait: 00459 if ( Resource->Flags & RTL_RESOURCE_FLAG_LONG_TERM ) { 00460 TimeoutTime = NULL; 00461 } 00462 Status = NtWaitForSingleObject( 00463 Resource->SharedSemaphore, 00464 FALSE, 00465 TimeoutTime 00466 ); 00467 if ( Status == STATUS_TIMEOUT ) { 00468 DbgPrint("RTL: Acquire Shared Sem Timeout %d(2 minutes)\n",TimeoutCount); 00469 DbgPrint("RTL: Resource at %p\n",Resource); 00470 TimeoutCount++; 00471 if ( TimeoutCount > 2 ) { 00472 PIMAGE_NT_HEADERS NtHeaders; 00473 00474 // 00475 // If the image is a Win32 image, then raise an exception and try to get to the 00476 // uae popup 00477 // 00478 00479 NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); 00480 00481 if (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || 00482 NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { 00483 EXCEPTION_RECORD ExceptionRecord; 00484 00485 ExceptionRecord.ExceptionCode = STATUS_POSSIBLE_DEADLOCK; 00486 ExceptionRecord.ExceptionFlags = 0; 00487 ExceptionRecord.ExceptionRecord = NULL; 00488 ExceptionRecord.ExceptionAddress = (PVOID)RtlRaiseException; 00489 ExceptionRecord.NumberParameters = 1; 00490 ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)Resource; 00491 RtlRaiseException(&ExceptionRecord); 00492 } 00493 else { 00494 DbgBreakPoint(); 00495 } 00496 } 00497 DbgPrint("RTL: Re-Waiting\n"); 00498 goto rewait; 00499 } 00500 if ( !NT_SUCCESS(Status) ) { 00501 RtlRaiseStatus(Status); 00502 } 00503 } 00504 00505 // 00506 // Now the resource is ours, for shared access 00507 // 00508 00509 return TRUE; 00510 00511 } 00512 00513 00514 BOOLEAN 00515 RtlAcquireResourceExclusive( 00516 IN PRTL_RESOURCE Resource, 00517 IN BOOLEAN Wait 00518 ) 00519 00520 /*++ 00521 00522 Routine Description: 00523 00524 The routine acquires the resource for exclusive access. Upon return from 00525 the procedure the resource is acquired for exclusive access. 00526 00527 Arguments: 00528 00529 Resource - Supplies the resource to acquire 00530 00531 Wait - Indicates if the call is allowed to wait for the resource 00532 to become available for must return immediately 00533 00534 Return Value: 00535 00536 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 00537 00538 --*/ 00539 00540 { 00541 NTSTATUS Status; 00542 ULONG TimeoutCount = 0; 00543 PLARGE_INTEGER TimeoutTime = &RtlpTimeout; 00544 00545 // 00546 // Loop until the resource is ours or exit if we cannot wait. 00547 // 00548 00549 while (TRUE) { 00550 00551 // 00552 // Enter the critical section 00553 // 00554 00555 RtlEnterCriticalSection(&Resource->CriticalSection); 00556 00557 // 00558 // If there are no shared users and it is not currently acquired for 00559 // exclusive use then we can acquire the resource for exclusive 00560 // access. We also can acquire it if the resource indicates exclusive 00561 // access but there isn't currently an owner. 00562 // 00563 00564 if ((Resource->NumberOfActive == 0) 00565 00566 || 00567 00568 ((Resource->NumberOfActive == -1) && 00569 (Resource->ExclusiveOwnerThread == NULL))) { 00570 00571 // 00572 // The resource is ours, so indicate that we have it and 00573 // exit the critical section 00574 // 00575 00576 Resource->NumberOfActive = -1; 00577 00578 Resource->ExclusiveOwnerThread = NtCurrentTeb()->ClientId.UniqueThread; 00579 00580 RtlLeaveCriticalSection(&Resource->CriticalSection); 00581 00582 return TRUE; 00583 00584 } 00585 00586 // 00587 // Otherwise check to see if we already have exclusive access to the 00588 // resource and can simply recusively acquire it again. 00589 // 00590 00591 if (Resource->ExclusiveOwnerThread == NtCurrentTeb()->ClientId.UniqueThread) { 00592 00593 // 00594 // The resource is ours (recusively) so indicate that we have it 00595 // and exit the critial section 00596 // 00597 00598 Resource->NumberOfActive -= 1; 00599 00600 RtlLeaveCriticalSection(&Resource->CriticalSection); 00601 00602 return TRUE; 00603 00604 } 00605 00606 // 00607 // Check if we are allowed to wait or must return immedately, and 00608 // indicate that we didn't acquire the resource 00609 // 00610 00611 if (!Wait) { 00612 00613 RtlLeaveCriticalSection(&Resource->CriticalSection); 00614 00615 return FALSE; 00616 00617 } 00618 00619 // 00620 // Otherwise we need to wait to acquire the resource. 00621 // To wait we will increment the number of waiting exclusive, 00622 // release the lock, and wait on the exclusive semaphore 00623 // 00624 00625 Resource->NumberOfWaitingExclusive += 1; 00626 Resource->DebugInfo->ContentionCount++; 00627 00628 RtlLeaveCriticalSection(&Resource->CriticalSection); 00629 00630 rewait: 00631 if ( Resource->Flags & RTL_RESOURCE_FLAG_LONG_TERM ) { 00632 TimeoutTime = NULL; 00633 } 00634 Status = NtWaitForSingleObject( 00635 Resource->ExclusiveSemaphore, 00636 FALSE, 00637 TimeoutTime 00638 ); 00639 if ( Status == STATUS_TIMEOUT ) { 00640 DbgPrint("RTL: Acquire Exclusive Sem Timeout %d (2 minutes)\n",TimeoutCount); 00641 DbgPrint("RTL: Resource at %p\n",Resource); 00642 TimeoutCount++; 00643 if ( TimeoutCount > 2 ) { 00644 PIMAGE_NT_HEADERS NtHeaders; 00645 00646 // 00647 // If the image is a Win32 image, then raise an exception and try to get to the 00648 // uae popup 00649 // 00650 00651 NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); 00652 00653 if (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || 00654 NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { 00655 EXCEPTION_RECORD ExceptionRecord; 00656 00657 ExceptionRecord.ExceptionCode = STATUS_POSSIBLE_DEADLOCK; 00658 ExceptionRecord.ExceptionFlags = 0; 00659 ExceptionRecord.ExceptionRecord = NULL; 00660 ExceptionRecord.ExceptionAddress = (PVOID)RtlRaiseException; 00661 ExceptionRecord.NumberParameters = 1; 00662 ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)Resource; 00663 RtlRaiseException(&ExceptionRecord); 00664 } 00665 else { 00666 DbgBreakPoint(); 00667 } 00668 } 00669 DbgPrint("RTL: Re-Waiting\n"); 00670 goto rewait; 00671 } 00672 if ( !NT_SUCCESS(Status) ) { 00673 RtlRaiseStatus(Status); 00674 } 00675 } 00676 } 00677 00678 00679 VOID 00680 RtlReleaseResource( 00681 IN PRTL_RESOURCE Resource 00682 ) 00683 00684 /*++ 00685 00686 Routine Description: 00687 00688 This routine release the input resource. The resource can have been 00689 acquired for either shared or exclusive access. 00690 00691 Arguments: 00692 00693 Resource - Supplies the resource to release 00694 00695 Return Value: 00696 00697 None. 00698 00699 --*/ 00700 00701 { 00702 NTSTATUS Status; 00703 LONG PreviousCount; 00704 00705 // 00706 // Enter the critical section 00707 // 00708 00709 RtlEnterCriticalSection(&Resource->CriticalSection); 00710 00711 // 00712 // Test if the resource is acquired for shared or exclusive access 00713 // 00714 00715 if (Resource->NumberOfActive > 0) { 00716 00717 // 00718 // Releasing shared access to the resource, so decrement 00719 // the number of shared users 00720 // 00721 00722 Resource->NumberOfActive -= 1; 00723 00724 // 00725 // If the resource is now available and there is a waiting 00726 // exclusive user then give the resource to the waiting thread 00727 // 00728 00729 if ((Resource->NumberOfActive == 0) && 00730 (Resource->NumberOfWaitingExclusive > 0)) { 00731 00732 // 00733 // Set the resource state to exclusive (but not owned), 00734 // decrement the number of waiting exclusive, and release 00735 // one exclusive waiter 00736 // 00737 00738 Resource->NumberOfActive = -1; 00739 Resource->ExclusiveOwnerThread = NULL; 00740 00741 Resource->NumberOfWaitingExclusive -= 1; 00742 00743 Status = NtReleaseSemaphore( 00744 Resource->ExclusiveSemaphore, 00745 1, 00746 &PreviousCount 00747 ); 00748 if ( !NT_SUCCESS(Status) ) { 00749 RtlRaiseStatus(Status); 00750 } 00751 } 00752 00753 } else if (Resource->NumberOfActive < 0) { 00754 00755 // 00756 // Releasing exclusive access to the resource, so increment the 00757 // number of active by one. And continue testing only 00758 // if the resource is now available. 00759 // 00760 00761 Resource->NumberOfActive += 1; 00762 00763 if (Resource->NumberOfActive == 0) { 00764 00765 // 00766 // The resource is now available. Remove ourselves as the 00767 // owner thread 00768 // 00769 00770 Resource->ExclusiveOwnerThread = NULL; 00771 00772 // 00773 // If there is another waiting exclusive then give the resource 00774 // to it. 00775 // 00776 00777 if (Resource->NumberOfWaitingExclusive > 0) { 00778 00779 // 00780 // Set the resource to exclusive, and its owner undefined. 00781 // Decrement the number of waiting exclusive and release one 00782 // exclusive waiter 00783 // 00784 00785 Resource->NumberOfActive = -1; 00786 Resource->NumberOfWaitingExclusive -= 1; 00787 00788 Status = NtReleaseSemaphore( 00789 Resource->ExclusiveSemaphore, 00790 1, 00791 &PreviousCount 00792 ); 00793 if ( !NT_SUCCESS(Status) ) { 00794 RtlRaiseStatus(Status); 00795 } 00796 00797 // 00798 // Check to see if there are waiting shared, who should now get 00799 // the resource 00800 // 00801 00802 } else if (Resource->NumberOfWaitingShared > 0) { 00803 00804 // 00805 // Set the new state to indicate that all of the shared 00806 // requesters have access and there are no more waiting 00807 // shared requesters, and then release all of the shared 00808 // requsters 00809 // 00810 00811 Resource->NumberOfActive = Resource->NumberOfWaitingShared; 00812 00813 Resource->NumberOfWaitingShared = 0; 00814 00815 Status = NtReleaseSemaphore( 00816 Resource->SharedSemaphore, 00817 Resource->NumberOfActive, 00818 &PreviousCount 00819 ); 00820 if ( !NT_SUCCESS(Status) ) { 00821 RtlRaiseStatus(Status); 00822 } 00823 } 00824 } 00825 00826 #if DBG 00827 } else { 00828 00829 // 00830 // The resource isn't current acquired, there is nothing to release 00831 // so tell the user the mistake 00832 // 00833 00834 00835 DbgPrint("NTDLL - Resource released too many times %lx\n", Resource); 00836 DbgBreakPoint(); 00837 #endif 00838 } 00839 00840 // 00841 // Exit the critical section, and return to the caller 00842 // 00843 00844 RtlLeaveCriticalSection(&Resource->CriticalSection); 00845 00846 return; 00847 } 00848 00849 00850 VOID 00851 RtlConvertSharedToExclusive( 00852 IN PRTL_RESOURCE Resource 00853 ) 00854 00855 /*++ 00856 00857 Routine Description: 00858 00859 This routine converts a resource acquired for shared access into 00860 one acquired for exclusive access. Upon return from the procedure 00861 the resource is acquired for exclusive access 00862 00863 Arguments: 00864 00865 Resource - Supplies the resource to acquire for shared access, it 00866 must already be acquired for shared access 00867 00868 Return Value: 00869 00870 None 00871 00872 --*/ 00873 00874 { 00875 NTSTATUS Status; 00876 ULONG TimeoutCount = 0; 00877 00878 // 00879 // Enter the critical section 00880 // 00881 00882 RtlEnterCriticalSection(&Resource->CriticalSection); 00883 00884 // 00885 // If there is only one shared user (it's us) and we can acquire the 00886 // resource for exclusive access. 00887 // 00888 00889 if (Resource->NumberOfActive == 1) { 00890 00891 // 00892 // The resource is ours, so indicate that we have it and 00893 // exit the critical section, and return 00894 // 00895 00896 Resource->NumberOfActive = -1; 00897 00898 Resource->ExclusiveOwnerThread = NtCurrentTeb()->ClientId.UniqueThread; 00899 00900 RtlLeaveCriticalSection(&Resource->CriticalSection); 00901 00902 return; 00903 } 00904 00905 // 00906 // If the resource is currently acquired exclusive and it's us then 00907 // we already have exclusive access 00908 // 00909 00910 if ((Resource->NumberOfActive < 0) && 00911 (Resource->ExclusiveOwnerThread == NtCurrentTeb()->ClientId.UniqueThread)) { 00912 00913 // 00914 // We already have exclusive access to the resource so we'll just 00915 // exit the critical section and return 00916 // 00917 00918 RtlLeaveCriticalSection(&Resource->CriticalSection); 00919 00920 return; 00921 } 00922 00923 // 00924 // If the resource is acquired by more than one shared then we need 00925 // to wait to get exclusive access to the resource 00926 // 00927 00928 if (Resource->NumberOfActive > 1) { 00929 00930 // 00931 // To wait we will decrement the fact that we have the resource for 00932 // shared, and then loop waiting on the exclusive lock, and then 00933 // testing to see if we can get exclusive access to the resource 00934 // 00935 00936 Resource->NumberOfActive -= 1; 00937 00938 while (TRUE) { 00939 00940 // 00941 // Increment the number of waiting exclusive, exit and critical 00942 // section and wait on the exclusive semaphore 00943 // 00944 00945 Resource->NumberOfWaitingExclusive += 1; 00946 Resource->DebugInfo->ContentionCount++; 00947 00948 RtlLeaveCriticalSection(&Resource->CriticalSection); 00949 rewait: 00950 Status = NtWaitForSingleObject( 00951 Resource->ExclusiveSemaphore, 00952 FALSE, 00953 &RtlpTimeout 00954 ); 00955 if ( Status == STATUS_TIMEOUT ) { 00956 DbgPrint("RTL: Convert Exclusive Sem Timeout %d (2 minutes)\n",TimeoutCount); 00957 DbgPrint("RTL: Resource at %p\n",Resource); 00958 TimeoutCount++; 00959 if ( TimeoutCount > 2 ) { 00960 PIMAGE_NT_HEADERS NtHeaders; 00961 00962 // 00963 // If the image is a Win32 image, then raise an exception and try to get to the 00964 // uae popup 00965 // 00966 00967 NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); 00968 00969 if (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || 00970 NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { 00971 EXCEPTION_RECORD ExceptionRecord; 00972 00973 ExceptionRecord.ExceptionCode = STATUS_POSSIBLE_DEADLOCK; 00974 ExceptionRecord.ExceptionFlags = 0; 00975 ExceptionRecord.ExceptionRecord = NULL; 00976 ExceptionRecord.ExceptionAddress = (PVOID)RtlRaiseException; 00977 ExceptionRecord.NumberParameters = 1; 00978 ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)Resource; 00979 RtlRaiseException(&ExceptionRecord); 00980 } 00981 else { 00982 DbgBreakPoint(); 00983 } 00984 } 00985 DbgPrint("RTL: Re-Waiting\n"); 00986 goto rewait; 00987 } 00988 if ( !NT_SUCCESS(Status) ) { 00989 RtlRaiseStatus(Status); 00990 } 00991 00992 // 00993 // Enter the critical section 00994 // 00995 00996 RtlEnterCriticalSection(&Resource->CriticalSection); 00997 00998 // 00999 // If there are no shared users and it is not currently acquired 01000 // for exclusive use then we can acquire the resource for 01001 // exclusive access. We can also acquire it if the resource 01002 // indicates exclusive access but there isn't currently an owner 01003 // 01004 01005 if ((Resource->NumberOfActive == 0) 01006 01007 || 01008 01009 ((Resource->NumberOfActive == -1) && 01010 (Resource->ExclusiveOwnerThread == NULL))) { 01011 01012 // 01013 // The resource is ours, so indicate that we have it and 01014 // exit the critical section and return. 01015 // 01016 01017 Resource->NumberOfActive = -1; 01018 01019 Resource->ExclusiveOwnerThread = NtCurrentTeb()->ClientId.UniqueThread; 01020 01021 RtlLeaveCriticalSection(&Resource->CriticalSection); 01022 01023 return; 01024 } 01025 01026 // 01027 // Otherwise check to see if we already have exclusive access to 01028 // the resource and can simply recusively acquire it again. 01029 // 01030 01031 if (Resource->ExclusiveOwnerThread == NtCurrentTeb()->ClientId.UniqueThread) { 01032 01033 // 01034 // The resource is ours (recusively) so indicate that we have 01035 // it and exit the critical section and return. 01036 // 01037 01038 Resource->NumberOfActive -= 1; 01039 01040 RtlLeaveCriticalSection(&Resource->CriticalSection); 01041 01042 return; 01043 } 01044 } 01045 01046 } 01047 01048 // 01049 // The resource is not currently acquired for shared so this is a 01050 // spurious call 01051 // 01052 01053 #if DBG 01054 DbgPrint("NTDLL: Failed error - SHARED_RESOURCE_CONV_ERROR\n"); 01055 DbgBreakPoint(); 01056 #endif 01057 } 01058 01059 01060 VOID 01061 RtlConvertExclusiveToShared( 01062 IN PRTL_RESOURCE Resource 01063 ) 01064 01065 /*++ 01066 01067 Routine Description: 01068 01069 This routine converts a resource acquired for exclusive access into 01070 one acquired for shared access. Upon return from the procedure 01071 the resource is acquired for shared access 01072 01073 Arguments: 01074 01075 Resource - Supplies the resource to acquire for shared access, it 01076 must already be acquired for exclusive access 01077 01078 Return Value: 01079 01080 None 01081 01082 --*/ 01083 01084 { 01085 LONG PreviousCount; 01086 NTSTATUS Status; 01087 01088 // 01089 // Enter the critical section 01090 // 01091 01092 RtlEnterCriticalSection(&Resource->CriticalSection); 01093 01094 // 01095 // If there is only one shared user (it's us) and we can acquire the 01096 // resource for exclusive access. 01097 // 01098 01099 if (Resource->NumberOfActive == -1) { 01100 01101 Resource->ExclusiveOwnerThread = NULL; 01102 01103 // 01104 // Check to see if there are waiting shared, who should now get the 01105 // resource along with us 01106 // 01107 01108 if (Resource->NumberOfWaitingShared > 0) { 01109 01110 // 01111 // Set the new state to indicate that all of the shared requesters 01112 // have access including us, and there are no more waiting shared 01113 // requesters, and then release all of the shared requsters 01114 // 01115 01116 Resource->NumberOfActive = Resource->NumberOfWaitingShared + 1; 01117 01118 Resource->NumberOfWaitingShared = 0; 01119 01120 Status = NtReleaseSemaphore( 01121 Resource->SharedSemaphore, 01122 Resource->NumberOfActive - 1, 01123 &PreviousCount 01124 ); 01125 if ( !NT_SUCCESS(Status) ) { 01126 RtlRaiseStatus(Status); 01127 } 01128 01129 } else { 01130 01131 // 01132 // There is no one waiting for shared access so it's only ours 01133 // 01134 01135 Resource->NumberOfActive = 1; 01136 01137 } 01138 01139 RtlLeaveCriticalSection(&Resource->CriticalSection); 01140 01141 return; 01142 01143 } 01144 01145 // 01146 // The resource is not currently acquired for exclusive, or we've 01147 // recursively acquired it, so this must be a spurious call 01148 // 01149 01150 #if DBG 01151 DbgPrint("NTDLL: Failed error - SHARED_RESOURCE_CONV_ERROR\n"); 01152 DbgBreakPoint(); 01153 #endif 01154 } 01155 01156 01157 VOID 01158 RtlDeleteResource ( 01159 IN PRTL_RESOURCE Resource 01160 ) 01161 01162 /*++ 01163 01164 Routine Description: 01165 01166 This routine deletes (i.e., uninitializes) the input resource variable 01167 01168 01169 Arguments: 01170 01171 Resource - Supplies the resource variable being deleted 01172 01173 Return Value: 01174 01175 None 01176 01177 --*/ 01178 01179 { 01180 RtlDeleteCriticalSection( &Resource->CriticalSection ); 01181 NtClose(Resource->SharedSemaphore); 01182 NtClose(Resource->ExclusiveSemaphore); 01183 01184 RtlpFreeDebugInfo( Resource->DebugInfo ); 01185 RtlZeroMemory( Resource, sizeof( *Resource ) ); 01186 01187 return; 01188 } 01189 01190 01191 01192 VOID 01193 RtlDumpResource( 01194 IN PRTL_RESOURCE Resource 01195 ) 01196 01197 { 01198 DbgPrint("Resource @ %lx\n", Resource); 01199 01200 DbgPrint(" NumberOfWaitingShared = %lx\n", Resource->NumberOfWaitingShared); 01201 DbgPrint(" NumberOfWaitingExclusive = %lx\n", Resource->NumberOfWaitingExclusive); 01202 01203 DbgPrint(" NumberOfActive = %lx\n", Resource->NumberOfActive); 01204 01205 return; 01206 } 01207 01208 01209 NTSTATUS 01210 RtlInitializeCriticalSection( 01211 IN PRTL_CRITICAL_SECTION CriticalSection 01212 ) 01213 01214 /*++ 01215 01216 Routine Description: 01217 01218 This routine initializes the input critial section variable 01219 01220 Arguments: 01221 01222 CriticalSection - Supplies the resource variable being initialized 01223 01224 Return Value: 01225 01226 TBD - Status of semaphore creation. 01227 01228 --*/ 01229 01230 { 01231 return RtlInitializeCriticalSectionAndSpinCount(CriticalSection,0); 01232 } 01233 01234 01235 01236 #define MAX_SPIN_COUNT 0x00ffffff 01237 #define PREALLOCATE_EVENT_MASK 0x80000000 01238 01239 VOID 01240 RtlEnableEarlyCriticalSectionEventCreation( 01241 VOID 01242 ) 01243 /*++ 01244 01245 Routine Description: 01246 01247 This routine marks the PEB of the calling process so critical section events 01248 are created at critical section creation time rather than at contetion time. 01249 This allows critical processes not to have to worry about error paths later 01250 on at the expense of extra pool consumed. 01251 01252 Arguments: 01253 01254 None 01255 01256 Return Value: 01257 01258 None 01259 01260 --*/ 01261 { 01262 NtCurrentPeb ()->NtGlobalFlag |= FLG_CRITSEC_EVENT_CREATION; 01263 } 01264 01265 NTSTATUS 01266 RtlInitializeCriticalSectionAndSpinCount( 01267 IN PRTL_CRITICAL_SECTION CriticalSection, 01268 ULONG SpinCount 01269 ) 01270 01271 /*++ 01272 01273 Routine Description: 01274 01275 This routine initializes the input critial section variable 01276 01277 Arguments: 01278 01279 CriticalSection - Supplies the resource variable being initialized 01280 01281 Return Value: 01282 01283 TBD - Status of semaphore creation. 01284 01285 --*/ 01286 01287 { 01288 PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 01289 NTSTATUS Status; 01290 01291 // 01292 // Initialize the lock fields, the count indicates how many are waiting 01293 // to enter or are in the critical section, LockSemaphore is the object 01294 // to wait on when entering the critical section. SpinLock is used 01295 // for the add interlock instruction. Recursion count is the number of 01296 // times the critical section has been recursively entered. 01297 // 01298 01299 CriticalSection->LockCount = -1; 01300 CriticalSection->RecursionCount = 0; 01301 CriticalSection->OwningThread = 0; 01302 CriticalSection->LockSemaphore = 0; 01303 if ( NtCurrentPeb()->NumberOfProcessors > 1 ) { 01304 CriticalSection->SpinCount = SpinCount & MAX_SPIN_COUNT; 01305 } 01306 else { 01307 CriticalSection->SpinCount = 0; 01308 } 01309 01310 if ( ( SpinCount & PREALLOCATE_EVENT_MASK ) || 01311 ( NtCurrentPeb ()->NtGlobalFlag & FLG_CRITSEC_EVENT_CREATION ) ) { 01312 Status = NtCreateEvent( 01313 &CriticalSection->LockSemaphore, 01314 DESIRED_EVENT_ACCESS, 01315 NULL, 01316 SynchronizationEvent, 01317 FALSE 01318 ); 01319 if ( !NT_SUCCESS(Status) ) { 01320 return Status; 01321 } 01322 #if DBG 01323 ProtectHandle(CriticalSection->LockSemaphore); 01324 #endif // DBG 01325 } 01326 01327 // 01328 // Initialize debugging information. 01329 // 01330 01331 DebugInfo = (PRTL_CRITICAL_SECTION_DEBUG)RtlpAllocateDebugInfo(); 01332 if (DebugInfo == NULL) { 01333 if (CriticalSection->LockSemaphore) { 01334 #if DBG 01335 UnProtectHandle( CriticalSection->LockSemaphore ); 01336 #endif // DBG 01337 NtClose( CriticalSection->LockSemaphore ); 01338 CriticalSection->LockSemaphore = 0; 01339 } 01340 return STATUS_NO_MEMORY; 01341 } 01342 01343 DebugInfo->Type = RTL_CRITSECT_TYPE; 01344 DebugInfo->ContentionCount = 0; 01345 DebugInfo->EntryCount = 0; 01346 01347 // 01348 // If the critical section lock itself is not being initialized, then 01349 // synchronize the insert of the critical section in the process locks 01350 // list. Otherwise, insert the critical section with no synchronization. 01351 // 01352 01353 if ((CriticalSection != &RtlCriticalSectionLock) && 01354 (RtlpCritSectInitialized != FALSE)) { 01355 RtlEnterCriticalSection(&RtlCriticalSectionLock); 01356 InsertTailList(&RtlCriticalSectionList, &DebugInfo->ProcessLocksList); 01357 RtlLeaveCriticalSection(&RtlCriticalSectionLock ); 01358 01359 } else { 01360 InsertTailList(&RtlCriticalSectionList, &DebugInfo->ProcessLocksList); 01361 } 01362 01363 DebugInfo->CriticalSection = CriticalSection; 01364 CriticalSection->DebugInfo = DebugInfo; 01365 #if i386 01366 DebugInfo->CreatorBackTraceIndex = (USHORT)RtlLogStackBackTrace(); 01367 #endif // i386 01368 01369 return STATUS_SUCCESS; 01370 } 01371 01372 01373 ULONG 01374 RtlSetCriticalSectionSpinCount( 01375 IN PRTL_CRITICAL_SECTION CriticalSection, 01376 ULONG SpinCount 01377 ) 01378 01379 /*++ 01380 01381 Routine Description: 01382 01383 This routine initializes the input critial section variable 01384 01385 Arguments: 01386 01387 CriticalSection - Supplies the resource variable being initialized 01388 01389 Return Value: 01390 01391 Returns the previous critical section spin count 01392 01393 --*/ 01394 01395 { 01396 ULONG OldSpinCount; 01397 01398 OldSpinCount = (ULONG)CriticalSection->SpinCount; 01399 01400 if ( NtCurrentPeb()->NumberOfProcessors > 1 ) { 01401 CriticalSection->SpinCount = SpinCount; 01402 } 01403 else { 01404 CriticalSection->SpinCount = 0; 01405 } 01406 01407 return OldSpinCount; 01408 } 01409 01410 01411 VOID 01412 RtlpCreateCriticalSectionSem( 01413 IN PRTL_CRITICAL_SECTION CriticalSection 01414 ) 01415 { 01416 NTSTATUS Status; 01417 LARGE_INTEGER tmo = {(ULONG) -100000, -1}; // Start at 1/100th of a second 01418 LONGLONG max_tmo = (LONGLONG) -10000000 * 60 * 3; // Wait for a max of 3 minutes 01419 01420 // 01421 // Loop trying to create the event on failure. 01422 // 01423 while (1) { 01424 Status = NtCreateEvent( 01425 &CriticalSection->LockSemaphore, 01426 DESIRED_EVENT_ACCESS, 01427 NULL, 01428 SynchronizationEvent, 01429 FALSE 01430 ); 01431 01432 if ( NT_SUCCESS(Status) ) { 01433 break; 01434 } else { 01435 if ( tmo.QuadPart < max_tmo ) { 01436 KdPrint(( "NTDLL: Warning. Unable to allocate lock semaphore for Cs %p. Status %x raising\n", CriticalSection,Status )); 01437 InterlockedDecrement(&CriticalSection->LockCount); 01438 RtlRaiseStatus(Status); 01439 } 01440 KdPrint(( "NTDLL: Warning. Unable to allocate lock semaphore for Cs %p. Status %x retrying\n", CriticalSection,Status )); 01441 01442 Status = NtDelayExecution (FALSE, &tmo); 01443 if ( !NT_SUCCESS(Status) ) { 01444 InterlockedDecrement(&CriticalSection->LockCount); 01445 RtlRaiseStatus(Status); 01446 } 01447 tmo.QuadPart *= 2; 01448 } 01449 } 01450 #if DBG 01451 ProtectHandle(CriticalSection->LockSemaphore); 01452 #endif // DBG 01453 } 01454 01455 VOID 01456 RtlpCheckDeferedCriticalSection( 01457 IN PRTL_CRITICAL_SECTION CriticalSection 01458 ) 01459 { 01460 RtlEnterCriticalSection(&DeferedCriticalSection); 01461 try { 01462 if ( !CriticalSection->LockSemaphore ) { 01463 RtlpCreateCriticalSectionSem(CriticalSection); 01464 } 01465 } 01466 finally { 01467 RtlLeaveCriticalSection(&DeferedCriticalSection); 01468 } 01469 return; 01470 } 01471 01472 01473 NTSTATUS 01474 RtlDeleteCriticalSection( 01475 IN PRTL_CRITICAL_SECTION CriticalSection 01476 ) 01477 01478 /*++ 01479 01480 Routine Description: 01481 01482 This routine deletes (i.e., uninitializes) the input critical 01483 section variable 01484 01485 01486 Arguments: 01487 01488 CriticalSection - Supplies the resource variable being deleted 01489 01490 Return Value: 01491 01492 TBD - Status of semaphore close. 01493 01494 --*/ 01495 01496 { 01497 NTSTATUS Status; 01498 PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 01499 01500 if ( CriticalSection->LockSemaphore ) { 01501 #if DBG 01502 UnProtectHandle( CriticalSection->LockSemaphore ); 01503 #endif // DBG 01504 Status = NtClose( CriticalSection->LockSemaphore ); 01505 } 01506 else { 01507 Status = STATUS_SUCCESS; 01508 } 01509 01510 // 01511 // Remove critical section from the list 01512 // 01513 01514 RtlEnterCriticalSection( &RtlCriticalSectionLock ); 01515 try { 01516 DebugInfo = CriticalSection->DebugInfo; 01517 if (DebugInfo != NULL) { 01518 RemoveEntryList( &DebugInfo->ProcessLocksList ); 01519 RtlZeroMemory( DebugInfo, sizeof( *DebugInfo ) ); 01520 } 01521 } 01522 finally { 01523 RtlLeaveCriticalSection( &RtlCriticalSectionLock ); 01524 } 01525 if (DebugInfo != NULL) { 01526 RtlpFreeDebugInfo( DebugInfo ); 01527 } 01528 RtlZeroMemory( CriticalSection, 01529 FIELD_OFFSET(RTL_CRITICAL_SECTION, SpinCount) + sizeof(ULONG) ); 01530 01531 return Status; 01532 } 01533 01534 01535 01536 // 01537 // The following support routines are called from the machine language 01538 // implementations of RtlEnterCriticalSection and RtlLeaveCriticalSection 01539 // to execute the slow path logic of either waiting for a critical section 01540 // or releasing a critical section to a waiting thread. 01541 // 01542 01543 void 01544 RtlpWaitForCriticalSection( 01545 IN PRTL_CRITICAL_SECTION CriticalSection 01546 ) 01547 { 01548 NTSTATUS st; 01549 ULONG TimeoutCount = 0; 01550 PLARGE_INTEGER TimeoutTime; 01551 BOOLEAN CsIsLoaderLock; 01552 01553 // 01554 // critical sections are disabled during exit process so that 01555 // apps that are not carefull during shutdown don't hang 01556 // 01557 01558 CsIsLoaderLock = (CriticalSection == NtCurrentPeb()->LoaderLock); 01559 NtCurrentTeb()->WaitingOnLoaderLock = (ULONG)CsIsLoaderLock; 01560 01561 if ( LdrpShutdownInProgress && 01562 ((!CsIsLoaderLock) || 01563 (CsIsLoaderLock && LdrpShutdownThreadId == NtCurrentTeb()->ClientId.UniqueThread) ) ) { 01564 01565 // 01566 // slimey reinitialization of the critical section with the count biased by one 01567 // this is how the critical section would normally look to the thread coming out 01568 // of this function. Note that the semaphore handle is leaked, but since the 01569 // app is exiting, it's ok 01570 // 01571 01572 CriticalSection->LockCount = 0; 01573 CriticalSection->RecursionCount = 0; 01574 CriticalSection->OwningThread = 0; 01575 CriticalSection->LockSemaphore = 0; 01576 01577 NtCurrentTeb()->WaitingOnLoaderLock = 0; 01578 01579 return; 01580 01581 } 01582 01583 if (RtlpTimoutDisable) { 01584 TimeoutTime = NULL; 01585 } 01586 else { 01587 TimeoutTime = &RtlpTimeout; 01588 } 01589 01590 if ( !CriticalSection->LockSemaphore ) { 01591 RtlpCheckDeferedCriticalSection(CriticalSection); 01592 } 01593 01594 CriticalSection->DebugInfo->EntryCount++; 01595 while( TRUE ) { 01596 01597 CriticalSection->DebugInfo->ContentionCount++; 01598 01599 #if 0 01600 DbgPrint( "NTDLL: Waiting for CritSect: %p owned by ThreadId: %X Count: %u Level: %u\n", 01601 CriticalSection, 01602 CriticalSection->OwningThread, 01603 CriticalSection->LockCount, 01604 CriticalSection->RecursionCount 01605 ); 01606 #endif 01607 01608 st = NtWaitForSingleObject( CriticalSection->LockSemaphore, 01609 FALSE, 01610 TimeoutTime 01611 ); 01612 if ( st == STATUS_TIMEOUT ) { 01613 DbgPrint( "RTL: Enter Critical Section Timeout (2 minutes) %d\n", 01614 TimeoutCount 01615 ); 01616 DbgPrint( "RTL: Pid.Tid %x.%x, owner tid %x Critical Section %p - ContentionCount == %lu\n", 01617 NtCurrentTeb()->ClientId.UniqueProcess, 01618 NtCurrentTeb()->ClientId.UniqueThread, 01619 CriticalSection->OwningThread, 01620 CriticalSection, CriticalSection->DebugInfo->ContentionCount 01621 ); 01622 TimeoutCount++; 01623 if ( TimeoutCount > 2 && CriticalSection != NtCurrentPeb()->LoaderLock ) { 01624 PIMAGE_NT_HEADERS NtHeaders; 01625 01626 // 01627 // If the image is a Win32 image, then raise an exception and try to get to the 01628 // uae popup 01629 // 01630 01631 NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); 01632 01633 if (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI || 01634 NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { 01635 EXCEPTION_RECORD ExceptionRecord; 01636 01637 ExceptionRecord.ExceptionCode = STATUS_POSSIBLE_DEADLOCK; 01638 ExceptionRecord.ExceptionFlags = 0; 01639 ExceptionRecord.ExceptionRecord = NULL; 01640 ExceptionRecord.ExceptionAddress = (PVOID)RtlRaiseException; 01641 ExceptionRecord.NumberParameters = 1; 01642 ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)CriticalSection; 01643 RtlRaiseException(&ExceptionRecord); 01644 } 01645 else { 01646 DbgBreakPoint(); 01647 } 01648 } 01649 DbgPrint("RTL: Re-Waiting\n"); 01650 } 01651 else { 01652 if ( NT_SUCCESS(st) ) { 01653 // 01654 // If some errant thread calls SetEvent on a bogus handle 01655 // which happens to match the handle we are using in the critical 01656 // section, everything gets really messed up since two threads 01657 // now own the lock at the same time. ASSERT that no other thread 01658 // owns the lock if we have been granted ownership. 01659 // 01660 ASSERT(CriticalSection->OwningThread == 0); 01661 if ( CsIsLoaderLock ) { 01662 CriticalSection->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; 01663 NtCurrentTeb()->WaitingOnLoaderLock = 0; 01664 } 01665 return; 01666 } 01667 else { 01668 RtlRaiseStatus(st); 01669 } 01670 } 01671 } 01672 } 01673 01674 void 01675 RtlpUnWaitCriticalSection( 01676 IN PRTL_CRITICAL_SECTION CriticalSection 01677 ) 01678 { 01679 NTSTATUS st; 01680 01681 #if 0 01682 DbgPrint( "NTDLL: Releasing CritSect: %p ThreadId: %X\n", 01683 CriticalSection, CriticalSection->OwningThread 01684 ); 01685 #endif 01686 01687 if ( !CriticalSection->LockSemaphore ) { 01688 RtlpCheckDeferedCriticalSection(CriticalSection); 01689 } 01690 01691 #if DBG 01692 // 01693 // Sneaky trick here to catch sleazy apps (csrss) that erroneously call 01694 // NtSetEvent on an event that happens to be somebody else's 01695 // critical section. Only allow setting a protected handle if the low 01696 // bit of PreviousState is set. 01697 // 01698 st = NtSetEvent( CriticalSection->LockSemaphore, 01699 (PLONG)1 01700 ); 01701 #else 01702 st = NtSetEvent( CriticalSection->LockSemaphore, 01703 NULL 01704 ); 01705 #endif 01706 01707 if ( NT_SUCCESS(st) ) { 01708 return; 01709 } 01710 else { 01711 RtlRaiseStatus(st); 01712 } 01713 } 01714 01715 01716 void 01717 RtlpNotOwnerCriticalSection( 01718 IN PRTL_CRITICAL_SECTION CriticalSection 01719 ) 01720 { 01721 BOOLEAN CsIsLoaderLock; 01722 01723 // 01724 // critical sections are disabled during exit process so that 01725 // apps that are not carefull during shutdown don't hang 01726 // 01727 01728 CsIsLoaderLock = (CriticalSection == NtCurrentPeb()->LoaderLock); 01729 01730 if ( LdrpShutdownInProgress && 01731 ((!CsIsLoaderLock) || 01732 (CsIsLoaderLock && LdrpShutdownThreadId == NtCurrentTeb()->ClientId.UniqueThread) ) ) { 01733 return; 01734 } 01735 01736 if (NtCurrentPeb()->BeingDebugged) { 01737 DbgPrint( "NTDLL: Calling thread (%X) not owner of CritSect: %p Owner ThreadId: %X\n", 01738 NtCurrentTeb()->ClientId.UniqueThread, 01739 CriticalSection, 01740 CriticalSection->OwningThread 01741 ); 01742 #if i386 01743 _asm { int 3 } 01744 #else 01745 DbgBreakPoint(); 01746 #endif 01747 } 01748 RtlRaiseStatus( STATUS_RESOURCE_NOT_OWNED ); 01749 } 01750 01751 01752 #if DBG 01753 void 01754 RtlpCriticalSectionIsOwned( 01755 IN PRTL_CRITICAL_SECTION CriticalSection 01756 ) 01757 { 01758 // 01759 // The loader lock gets handled differently, so don't assert on it 01760 // 01761 01762 if ( CriticalSection == NtCurrentPeb()->LoaderLock && 01763 CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread ) { 01764 return; 01765 } 01766 01767 // 01768 // If we're being debugged, throw up a warning 01769 // 01770 01771 if (NtCurrentPeb()->BeingDebugged) { 01772 DbgPrint( "NTDLL: Calling thread (%X) shouldn't enter CritSect: %p Owner ThreadId: %X\n", 01773 NtCurrentTeb()->ClientId.UniqueThread, 01774 CriticalSection, 01775 CriticalSection->OwningThread 01776 ); 01777 #if i386 01778 _asm { int 3 } 01779 #else 01780 DbgBreakPoint(); 01781 #endif 01782 } 01783 } 01784 #endif 01785 01786 01787 void 01788 RtlCheckForOrphanedCriticalSections( 01789 IN HANDLE hThread 01790 ) 01791 /*++ 01792 01793 Routine Description: 01794 01795 This routine is called from kernel32's ExitThread and TerminateThread 01796 in an effort to track calls that kill threads while they own 01797 critical sections. 01798 01799 Arguments: 01800 01801 hThread -- thread to be killed 01802 01803 Return Value: 01804 01805 None. 01806 01807 --*/ 01808 { 01809 // 01810 // This whole routine should be called only on checked builds. 01811 // It is a stub in the free build, so that a checked kernel32.dll 01812 // can bind against a free ntdll.dll 01813 // 01814 #if DBG 01815 NTSTATUS Status; 01816 THREAD_BASIC_INFORMATION ThreadInfo; 01817 PLIST_ENTRY Entry; 01818 PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 01819 PRTL_CRITICAL_SECTION CriticalSection; 01820 BOOLEAN OrphanAboutToHappen; 01821 RTL_CRITICAL_SECTION CritSectCopy; 01822 01823 if (LdrpShutdownInProgress) { 01824 // 01825 // In the middle of shutting down the process 01826 // 01827 return; 01828 } 01829 01830 Status = NtQueryInformationThread( 01831 hThread, 01832 ThreadBasicInformation, 01833 &ThreadInfo, 01834 sizeof(ThreadInfo), 01835 NULL 01836 ); 01837 if (!NT_SUCCESS(Status)) { 01838 return; 01839 } 01840 01841 OrphanAboutToHappen = FALSE; 01842 01843 RtlEnterCriticalSection( &RtlCriticalSectionLock ); 01844 01845 for (Entry = RtlCriticalSectionList.Flink; 01846 Entry != &RtlCriticalSectionList; 01847 Entry = Entry->Flink) { 01848 01849 DebugInfo = CONTAINING_RECORD(Entry, 01850 RTL_CRITICAL_SECTION_DEBUG, 01851 ProcessLocksList); 01852 01853 CriticalSection = DebugInfo->CriticalSection; 01854 01855 if (CriticalSection == &RtlCriticalSectionLock || 01856 CriticalSection == NtCurrentPeb()->LoaderLock) { 01857 // 01858 // Skip these critsects. 01859 // 01860 continue; 01861 } 01862 01863 // 01864 // Call NtReadVirtualMemory() and make a copy of the critsect. 01865 // This won't AV and break to the debugger if the critsect's 01866 // memory has been freed without an RtlDeleteCriticalSection call. 01867 // 01868 Status = NtReadVirtualMemory(NtCurrentProcess(), 01869 CriticalSection, 01870 &CritSectCopy, 01871 sizeof(CritSectCopy), 01872 NULL); 01873 if (!NT_SUCCESS(Status) || CritSectCopy.DebugInfo != DebugInfo) { 01874 // 01875 // Error reading the contents of the critsect. The critsect 01876 // has probably been decommitted without a call to 01877 // RtlDeleteCriticalSection. Ignore it. 01878 // 01879 // You might think the entry could be deleted from the list, 01880 // but it can't... there may be another RTL_CRITICAL_SECTION 01881 // out there that is truly allocated, and who DebugInfo pointer 01882 // points at this DebugInfo. In that case, when that critsect 01883 // is deleted, the RtlCriticalSectionList is corrupted. 01884 // 01885 } else if (CritSectCopy.OwningThread == ThreadInfo.ClientId.UniqueThread 01886 && CritSectCopy.LockCount != -1) { 01887 // 01888 // The thread is about to die with a critical section locked. 01889 // 01890 DbgPrint("NTDLL: Pid.Tid %x.%x Critsec %p about to be orphaned when owning thread is terminated.\n", 01891 NtCurrentTeb()->ClientId.UniqueProcess, 01892 NtCurrentTeb()->ClientId.UniqueThread, 01893 CriticalSection); 01894 OrphanAboutToHappen = TRUE; 01895 } 01896 } 01897 01898 if (OrphanAboutToHappen) { 01899 #if i386 01900 _asm { int 3 } 01901 #else 01902 DbgBreakPoint(); 01903 #endif 01904 } 01905 01906 RtlLeaveCriticalSection( &RtlCriticalSectionLock ); 01907 #endif 01908 } 01909 

Generated on Sat May 15 19:41:39 2004 for test by doxygen 1.3.7