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

ddkresrc.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 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, that was unfortunately export to ntddk in release 1. 00013 00014 Author: 00015 00016 Gary D. Kimura [GaryKi] 25-Jun-1989 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 #include "exp.h" 00027 #pragma hdrstop 00028 00029 #include <nturtl.h> 00030 00031 // 00032 // The following variable, macros, and procedure are only for debug purposes. 00033 // 00034 00035 extern LARGE_INTEGER ExpTimeout; 00036 00037 // 00038 // thirty days worth 00039 // 00040 00041 extern ULONG ExpResourceTimeoutCount; 00042 00043 // 00044 // Avoid the aliasing done in ex.h 00045 // 00046 00047 #undef ExInitializeResource 00048 #undef ExAcquireResourceExclusive 00049 #undef ExReleaseResourceForThread 00050 #undef ExDeleteResource 00051 00052 #if !DBG && NT_UP && defined(i386) 00053 #define ExReleaseResourceForThread ExpReleaseResourceForThread 00054 VOID 00055 ExReleaseResourceForThread( 00056 IN PNTDDK_ERESOURCE Resource, 00057 IN ERESOURCE_THREAD OurThread 00058 ); 00059 #endif 00060 00061 #if DBG 00062 00063 VOID 00064 ExpAssertResourceDdk ( 00065 IN PNTDDK_ERESOURCE Resource 00066 ); 00067 00068 #define ASSERT_RESOURCE(_Resource) ExpAssertResourceDdk(_Resource) 00069 #else 00070 #define ASSERT_RESOURCE(_Resource) 00071 #endif 00072 00073 // 00074 // bit value for ERESOURCE.Flag 00075 // 00076 00077 #define ExclusiveWaiter 0x01 // ** Also in i386\resoura.asm ** 00078 #define SharedWaiter 0x02 // ** Also in i386\resoura.asm ** 00079 // CounterShiftBit 0x04 - see below 00080 #define DisablePriorityBoost 0x08 00081 // ResourceOwnedExclusive 0x80 - from ex.h 00082 00083 #if NT_UP 00084 #define CounterShiftBit 0x00 00085 #else 00086 #define CounterShiftBit 0x04 // Must be 0x04! 00087 #endif 00088 00089 #define IsExclusiveWaiting(a) (((a)->Flag & ExclusiveWaiter) != 0) 00090 #define IsOwnedExclusive(a) (((a)->Flag & ResourceOwnedExclusive) != 0) 00091 #define IsOwnedExclusive(a) (((a)->Flag & ResourceOwnedExclusive) != 0) 00092 #define IsBoostAllowed(a) (((a)->Flag & DisablePriorityBoost) == 0) 00093 00094 // 00095 // The following static data and two macros are used to control entering and 00096 // exiting the resource critical section. 00097 // 00098 00099 static KSPIN_LOCK ExpResourceSpinLock; 00100 00101 //++ 00102 // 00103 // Macros: 00104 // AcquireResourceLock - Obtains the Resource's spinlock 00105 // ReleaseResourceLock - Releases the Resource's spinlock 00106 // 00107 // WaitForResourceExclusive(Resource, OldIrql) 00108 // Block on resource until WakeSharedWaiters 00109 // 00110 // WakeExclusiveWaiters 00111 // Wakes threads on resource which are WaitForResourceShared 00112 // 00113 //-- 00114 00115 #define AcquireResourceLock(_Resource,_Irql) { \ 00116 ExAcquireSpinLock( &_Resource->SpinLock, _Irql ); \ 00117 ASSERT_RESOURCE( _Resource ); \ 00118 } 00119 00120 #define ReleaseResourceLock(_Resource,_Irql) { \ 00121 ExReleaseSpinLock( &_Resource->SpinLock, _Irql ); \ 00122 } 00123 00124 #define INITIAL_TABLE_SIZE 4 00125 00126 #define WaitForResourceExclusive(_Resource, _OldIrql) { \ 00127 _Resource->Flag |= ExclusiveWaiter; \ 00128 _Resource->NumberOfExclusiveWaiters += 1; \ 00129 ReleaseResourceLock ( _Resource, _OldIrql ); \ 00130 ExpWaitForResourceDdk ( _Resource, &_Resource->ExclusiveWaiters ); \ 00131 AcquireResourceLock ( _Resource, &_OldIrql); \ 00132 if (--_Resource->NumberOfExclusiveWaiters != 0) { \ 00133 _Resource->Flag |= ExclusiveWaiter; \ 00134 } \ 00135 } 00136 00137 #define WakeExclusiveWaiters(_Resource) { \ 00138 _Resource->Flag &= ~ExclusiveWaiter; \ 00139 KeSetEvent(&_Resource->ExclusiveWaiters, 0, FALSE); \ 00140 } 00141 00142 // 00143 // Local procedure prototypes 00144 // 00145 00146 VOID 00147 ExpWaitForResourceDdk ( 00148 IN PNTDDK_ERESOURCE Resource, 00149 IN PVOID Object 00150 ); 00151 00152 // 00153 // The following list head points to a list of all currently 00154 // initialized Executive Resources in the system. 00155 // 00156 00157 extern LIST_ENTRY ExpSystemResourcesList; 00158 00159 00160 #ifdef ALLOC_PRAGMA 00161 #pragma alloc_text(INIT,ExpResourceInitialization) 00162 #pragma alloc_text(PAGELK,ExQuerySystemLockInformation) 00163 #endif 00164 00165 // 00166 // 00167 // 00168 // 00169 00170 00171 NTSTATUS 00172 ExInitializeResource ( 00173 IN PNTDDK_ERESOURCE Resource 00174 ) 00175 00176 /*++ 00177 00178 Routine Description: 00179 00180 This routine initializes the input resource variable 00181 00182 Arguments: 00183 00184 Resource - Supplies the resource variable being initialized 00185 00186 Return Value: 00187 00188 Status of the operation. 00189 00190 --*/ 00191 00192 { 00193 ULONG i; 00194 00195 ASSERTMSG("A resource cannot be in paged pool ", MmDeterminePoolType(Resource) == NonPagedPool); 00196 // 00197 // Initialize the shared and exclusive waiting counters and semaphore. 00198 // The counters indicate how many are waiting for access to the resource 00199 // and the semaphores are used to wait on the resource. Note that 00200 // the semaphores can also indicate the number waiting for a resource 00201 // however there is a race condition in the algorithm on the acquire 00202 // side if count if not updated before the critical section is exited. 00203 // So we need to have an outside counter. 00204 // 00205 00206 Resource->NumberOfSharedWaiters = 0; 00207 Resource->NumberOfExclusiveWaiters = 0; 00208 00209 KeInitializeSemaphore ( &Resource->SharedWaiters, 0, MAXLONG ); 00210 KeInitializeEvent ( &Resource->ExclusiveWaiters, SynchronizationEvent, FALSE ); 00211 KeInitializeSpinLock ( &Resource->SpinLock ); 00212 00213 Resource->OwnerThreads = Resource->InitialOwnerThreads; 00214 Resource->OwnerCounts = Resource->InitialOwnerCounts; 00215 00216 Resource->TableSize = INITIAL_TABLE_SIZE; 00217 Resource->ActiveCount = 0; 00218 Resource->TableRover = 1; 00219 Resource->Flag = 0; 00220 00221 for(i=0; i < INITIAL_TABLE_SIZE; i++) { 00222 Resource->OwnerThreads[i] = 0; 00223 Resource->OwnerCounts[i] = 0; 00224 } 00225 00226 Resource->ContentionCount = 0; 00227 InitializeListHead( &Resource->SystemResourcesList ); 00228 00229 #if i386 && !FPO 00230 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) { 00231 Resource->CreatorBackTraceIndex = RtlLogStackBackTrace(); 00232 } 00233 else { 00234 Resource->CreatorBackTraceIndex = 0; 00235 } 00236 #endif // i386 && !FPO 00237 if (Resource >= (PNTDDK_ERESOURCE)MM_USER_PROBE_ADDRESS) { 00238 ExInterlockedInsertTailList ( 00239 &ExpSystemResourcesList, 00240 &Resource->SystemResourcesList, 00241 &ExpResourceSpinLock ); 00242 } 00243 00244 return STATUS_SUCCESS; 00245 } 00246 00247 00248 BOOLEAN 00249 ExAcquireResourceExclusive( 00250 IN PNTDDK_ERESOURCE Resource, 00251 IN BOOLEAN Wait 00252 ) 00253 00254 /*++ 00255 00256 Routine Description: 00257 00258 The routine acquires the resource for exclusive access. Upon return from 00259 the procedure the resource is acquired for exclusive access. 00260 00261 Arguments: 00262 00263 Resource - Supplies the resource to acquire 00264 00265 Wait - Indicates if the call is allowed to wait for the resource 00266 to become available for must return immediately 00267 00268 Return Value: 00269 00270 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 00271 00272 --*/ 00273 00274 { 00275 KIRQL OldIrql; 00276 ERESOURCE_THREAD OurThread; 00277 00278 ASSERTMSG("Routine cannot be called at DPC ", !KeIsExecutingDpc() ); 00279 00280 ASSERT((Resource->Flag & ResourceNeverExclusive) == 0); 00281 00282 OurThread = (ULONG_PTR)ExGetCurrentResourceThread(); 00283 00284 // 00285 // Get exclusive access to this resource structure 00286 // 00287 00288 AcquireResourceLock( Resource, &OldIrql ); 00289 00290 // 00291 // Loop until the resource is ours or exit if we cannot wait. 00292 // 00293 00294 while (TRUE) { 00295 if (Resource->ActiveCount == 0) { 00296 00297 // 00298 // Resource is un-owned, obtain it exclusive 00299 // 00300 00301 Resource->InitialOwnerThreads[0] = OurThread; 00302 Resource->OwnerThreads[0] = OurThread; 00303 Resource->OwnerCounts[0] = 1; 00304 Resource->ActiveCount = 1; 00305 Resource->Flag |= ResourceOwnedExclusive; 00306 ReleaseResourceLock ( Resource, OldIrql ); 00307 return TRUE; 00308 } 00309 00310 if (IsOwnedExclusive(Resource) && 00311 Resource->OwnerThreads[0] == OurThread) { 00312 00313 // 00314 // Our thread is already the exclusive resource owner 00315 // 00316 00317 Resource->OwnerCounts[0] += 1; 00318 ReleaseResourceLock( Resource, OldIrql ); 00319 return TRUE; 00320 } 00321 00322 // 00323 // Check if we are allowed to wait or must return immediately, and 00324 // indicate that we didn't acquire the resource 00325 // 00326 00327 if (!Wait) { 00328 ReleaseResourceLock( Resource, OldIrql ); 00329 return FALSE; 00330 } 00331 00332 // 00333 // Otherwise we need to wait to acquire the resource. 00334 // 00335 00336 WaitForResourceExclusive ( Resource, OldIrql ); 00337 } 00338 } 00339 00340 00341 VOID 00342 ExReleaseResourceForThread( 00343 IN PNTDDK_ERESOURCE Resource, 00344 IN ERESOURCE_THREAD OurThread 00345 ) 00346 00347 /*++ 00348 00349 Routine Description: 00350 00351 This routine release the input resource for the indicated thread. The 00352 resource could have been acquired for either shared or exclusive access. 00353 00354 Arguments: 00355 00356 Resource - Supplies the resource to release 00357 00358 Thread - Supplies the thread that originally acquired the resource 00359 00360 Return Value: 00361 00362 None. 00363 00364 --*/ 00365 00366 { 00367 KIRQL OldIrql; 00368 00369 ASSERT( OurThread != 0 ); 00370 00371 // 00372 // Get exclusive access to this resource structure 00373 // 00374 00375 AcquireResourceLock( Resource, &OldIrql ); 00376 00377 ASSERT( Resource->OwnerThreads[0] == OurThread ); 00378 00379 // 00380 // OwnerThread[0] is optimized for resources which get 00381 // single users. We check it first, plus we clear the 00382 // threadid if the counts goes to zero 00383 // 00384 00385 if (--Resource->OwnerCounts[0] != 0) { 00386 ReleaseResourceLock( Resource, OldIrql ); 00387 return; 00388 } 00389 00390 Resource->OwnerThreads[0] = 0; 00391 Resource->InitialOwnerThreads[0] = 0; 00392 00393 // 00394 // Thread's count went to zero, lower the resource's active count. 00395 // 00396 00397 Resource->ActiveCount -= 1; 00398 00399 ASSERT( Resource->ActiveCount == 0 ); 00400 00401 // 00402 // Resource's activecount went to zero - clear possible exclusive 00403 // owner bit, and wake any waiters 00404 // 00405 00406 if (IsExclusiveWaiting(Resource)) { 00407 00408 WakeExclusiveWaiters ( Resource ); 00409 } 00410 00411 // 00412 // No longer owned exclusive 00413 // 00414 00415 Resource->Flag &= ~ResourceOwnedExclusive; 00416 00417 ReleaseResourceLock( Resource, OldIrql ); 00418 return; 00419 } 00420 00421 NTSTATUS 00422 ExDeleteResource ( 00423 IN PNTDDK_ERESOURCE Resource 00424 ) 00425 00426 /*++ 00427 00428 Routine Description: 00429 00430 This routine deletes (i.e., uninitializes) the input resource variable 00431 00432 00433 Arguments: 00434 00435 Resource - Supplies the resource variable being deleted 00436 00437 Return Value: 00438 00439 None 00440 00441 --*/ 00442 00443 { 00444 ASSERTMSG("Routine cannot be called at DPC ", !KeIsExecutingDpc() ); 00445 00446 ASSERT_RESOURCE( Resource ); 00447 ASSERT( !IsExclusiveWaiting(Resource) ); 00448 00449 00450 if (Resource >= (PNTDDK_ERESOURCE)MM_USER_PROBE_ADDRESS) { 00451 KIRQL OldIrql; 00452 00453 ExAcquireSpinLock( &ExpResourceSpinLock, &OldIrql ); 00454 RemoveEntryList( &Resource->SystemResourcesList ); 00455 ExReleaseSpinLock( &ExpResourceSpinLock, OldIrql ); 00456 00457 } 00458 00459 return STATUS_SUCCESS; 00460 } 00461 00462 VOID 00463 ExpWaitForResourceDdk ( 00464 IN PNTDDK_ERESOURCE Resource, 00465 IN PVOID Object 00466 ) 00467 /*++ 00468 00469 Routine Description: 00470 00471 The routine waits on the Resource's object to be set. If the 00472 wait is too long the current owners of the resource are boosted 00473 in priority. 00474 00475 Arguments: 00476 00477 Resource - Supplies the resource 00478 00479 Object - Event or Semaphore to wait on 00480 00481 Return Value: 00482 00483 None 00484 00485 --*/ 00486 { 00487 KIRQL OldIrql; 00488 NTSTATUS Status; 00489 ULONG i; 00490 00491 00492 Resource->ContentionCount += 1; 00493 00494 i = 0; 00495 for (; ;) { 00496 Status = KeWaitForSingleObject ( 00497 Object, 00498 Executive, 00499 KernelMode, 00500 FALSE, 00501 &ExpTimeout ); 00502 00503 if (Status != STATUS_TIMEOUT) { 00504 break; 00505 } 00506 00507 if (i++ >= ExpResourceTimeoutCount) { 00508 i = 0; 00509 00510 DbgPrint("Resource @ %lx\n", Resource); 00511 DbgPrint(" ActiveCount = %04lx Flags = %s%s%s\n", 00512 Resource->ActiveCount, 00513 IsOwnedExclusive(Resource) ? "IsOwnedExclusive " : "", 00514 "", 00515 IsExclusiveWaiting(Resource) ? "ExclusiveWaiter " : "" 00516 ); 00517 00518 DbgPrint(" NumberOfExclusiveWaiters = %04lx\n", Resource->NumberOfExclusiveWaiters); 00519 00520 DbgPrint(" Thread = %08lx, Count = %02x\n", 00521 Resource->OwnerThreads[0], 00522 Resource->OwnerCounts[0] ); 00523 00524 DbgBreakPoint(); 00525 DbgPrint("EX - Rewaiting\n"); 00526 } 00527 00528 // 00529 // Give owning thread(s) a priority boost 00530 // 00531 00532 AcquireResourceLock( Resource, &OldIrql ); 00533 00534 if (IsBoostAllowed(Resource) && IsOwnedExclusive(Resource)) { 00535 00536 // 00537 // Only one thread, boost it 00538 // 00539 00540 KeBoostPriorityThread((PKTHREAD) Resource->OwnerThreads[0], 00541 ERESOURCE_INCREMENT ); 00542 } 00543 00544 ReleaseResourceLock( Resource, OldIrql ); 00545 00546 // 00547 // Loop and wait some more 00548 // 00549 } 00550 00551 // 00552 // Wait was satisfied 00553 // 00554 00555 ASSERT(NT_SUCCESS(Status)); 00556 return ; 00557 } 00558 00559 #if DBG 00560 VOID 00561 ExpAssertResourceDdk ( 00562 IN PNTDDK_ERESOURCE Resource 00563 ) 00564 { 00565 USHORT Sum; 00566 00567 // 00568 // Assert internal structures headers are correct 00569 // 00570 00571 ASSERT(Resource->SharedWaiters.Header.Type == SemaphoreObject); 00572 ASSERT(Resource->SharedWaiters.Header.Size == sizeof(KSEMAPHORE)); 00573 ASSERT(Resource->ExclusiveWaiters.Header.Type == SynchronizationEvent); 00574 ASSERT(Resource->ExclusiveWaiters.Header.Size == sizeof(KEVENT)); 00575 00576 // 00577 // Count number of currently owned threads 00578 // 00579 00580 Sum = Resource->OwnerCounts[0]; 00581 00582 // 00583 // Verify sum is consistent with what's in the resource 00584 // 00585 00586 ASSERT(Resource->ActiveCount == Sum); 00587 00588 if (Sum == 0) { 00589 ASSERT(!IsOwnedExclusive(Resource)); 00590 ASSERT(Resource->OwnerThreads[0] == 0); 00591 ASSERT(Resource->InitialOwnerThreads[0] == 0); 00592 } 00593 00594 if (Sum > 1) { 00595 ASSERT(!IsOwnedExclusive(Resource)); 00596 } 00597 00598 // 00599 // Verify resource flags appear correct 00600 // 00601 00602 if (IsOwnedExclusive(Resource)) { 00603 ASSERT (Sum == 1); 00604 ASSERT (Resource->OwnerCounts[0] != 0); 00605 ASSERT (Resource->OwnerThreads[0] == Resource->InitialOwnerThreads[0]); 00606 } 00607 } 00608 #endif // dbg 00609

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