test: ddkresrc.c Source File

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