00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#include "exp.h"
00027
#pragma hdrstop
00028
00029
#include <nturtl.h>
00030
00031
00032
00033
00034
00035 extern LARGE_INTEGER
ExpTimeout;
00036
00037
00038
00039
00040
00041 extern ULONG
ExpResourceTimeoutCount;
00042
00043
00044
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
00075
00076
00077 #define ExclusiveWaiter 0x01 // ** Also in i386\resoura.asm **
00078 #define SharedWaiter 0x02 // ** Also in i386\resoura.asm **
00079
00080 #define DisablePriorityBoost 0x08
00081
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
00096
00097
00098
00099 static KSPIN_LOCK
ExpResourceSpinLock;
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
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
00144
00145
00146
VOID
00147
ExpWaitForResourceDdk (
00148 IN
PNTDDK_ERESOURCE Resource,
00149 IN PVOID Object
00150 );
00151
00152
00153
00154
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
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 {
00193 ULONG i;
00194
00195
ASSERTMSG(
"A resource cannot be in paged pool ",
MmDeterminePoolType(
Resource) ==
NonPagedPool);
00196
00197
00198
00199
00200
00201
00202
00203
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
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
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
00286
00287
00288
AcquireResourceLock(
Resource, &OldIrql );
00289
00290
00291
00292
00293
00294
while (
TRUE) {
00295
if (
Resource->
ActiveCount == 0) {
00296
00297
00298
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
00315
00316
00317
Resource->OwnerCounts[0] += 1;
00318
ReleaseResourceLock(
Resource, OldIrql );
00319
return TRUE;
00320 }
00321
00322
00323
00324
00325
00326
00327
if (!Wait) {
00328
ReleaseResourceLock(
Resource, OldIrql );
00329
return FALSE;
00330 }
00331
00332
00333
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
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366 {
00367 KIRQL OldIrql;
00368
00369
ASSERT( OurThread != 0 );
00370
00371
00372
00373
00374
00375
AcquireResourceLock(
Resource, &OldIrql );
00376
00377
ASSERT(
Resource->
OwnerThreads[0] == OurThread );
00378
00379
00380
00381
00382
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
00395
00396
00397
Resource->
ActiveCount -= 1;
00398
00399
ASSERT(
Resource->
ActiveCount == 0 );
00400
00401
00402
00403
00404
00405
00406
if (
IsExclusiveWaiting(
Resource)) {
00407
00408
WakeExclusiveWaiters (
Resource );
00409 }
00410
00411
00412
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
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
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
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
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
00530
00531
00532
AcquireResourceLock(
Resource, &OldIrql );
00533
00534
if (
IsBoostAllowed(
Resource) &&
IsOwnedExclusive(
Resource)) {
00535
00536
00537
00538
00539
00540
KeBoostPriorityThread((
PKTHREAD)
Resource->
OwnerThreads[0],
00541
ERESOURCE_INCREMENT );
00542 }
00543
00544
ReleaseResourceLock(
Resource, OldIrql );
00545
00546
00547
00548
00549 }
00550
00551
00552
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
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
00578
00579
00580
Sum =
Resource->OwnerCounts[0];
00581
00582
00583
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
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