ReactOS 0.4.17-dev-672-gf9943c7
ExPushLock.c File Reference
#include <kmt_test.h>
Include dependency graph for ExPushLock.c:

Go to the source code of this file.

Classes

struct  PUSH_LOCK_TEST_STATE
 
struct  PUSH_LOCK_THREAD_CONTEXT
 

Macros

#define PUSH_LOCK_TIMEOUT_MS   5000
 
#define PUSH_LOCK_POLL_INTERVAL_MS   1
 
#define PUSH_LOCK_RELATIVE_TIMEOUT(Milliseconds)   (-((LONGLONG)(Milliseconds) * 10 * 1000))
 
#define PUSH_LOCK_MAX_WAITERS   4
 
#define PUSH_LOCK_RACE_ITERATIONS   64
 
#define PUSH_LOCK_CONTENTION_THREADS   6
 
#define PUSH_LOCK_CONTENTION_ITERATIONS   2048
 
#define PUSH_LOCK_CHECKSUM_XOR   0xA5A5A5A5UL
 

Typedefs

typedef enum PUSH_LOCK_MODE PUSH_LOCK_MODE
 
typedef enum PUSH_LOCK_RELEASE_KIND PUSH_LOCK_RELEASE_KIND
 
typedef enum PUSH_LOCK_WAIT_CHAIN_STATE PUSH_LOCK_WAIT_CHAIN_STATE
 
typedef struct PUSH_LOCK_TEST_STATE PUSH_LOCK_TEST_STATE
 
typedef struct PUSH_LOCK_TEST_STATEPPUSH_LOCK_TEST_STATE
 
typedef struct PUSH_LOCK_THREAD_CONTEXT PUSH_LOCK_THREAD_CONTEXT
 
typedef struct PUSH_LOCK_THREAD_CONTEXTPPUSH_LOCK_THREAD_CONTEXT
 

Enumerations

enum  PUSH_LOCK_MODE { PushLockModeShared , PushLockModeExclusive }
 
enum  PUSH_LOCK_RELEASE_KIND { PushLockReleaseSpecific , PushLockReleaseGeneric }
 
enum  PUSH_LOCK_WAIT_CHAIN_STATE { PushLockWaitChainInProgress , PushLockWaitChainStable , PushLockWaitChainInvalid }
 

Functions

 C_ASSERT (sizeof(EX_PUSH_LOCK)==sizeof(ULONG_PTR))
 
FORCEINLINE NTSTATUS PushLockWaitForEvent (_In_ PKEVENT Event)
 
FORCEINLINE VOID PushLockDelay (VOID)
 
static EX_PUSH_LOCK PushLockReadValue (_In_ PEX_PUSH_LOCK PushLock)
 
static BOOLEAN PushLockValueIsPlausible (_In_ EX_PUSH_LOCK Value)
 
FORCEINLINE VOID PushLockRecordViolation (_Inout_ PPUSH_LOCK_TEST_STATE State)
 
static VOID PushLockSampleState (_Inout_ PPUSH_LOCK_TEST_STATE State)
 
static VOID PushLockAcquire (_Inout_ PEX_PUSH_LOCK PushLock, _In_ PUSH_LOCK_MODE Mode)
 
static VOID PushLockRelease (_Inout_ PEX_PUSH_LOCK PushLock, _In_ PUSH_LOCK_MODE Mode, _In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
 
static VOID PushLockEnterProtectedRegion (_Inout_ PPUSH_LOCK_TEST_STATE State, _In_ PUSH_LOCK_MODE Mode)
 
static VOID PushLockLeaveProtectedRegion (_Inout_ PPUSH_LOCK_TEST_STATE State, _In_ PUSH_LOCK_MODE Mode)
 
static VOID PushLockReadProtectedValue (_Inout_ PPUSH_LOCK_TEST_STATE State)
 
static VOID PushLockWriteProtectedValue (_Inout_ PPUSH_LOCK_TEST_STATE State)
 
static VOID PushLockInitializeState (_Out_ PPUSH_LOCK_TEST_STATE State)
 
static VOID PushLockInitializeThreadContext (_Out_ PPUSH_LOCK_THREAD_CONTEXT Context, _Inout_ PPUSH_LOCK_TEST_STATE State, _In_ PUSH_LOCK_MODE Mode, _In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
 
static VOID NTAPI PushLockControlledThread (_In_ PVOID Parameter)
 
static BOOLEAN PushLockStartControlledThread (_Inout_ PPUSH_LOCK_THREAD_CONTEXT Context, _Out_ PKTHREAD *Thread)
 
static VOID PushLockReleaseAndFinishThread (_In_opt_ PKTHREAD Thread, _Inout_ PPUSH_LOCK_THREAD_CONTEXT Context)
 
static PUSH_LOCK_WAIT_CHAIN_STATE PushLockValidateWaitChain (_In_ PEX_PUSH_LOCK PushLock, _In_reads_(ExpectedCount) const PUSH_LOCK_MODE *ExpectedNewestFirst, _In_ ULONG ExpectedCount, _Out_opt_ PEX_PUSH_LOCK_WAIT_BLOCK *OldestWaitBlock)
 
static BOOLEAN PushLockWaitForStableWaitChain (_In_ PEX_PUSH_LOCK PushLock, _In_reads_(ExpectedCount) const PUSH_LOCK_MODE *ExpectedNewestFirst, _In_ ULONG ExpectedCount, _Out_opt_ PEX_PUSH_LOCK_WAIT_BLOCK *OldestWaitBlock)
 
static VOID TestPushLockUncontended (_In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
 
static VOID TestPushLockWaiterSelection (VOID)
 
static VOID TestPushLockSharedOwnerDrain (_In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
 
static VOID TestPushLockWaiterArrivalDuringRelease (VOID)
 
static VOID NTAPI PushLockContentionThread (_In_ PVOID Parameter)
 
static VOID TestPushLockContention (VOID)
 
 START_TEST (ExPushLock)
 

Macro Definition Documentation

◆ PUSH_LOCK_CHECKSUM_XOR

#define PUSH_LOCK_CHECKSUM_XOR   0xA5A5A5A5UL

Definition at line 21 of file ExPushLock.c.

◆ PUSH_LOCK_CONTENTION_ITERATIONS

#define PUSH_LOCK_CONTENTION_ITERATIONS   2048

Definition at line 19 of file ExPushLock.c.

◆ PUSH_LOCK_CONTENTION_THREADS

#define PUSH_LOCK_CONTENTION_THREADS   6

Definition at line 18 of file ExPushLock.c.

◆ PUSH_LOCK_MAX_WAITERS

#define PUSH_LOCK_MAX_WAITERS   4

Definition at line 15 of file ExPushLock.c.

◆ PUSH_LOCK_POLL_INTERVAL_MS

#define PUSH_LOCK_POLL_INTERVAL_MS   1

Definition at line 11 of file ExPushLock.c.

◆ PUSH_LOCK_RACE_ITERATIONS

#define PUSH_LOCK_RACE_ITERATIONS   64

Definition at line 17 of file ExPushLock.c.

◆ PUSH_LOCK_RELATIVE_TIMEOUT

#define PUSH_LOCK_RELATIVE_TIMEOUT (   Milliseconds)    (-((LONGLONG)(Milliseconds) * 10 * 1000))

Definition at line 13 of file ExPushLock.c.

◆ PUSH_LOCK_TIMEOUT_MS

#define PUSH_LOCK_TIMEOUT_MS   5000

Definition at line 10 of file ExPushLock.c.

Typedef Documentation

◆ PPUSH_LOCK_TEST_STATE

◆ PPUSH_LOCK_THREAD_CONTEXT

◆ PUSH_LOCK_MODE

◆ PUSH_LOCK_RELEASE_KIND

◆ PUSH_LOCK_TEST_STATE

◆ PUSH_LOCK_THREAD_CONTEXT

◆ PUSH_LOCK_WAIT_CHAIN_STATE

Enumeration Type Documentation

◆ PUSH_LOCK_MODE

Enumerator
PushLockModeShared 
PushLockModeExclusive 

Definition at line 23 of file ExPushLock.c.

24{
PUSH_LOCK_MODE
Definition: ExPushLock.c:24
@ PushLockModeShared
Definition: ExPushLock.c:25
@ PushLockModeExclusive
Definition: ExPushLock.c:26

◆ PUSH_LOCK_RELEASE_KIND

Enumerator
PushLockReleaseSpecific 
PushLockReleaseGeneric 

Definition at line 29 of file ExPushLock.c.

30{
PUSH_LOCK_RELEASE_KIND
Definition: ExPushLock.c:30
@ PushLockReleaseSpecific
Definition: ExPushLock.c:31
@ PushLockReleaseGeneric
Definition: ExPushLock.c:32

◆ PUSH_LOCK_WAIT_CHAIN_STATE

Enumerator
PushLockWaitChainInProgress 
PushLockWaitChainStable 
PushLockWaitChainInvalid 

Definition at line 35 of file ExPushLock.c.

36{
PUSH_LOCK_WAIT_CHAIN_STATE
Definition: ExPushLock.c:36
@ PushLockWaitChainInProgress
Definition: ExPushLock.c:37
@ PushLockWaitChainInvalid
Definition: ExPushLock.c:39
@ PushLockWaitChainStable
Definition: ExPushLock.c:38

Function Documentation

◆ C_ASSERT()

C_ASSERT ( sizeof(EX_PUSH_LOCK = =sizeof(ULONG_PTR))

◆ PushLockAcquire()

static VOID PushLockAcquire ( _Inout_ PEX_PUSH_LOCK  PushLock,
_In_ PUSH_LOCK_MODE  Mode 
)
static

Definition at line 187 of file ExPushLock.c.

190{
192 {
194 }
195 else
196 {
197 ExfAcquirePushLockShared(PushLock);
198 }
199}
_In_ ULONG Mode
Definition: hubbusif.h:303
VOID FASTCALL ExfAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
Definition: pushlock.c:471
VOID FASTCALL ExfAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
Definition: pushlock.c:645

Referenced by PushLockContentionThread(), and PushLockControlledThread().

◆ PushLockContentionThread()

static VOID NTAPI PushLockContentionThread ( _In_ PVOID  Parameter)
static

Definition at line 1213 of file ExPushLock.c.

1215{
1218 PUSH_LOCK_RELEASE_KIND ReleaseKind;
1220 ULONG Iteration;
1221
1223 State = Context->State;
1224
1225 KeSetEvent(&Context->ReadyEvent, IO_NO_INCREMENT, FALSE);
1226
1228 Executive,
1229 KernelMode,
1230 FALSE,
1231 NULL);
1232 if (Status != STATUS_SUCCESS)
1233 {
1235 KeSetEvent(&Context->DoneEvent, IO_NO_INCREMENT, FALSE);
1236 return;
1237 }
1238
1239 for (Iteration = 0; Iteration < Context->Iterations; Iteration++)
1240 {
1241 /* Alternate release per worker and iteration so every role uses
1242 both the generic and mode specific release functions */
1243 ReleaseKind = ((Iteration + Context->Index) & 1)
1246
1248
1249 PushLockAcquire(&State->Lock, Context->Mode);
1250 /* The ownership counters and protected value checks validate the
1251 exclusion contract without relying on the internal push lock fields */
1253
1254 if (Context->Mode == PushLockModeExclusive)
1255 {
1257 }
1258 else
1259 {
1261 }
1262
1264 PushLockRelease(&State->Lock, Context->Mode, ReleaseKind);
1265
1267
1268 InterlockedIncrement(&State->CompletedOperations);
1269
1270 /* Occasionally sample the encoded lock state and yield to increase useful nterleavings */
1271 if ((Iteration & 0x3f) == 0)
1272 {
1275 }
1276 }
1277
1278 KeSetEvent(&Context->DoneEvent, IO_NO_INCREMENT, FALSE);
1279}
static VOID PushLockEnterProtectedRegion(_Inout_ PPUSH_LOCK_TEST_STATE State, _In_ PUSH_LOCK_MODE Mode)
Definition: ExPushLock.c:229
static VOID PushLockSampleState(_Inout_ PPUSH_LOCK_TEST_STATE State)
Definition: ExPushLock.c:176
static VOID PushLockReadProtectedValue(_Inout_ PPUSH_LOCK_TEST_STATE State)
Definition: ExPushLock.c:294
static VOID PushLockWriteProtectedValue(_Inout_ PPUSH_LOCK_TEST_STATE State)
Definition: ExPushLock.c:317
static VOID PushLockAcquire(_Inout_ PEX_PUSH_LOCK PushLock, _In_ PUSH_LOCK_MODE Mode)
Definition: ExPushLock.c:187
static VOID PushLockLeaveProtectedRegion(_Inout_ PPUSH_LOCK_TEST_STATE State, _In_ PUSH_LOCK_MODE Mode)
Definition: ExPushLock.c:268
static VOID PushLockRelease(_Inout_ PEX_PUSH_LOCK PushLock, _In_ PUSH_LOCK_MODE Mode, _In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
Definition: ExPushLock.c:203
FORCEINLINE VOID PushLockRecordViolation(_Inout_ PPUSH_LOCK_TEST_STATE State)
Definition: ExPushLock.c:168
#define InterlockedIncrement
Definition: armddk.h:53
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
Status
Definition: gdiplustypes.h:24
#define KeLeaveCriticalRegion()
Definition: ke_x.h:119
#define KeEnterCriticalRegion()
Definition: ke_x.h:88
#define KernelMode
Definition: asm.h:38
#define YieldProcessor
Definition: ke.h:48
#define STATUS_SUCCESS
Definition: shellext.h:65
_In_ PVOID Context
Definition: storport.h:2269
State(char *beg, char *end)
uint32_t ULONG
Definition: typedefs.h:59
#define IO_NO_INCREMENT
Definition: iotypes.h:598
@ Executive
Definition: ketypes.h:467
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:336

Referenced by TestPushLockContention().

◆ PushLockControlledThread()

static VOID NTAPI PushLockControlledThread ( _In_ PVOID  Parameter)
static

Definition at line 373 of file ExPushLock.c.

375{
379
382
383 /* ReadyEvent reports only that the thread is running. It may still be held
384 behind StartGate and hasn't yet attempted to acquire the push lock. */
385 KeSetEvent(&Context->ReadyEvent, IO_NO_INCREMENT, FALSE);
386
387 if (Context->StartGate != NULL)
388 {
390 Executive,
392 FALSE,
393 NULL);
394 if (Status != STATUS_SUCCESS)
395 {
398 return;
399 }
400 }
401
403
404 PushLockAcquire(&State->Lock, Context->Mode);
406
407 /* Publish acquisition only after updating the ownership counters,
408 so the controlling thread can inspect a consistent protected
409 state after this event is signaled */
410 KeSetEvent(&Context->AcquiredEvent, IO_NO_INCREMENT, FALSE);
411
412 /* Remain inside the protected region until the test has inspected the lock
413 word and waiter chain for this acquisition */
414 Status = KeWaitForSingleObject(&Context->ReleaseEvent,
415 Executive,
417 FALSE,
418 NULL);
419 if (Status != STATUS_SUCCESS)
420 {
422 }
423
425 PushLockRelease(&State->Lock, Context->Mode, Context->ReleaseKind);
426
428
430}
struct PUSH_LOCK_THREAD_CONTEXT * PPUSH_LOCK_THREAD_CONTEXT

Referenced by PushLockStartControlledThread().

◆ PushLockDelay()

FORCEINLINE VOID PushLockDelay ( VOID  )

Definition at line 95 of file ExPushLock.c.

96{
97 LARGE_INTEGER Delay;
98
100
102}
#define PUSH_LOCK_RELATIVE_TIMEOUT(Milliseconds)
Definition: ExPushLock.c:13
#define PUSH_LOCK_POLL_INTERVAL_MS
Definition: ExPushLock.c:11
#define KeDelayExecutionThread(mode, foo, t)
Definition: env_spec_w32.h:484
LONGLONG QuadPart
Definition: typedefs.h:114

Referenced by PushLockWaitForStableWaitChain().

◆ PushLockEnterProtectedRegion()

static VOID PushLockEnterProtectedRegion ( _Inout_ PPUSH_LOCK_TEST_STATE  State,
_In_ PUSH_LOCK_MODE  Mode 
)
static

Definition at line 229 of file ExPushLock.c.

232{
233 LONG Count;
234
236 {
237 Count = InterlockedIncrement(&State->ActiveWriters);
238 if (Count != 1 || State->ActiveReaders != 0)
239 {
241 }
242
243 InterlockedIncrement(&State->ExclusiveAcquisitions);
244 }
245 else
246 {
247 /* Check on both sides of the reader increment. The second check detects a
248 writer that entered after the first load but before this reader published
249 itself. */
250 if (State->ActiveWriters != 0)
251 {
253 }
254
255 InterlockedIncrement(&State->ActiveReaders);
256
257 if (State->ActiveWriters != 0)
258 {
260 }
261
262 InterlockedIncrement(&State->SharedAcquisitions);
263 }
264}
int Count
Definition: noreturn.cpp:7
long LONG
Definition: pedump.c:60

Referenced by PushLockContentionThread(), and PushLockControlledThread().

◆ PushLockInitializeState()

static VOID PushLockInitializeState ( _Out_ PPUSH_LOCK_TEST_STATE  State)
static

Definition at line 337 of file ExPushLock.c.

339{
340 RtlZeroMemory(State, sizeof(*State));
341 State->SequenceInverse = ~(ULONG)0;
342 State->Checksum = PUSH_LOCK_CHECKSUM_XOR;
343}
#define PUSH_LOCK_CHECKSUM_XOR
Definition: ExPushLock.c:21
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262

Referenced by TestPushLockContention(), TestPushLockSharedOwnerDrain(), TestPushLockUncontended(), TestPushLockWaiterArrivalDuringRelease(), and TestPushLockWaiterSelection().

◆ PushLockInitializeThreadContext()

static VOID PushLockInitializeThreadContext ( _Out_ PPUSH_LOCK_THREAD_CONTEXT  Context,
_Inout_ PPUSH_LOCK_TEST_STATE  State,
_In_ PUSH_LOCK_MODE  Mode,
_In_ PUSH_LOCK_RELEASE_KIND  ReleaseKind 
)
static

Definition at line 347 of file ExPushLock.c.

352{
353 RtlZeroMemory(Context, sizeof(*Context));
354
355 Context->State = State;
356 Context->Mode = Mode;
357 Context->ReleaseKind = ReleaseKind;
358
363}
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
@ NotificationEvent

Referenced by TestPushLockContention(), TestPushLockSharedOwnerDrain(), TestPushLockWaiterArrivalDuringRelease(), and TestPushLockWaiterSelection().

◆ PushLockLeaveProtectedRegion()

static VOID PushLockLeaveProtectedRegion ( _Inout_ PPUSH_LOCK_TEST_STATE  State,
_In_ PUSH_LOCK_MODE  Mode 
)
static

Definition at line 268 of file ExPushLock.c.

271{
272 LONG Count;
273
275 {
276 Count = InterlockedDecrement(&State->ActiveWriters);
277 if (Count != 0)
278 {
280 }
281 }
282 else
283 {
284 Count = InterlockedDecrement(&State->ActiveReaders);
285 if (Count < 0)
286 {
288 }
289 }
290}
#define InterlockedDecrement
Definition: armddk.h:52

Referenced by PushLockContentionThread(), and PushLockControlledThread().

◆ PushLockReadProtectedValue()

static VOID PushLockReadProtectedValue ( _Inout_ PPUSH_LOCK_TEST_STATE  State)
static

Definition at line 294 of file ExPushLock.c.

296{
297 ULONG Sequence;
298 ULONG SequenceInverse;
299 ULONG Checksum;
300
301 /* A reader must observe all 3 fields from the same completed writer
302 update. Any mixture of old and new fields indicates overlap with an
303 x owner. */
304 Sequence = State->Sequence;
305 SequenceInverse = State->SequenceInverse;
306 Checksum = State->Checksum;
307
308 if (SequenceInverse != ~Sequence ||
309 Checksum != (Sequence ^ PUSH_LOCK_CHECKSUM_XOR))
310 {
312 }
313}

Referenced by PushLockContentionThread().

◆ PushLockReadValue()

static EX_PUSH_LOCK PushLockReadValue ( _In_ PEX_PUSH_LOCK  PushLock)
static

Definition at line 106 of file ExPushLock.c.

108{
110
111 /* Use a cmpxchg with identical xchg and comparand values as an
112 atomic read of the complete push lock word. A zero value remains zero,
113 and a nonzero value never matches the comparand, so the operation doesn't
114 modify the lock. */
115 Value.Ptr = InterlockedCompareExchangePointer(&PushLock->Ptr, NULL, NULL);
116
117 return Value;
118}
#define InterlockedCompareExchangePointer
Definition: interlocked.h:144
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413

Referenced by PushLockSampleState(), PushLockValidateWaitChain(), TestPushLockContention(), TestPushLockSharedOwnerDrain(), TestPushLockUncontended(), TestPushLockWaiterArrivalDuringRelease(), and TestPushLockWaiterSelection().

◆ PushLockRecordViolation()

◆ PushLockRelease()

static VOID PushLockRelease ( _Inout_ PEX_PUSH_LOCK  PushLock,
_In_ PUSH_LOCK_MODE  Mode,
_In_ PUSH_LOCK_RELEASE_KIND  ReleaseKind 
)
static

Definition at line 203 of file ExPushLock.c.

207{
208 if (ReleaseKind == PushLockReleaseGeneric)
209 {
210 ExfReleasePushLock(PushLock);
211 }
212 else if (Mode == PushLockModeExclusive)
213 {
215 }
216 else
217 {
218 ExfReleasePushLockShared(PushLock);
219 }
220}
VOID FASTCALL ExfReleasePushLock(PEX_PUSH_LOCK PushLock)
Definition: pushlock.c:810
VOID FASTCALL ExfReleasePushLockShared(PEX_PUSH_LOCK PushLock)
Definition: pushlock.c:972
VOID FASTCALL ExfReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
Definition: pushlock.c:1123

Referenced by PushLockContentionThread(), PushLockControlledThread(), TestPushLockSharedOwnerDrain(), TestPushLockUncontended(), and TestPushLockWaiterArrivalDuringRelease().

◆ PushLockReleaseAndFinishThread()

static VOID PushLockReleaseAndFinishThread ( _In_opt_ PKTHREAD  Thread,
_Inout_ PPUSH_LOCK_THREAD_CONTEXT  Context 
)
static

Definition at line 458 of file ExPushLock.c.

461{
463
464 if (Thread == NULL)
465 {
466 return;
467 }
468
469 KeSetEvent(&Context->ReleaseEvent, IO_NO_INCREMENT, FALSE);
470
471 Status = PushLockWaitForEvent(&Context->DoneEvent);
473
475}
FORCEINLINE NTSTATUS PushLockWaitForEvent(_In_ PKEVENT Event)
Definition: ExPushLock.c:79
#define ok_eq_hex(value, expected)
Definition: apitest.h:134
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
VOID KmtFinishThread(IN PKTHREAD Thread OPTIONAL, IN PKEVENT Event OPTIONAL)

Referenced by TestPushLockSharedOwnerDrain(), TestPushLockWaiterArrivalDuringRelease(), and TestPushLockWaiterSelection().

◆ PushLockSampleState()

static VOID PushLockSampleState ( _Inout_ PPUSH_LOCK_TEST_STATE  State)
static

Definition at line 176 of file ExPushLock.c.

178{
180 {
182 }
183}
static EX_PUSH_LOCK PushLockReadValue(_In_ PEX_PUSH_LOCK PushLock)
Definition: ExPushLock.c:106
static BOOLEAN PushLockValueIsPlausible(_In_ EX_PUSH_LOCK Value)
Definition: ExPushLock.c:127

Referenced by PushLockContentionThread().

◆ PushLockStartControlledThread()

static BOOLEAN PushLockStartControlledThread ( _Inout_ PPUSH_LOCK_THREAD_CONTEXT  Context,
_Out_ PKTHREAD Thread 
)
static

Definition at line 434 of file ExPushLock.c.

437{
439
441 if (*Thread == NULL)
442 {
443 ok(FALSE, "Could not create push-lock test thread\n");
444 return FALSE;
445 }
446
447 /* Don't examine the queue until the worker has started.
448 N.B. ReadyEvent doesn't imply that acquisition or queue
449 insertion has completed. */
450 Status = PushLockWaitForEvent(&Context->ReadyEvent);
452
453 return Status == STATUS_SUCCESS;
454}
static VOID NTAPI PushLockControlledThread(_In_ PVOID Parameter)
Definition: ExPushLock.c:373
#define ok(value,...)
Definition: atltest.h:57
PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL)

Referenced by TestPushLockSharedOwnerDrain(), TestPushLockWaiterArrivalDuringRelease(), and TestPushLockWaiterSelection().

◆ PushLockValidateWaitChain()

static PUSH_LOCK_WAIT_CHAIN_STATE PushLockValidateWaitChain ( _In_ PEX_PUSH_LOCK  PushLock,
_In_reads_(ExpectedCount) const PUSH_LOCK_MODE ExpectedNewestFirst,
_In_ ULONG  ExpectedCount,
_Out_opt_ PEX_PUSH_LOCK_WAIT_BLOCK OldestWaitBlock 
)
static

Definition at line 492 of file ExPushLock.c.

497{
499 EX_PUSH_LOCK CurrentValue;
501 PUSH_LOCK_MODE ActualNewestFirst[PUSH_LOCK_MAX_WAITERS];
506 ULONG ActualCount;
507 ULONG Index;
508 ULONG SeenIndex;
509 LONG Flags;
510
511 if (ExpectedCount == 0 || ExpectedCount > PUSH_LOCK_MAX_WAITERS)
512 {
514 }
515
516 Value = PushLockReadValue(PushLock);
517
519 {
521 }
522
523 /* The tests keep an owner in place while constructing the queue.
524 Waiting may still be clear until the expected waiter is inserted,
525 and Waking remains set while the list links are being optimized. */
526 if (!Value.Locked)
527 {
529 }
530
531 if (!Value.Waiting || Value.Waking)
532 {
534 }
535
537 if (!MmIsAddressValid(Head))
538 {
540 }
541
542 Last = Head->Last;
543 if (Last == NULL)
544 goto CheckForConcurrentChange;
545
546 if (((ULONG_PTR)Last & EX_PUSH_LOCK_PTR_BITS) != 0 || !MmIsAddressValid(Last))
547 {
549 }
550
551 RtlZeroMemory(Seen, sizeof(Seen));
552
553 Current = Head;
554 Previous = NULL;
555 ActualCount = 0;
556
557 for (Index = 0; Index < PUSH_LOCK_MAX_WAITERS; Index++)
558 {
559 if (Current == NULL)
560 {
562 }
563
564 if (!MmIsAddressValid(Current))
565 {
567 }
568
569 if (((ULONG_PTR)Current & EX_PUSH_LOCK_PTR_BITS) != 0)
570 {
572 }
573
574 for (SeenIndex = 0; SeenIndex < ActualCount; SeenIndex++)
575 {
576 if (Seen[SeenIndex] == Current)
577 {
579 }
580 }
581
582 Seen[ActualCount] = Current;
583
584 /* Previous links are built by ExpOptimizePushLockList. If the
585 push lock value changed while examining them, retry after the
586 concurrent insertion/optimization completes. */
587 if (Current->Previous != Previous)
588 {
589 goto CheckForConcurrentChange;
590 }
591
592 Flags = Current->Flags;
593
594 /* WAIT is the wake/sleep handshake bit and may already be clear.
595 EXCLUSIVE records the acquisition mode. No other flag bits are
596 valid for these wait blocks. */
598 {
600 }
601
602 ActualNewestFirst[ActualCount] = Flags & EX_PUSH_LOCK_FLAGS_EXCLUSIVE
605
606 ActualCount++;
607
608 if (Current == Last)
609 {
610 break;
611 }
612
613 Previous = Current;
614 Current = Current->Next;
615 }
616
617 if (Current != Last)
619
620 /* Make sure the lock word didn't change while the non-atomic wait block
621 links were being examined */
622 CurrentValue = PushLockReadValue(PushLock);
623 if (CurrentValue.Value != Value.Value)
624 {
626 }
627
628 /* A shorter chain means that not all expected waiters have been queued yet.
629 Additional waiters are invalid because the tests construct the queue in
630 controlled steps. */
631 if (ActualCount < ExpectedCount)
632 {
634 }
635
636 if (ActualCount > ExpectedCount)
637 {
639 }
640
641 for (Index = 0; Index < ExpectedCount; Index++)
642 {
643 /* EXCLUSIVE is the persistent mode bit, so the stable chain must
644 match the acquisition modes requested by the test */
645 if (ActualNewestFirst[Index] != ExpectedNewestFirst[Index])
646 {
648 }
649 }
650
651 if (OldestWaitBlock != NULL)
652 {
653 *OldestWaitBlock = Last;
654 }
655
657
658CheckForConcurrentChange:
659
660 CurrentValue = PushLockReadValue(PushLock);
661 if (CurrentValue.Value != Value.Value)
662 {
664 }
665
667}
#define PUSH_LOCK_MAX_WAITERS
Definition: ExPushLock.c:15
#define EX_PUSH_LOCK_PTR_BITS
Definition: Object.c:34
BOOLEAN NTAPI MmIsAddressValid(IN PVOID VirtualAddress)
Definition: mmsup.c:174
* PEX_PUSH_LOCK_WAIT_BLOCK
Definition: extypes.h:672
#define EX_PUSH_LOCK_FLAGS_EXCLUSIVE
Definition: extypes.h:162
#define EX_PUSH_LOCK_FLAGS_WAIT
Definition: extypes.h:164
ULONG_PTR Value
Definition: extypes.h:636
uint32_t ULONG_PTR
Definition: typedefs.h:65
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170

Referenced by PushLockWaitForStableWaitChain().

◆ PushLockValueIsPlausible()

static BOOLEAN PushLockValueIsPlausible ( _In_ EX_PUSH_LOCK  Value)
static

Definition at line 127 of file ExPushLock.c.

129{
130 ULONG_PTR WaitBlockAddress;
131
132 if (Value.Waking && !Value.Waiting)
133 {
134 return FALSE;
135 }
136
137 if (Value.MultipleShared && (!Value.Locked || !Value.Waiting))
138 {
139 return FALSE;
140 }
141
142 if (!Value.Waiting && (Value.Waking || Value.MultipleShared))
143 {
144 return FALSE;
145 }
146
147 if (!Value.Locked && !Value.Waiting && Value.Value != 0)
148 {
149 return FALSE;
150 }
151
152 /* When Waiting is set, the upper bits contain the address of the newest wait
153 block while the low bits retain the push lock flags */
154 if (Value.Waiting)
155 {
156 WaitBlockAddress = Value.Value & ~EX_PUSH_LOCK_PTR_BITS;
157 if (WaitBlockAddress == 0)
158 {
159 return FALSE;
160 }
161 }
162
163 return TRUE;
164}
#define TRUE
Definition: types.h:120

Referenced by PushLockSampleState(), and PushLockValidateWaitChain().

◆ PushLockWaitForEvent()

◆ PushLockWaitForStableWaitChain()

static BOOLEAN PushLockWaitForStableWaitChain ( _In_ PEX_PUSH_LOCK  PushLock,
_In_reads_(ExpectedCount) const PUSH_LOCK_MODE ExpectedNewestFirst,
_In_ ULONG  ExpectedCount,
_Out_opt_ PEX_PUSH_LOCK_WAIT_BLOCK OldestWaitBlock 
)
static

Definition at line 676 of file ExPushLock.c.

681{
683 ULONG Elapsed;
684
685 /* Queue insertion and list optimization are separate operations. Poll until
686 the waiter chain reaches the backward linked form required by the
687 structural checks below. */
688 for (Elapsed = 0;
689 Elapsed < PUSH_LOCK_TIMEOUT_MS;
691 {
692 ChainState = PushLockValidateWaitChain(PushLock,
693 ExpectedNewestFirst,
694 ExpectedCount,
695 OldestWaitBlock);
696
697 if (ChainState == PushLockWaitChainStable)
698 {
699 return TRUE;
700 }
701
702 if (ChainState == PushLockWaitChainInvalid)
703 {
704 return FALSE;
705 }
706
708 }
709
710 return FALSE;
711}
static PUSH_LOCK_WAIT_CHAIN_STATE PushLockValidateWaitChain(_In_ PEX_PUSH_LOCK PushLock, _In_reads_(ExpectedCount) const PUSH_LOCK_MODE *ExpectedNewestFirst, _In_ ULONG ExpectedCount, _Out_opt_ PEX_PUSH_LOCK_WAIT_BLOCK *OldestWaitBlock)
Definition: ExPushLock.c:492
FORCEINLINE VOID PushLockDelay(VOID)
Definition: ExPushLock.c:95

Referenced by TestPushLockSharedOwnerDrain(), TestPushLockWaiterArrivalDuringRelease(), and TestPushLockWaiterSelection().

◆ PushLockWriteProtectedValue()

static VOID PushLockWriteProtectedValue ( _Inout_ PPUSH_LOCK_TEST_STATE  State)
static

Definition at line 317 of file ExPushLock.c.

319{
320 ULONG Sequence;
321
322 /* Publish an intentionally inconsistent value while the update is in
323 progress. A reader entering concurrently is likely to observe
324 either an invalid inverse or an invalid checksum. */
325 Sequence = State->Sequence + 1;
326 State->Sequence = Sequence;
327 /* Keep the 3 stores ordered. N.B. The barriers aren't intended to replace
328 the synchronization supplied by the push lock. */
330 State->SequenceInverse = ~Sequence;
332 State->Checksum = Sequence ^ PUSH_LOCK_CHECKSUM_XOR;
333}
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58

Referenced by PushLockContentionThread().

◆ START_TEST()

START_TEST ( ExPushLock  )

Definition at line 1373 of file ExPushLock.c.

1374{
1377
1379
1382
1385}
static VOID TestPushLockSharedOwnerDrain(_In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
Definition: ExPushLock.c:901
static VOID TestPushLockWaiterSelection(VOID)
Definition: ExPushLock.c:772
static VOID TestPushLockUncontended(_In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
Definition: ExPushLock.c:716
static VOID TestPushLockContention(VOID)
Definition: ExPushLock.c:1283
static VOID TestPushLockWaiterArrivalDuringRelease(VOID)
Definition: ExPushLock.c:1120

◆ TestPushLockContention()

static VOID TestPushLockContention ( VOID  )
static

Definition at line 1283 of file ExPushLock.c.

1284{
1288 KEVENT StartGate;
1290 ULONG Index;
1291 ULONG Started;
1292 ULONG WriterCount;
1293 ULONG ReaderCount;
1294
1297
1298 Started = 0;
1299 WriterCount = 0;
1300 ReaderCount = 0;
1301
1303 {
1305
1306 /* Threads 0 and 3 are writers; the remaining 4 are readers */
1308
1310 {
1311 WriterCount++;
1312 }
1313 else
1314 {
1315 ReaderCount++;
1316 }
1317
1319 &State,
1320 Mode,
1322 Contexts[Index].StartGate = &StartGate;
1323 Contexts[Index].Index = Index;
1325
1327 &Contexts[Index]);
1328 if (Threads[Index] == NULL)
1329 {
1330 ok(FALSE, "Could not create contention thread %lu\n", Index);
1331 break;
1332 }
1333
1334 Started++;
1335
1336 Status = PushLockWaitForEvent(&Contexts[Index].ReadyEvent);
1338
1339 if (Status != STATUS_SUCCESS)
1340 {
1341 break;
1342 }
1343 }
1344
1345 /* Release all successfully created workers together so their first
1346 acquisitions contend on the same initially unlocked push lock */
1347 KeSetEvent(&StartGate, IO_NO_INCREMENT, FALSE);
1348
1349 for (Index = 0; Index < Started; Index++)
1350 {
1353 KmtFinishThread(Threads[Index], NULL);
1354 }
1355
1356 ok_eq_long(State.ActiveReaders, 0);
1357 ok_eq_long(State.ActiveWriters, 0);
1358 ok_eq_long(State.Violations, 0);
1359 ok_eq_long(State.CompletedOperations,
1361
1363 {
1364 ok_eq_long(State.ExclusiveAcquisitions,
1365 (LONG)(WriterCount * PUSH_LOCK_CONTENTION_ITERATIONS));
1366 ok_eq_long(State.SharedAcquisitions,
1367 (LONG)(ReaderCount * PUSH_LOCK_CONTENTION_ITERATIONS));
1368 }
1369
1371}
#define PUSH_LOCK_CONTENTION_ITERATIONS
Definition: ExPushLock.c:19
#define PUSH_LOCK_CONTENTION_THREADS
Definition: ExPushLock.c:18
static VOID PushLockInitializeThreadContext(_Out_ PPUSH_LOCK_THREAD_CONTEXT Context, _Inout_ PPUSH_LOCK_TEST_STATE State, _In_ PUSH_LOCK_MODE Mode, _In_ PUSH_LOCK_RELEASE_KIND ReleaseKind)
Definition: ExPushLock.c:347
static VOID NTAPI PushLockContentionThread(_In_ PVOID Parameter)
Definition: ExPushLock.c:1213
static VOID PushLockInitializeState(_Out_ PPUSH_LOCK_TEST_STATE State)
Definition: ExPushLock.c:337
@ Started
Definition: acpisys.h:14
#define ok_eq_long(value, expected)
Definition: apitest.h:119
#define ok_eq_ulongptr(value, expected)
Definition: apitest.h:128
static PFLT_CONTEXT_REGISTRATION Contexts

Referenced by START_TEST().

◆ TestPushLockSharedOwnerDrain()

static VOID TestPushLockSharedOwnerDrain ( _In_ PUSH_LOCK_RELEASE_KIND  ReleaseKind)
static

Definition at line 901 of file ExPushLock.c.

903{
904 /*
905 * shared
906 * shared
907 * shared
908 * |
909 * v
910 * exclusive waiter <- oldest, ShareCount = 3
911 * |
912 * v
913 * shared waiter <- newest
914 * |
915 * v
916 * release share ShareCount = 2, nobody wakes
917 * release share ShareCount = 1, nobody wakes
918 * release share ShareCount = 0
919 * |
920 * v
921 * exclusive wakes shared MUST remain queued
922 * |
923 * v
924 * exclusive releases
925 * |
926 * v
927 * shared wakes
928 */
929 static const PUSH_LOCK_MODE ExpectedExclusive[] = {PushLockModeExclusive};
930 static const PUSH_LOCK_MODE ExpectedBoth[] = {PushLockModeShared, PushLockModeExclusive};
931 static const PUSH_LOCK_MODE ExpectedShared[] = {PushLockModeShared};
933 PUSH_LOCK_THREAD_CONTEXT ExclusiveContext;
934 PUSH_LOCK_THREAD_CONTEXT SharedContext;
935 PKTHREAD ExclusiveThread;
936 PKTHREAD SharedThread;
937 PEX_PUSH_LOCK_WAIT_BLOCK OldestWaitBlock;
941 ULONG Count;
942
944 ExclusiveThread = NULL;
945 SharedThread = NULL;
946 OldestWaitBlock = NULL;
947
948 PushLockInitializeThreadContext(&ExclusiveContext,
949 &State,
952
953 PushLockInitializeThreadContext(&SharedContext,
954 &State,
957
959
960 /* 3 shared acquisitions force the 1st x waiter to use
961 MultipleShared and store the outstanding count in its wait block */
962 for (Count = 0; Count < 3; Count++)
963 {
965 }
966
967 if (!PushLockStartControlledThread(&ExclusiveContext, &ExclusiveThread))
968 {
969 goto Cleanup;
970 }
971
973 ExpectedExclusive,
974 RTL_NUMBER_OF(ExpectedExclusive),
975 &OldestWaitBlock);
976 ok(Success, "Exclusive waiter did not reach a stable wait state\n");
977 if (!Success)
978 {
979 goto Cleanup;
980 }
981
982 /* Queue an s waiter after the x waiter. Since Waiting is already set,
983 it must queue instead of joining the current s owners */
984 if (!PushLockStartControlledThread(&SharedContext, &SharedThread))
985 {
986 goto Cleanup;
987 }
988
990 ExpectedBoth,
991 RTL_NUMBER_OF(ExpectedBoth),
992 &OldestWaitBlock);
993 ok(Success, "Exclusive/shared wait chain did not stabilize\n");
994 if (!Success)
995 {
996 goto Cleanup;
997 }
998
1000 ok(Value.Locked, "Push lock is not locked\n");
1001 ok(Value.Waiting, "Push lock has no waiters\n");
1002 ok(!Value.Waking, "Push lock is waking\n");
1003 ok(Value.MultipleShared, "MultipleShared is not set\n");
1004
1005 if (OldestWaitBlock != NULL)
1006 {
1007 ok_eq_long(OldestWaitBlock->ShareCount, 3);
1008 ok(OldestWaitBlock->Flags & EX_PUSH_LOCK_FLAGS_EXCLUSIVE, "Oldest waiter is not exclusive\n");
1009 }
1010
1011 /* The first 2 releases only decrement the saved shared count.
1012 Neither waiter may acquire while an existing s owner remains. */
1013 for (Count = 3; Count > 1; Count--)
1014 {
1015 PushLockRelease(&State.Lock, PushLockModeShared, ReleaseKind);
1016
1017 if (OldestWaitBlock != NULL)
1018 {
1019 ok_eq_long(OldestWaitBlock->ShareCount, Count - 1);
1020 }
1021
1022 Value = PushLockReadValue(&State.Lock);
1023 ok(Value.Locked, "Push lock is not locked while shares remain\n");
1024 ok(Value.Waiting, "Push lock has no waiters while shares remain\n");
1025 ok(Value.MultipleShared, "MultipleShared is not set while shares remain\n");
1026
1027 ok_eq_long(KeReadStateEvent(&ExclusiveContext.AcquiredEvent), 0);
1028 ok_eq_long(KeReadStateEvent(&SharedContext.AcquiredEvent), 0);
1029 }
1030
1031 /* The final s release must select the oldest x waiter.
1032 The newer s waiter must remain queued behind it. */
1033 PushLockRelease(&State.Lock, PushLockModeShared, ReleaseKind);
1034
1036
1037 Status = PushLockWaitForEvent(&ExclusiveContext.AcquiredEvent);
1039
1040 if (Status != STATUS_SUCCESS)
1041 {
1042 /* Allow either waiter to finish if the expected handoff failed.
1043 Signaling both avoids making cleanup depend on which one acquired. */
1044 KeSetEvent(&ExclusiveContext.ReleaseEvent, IO_NO_INCREMENT, FALSE);
1045 KeSetEvent(&SharedContext.ReleaseEvent, IO_NO_INCREMENT, FALSE);
1046
1047 PushLockReleaseAndFinishThread(ExclusiveThread, &ExclusiveContext);
1048 PushLockReleaseAndFinishThread(SharedThread, &SharedContext);
1049 return;
1050 }
1051
1052 ok_eq_long(KeReadStateEvent(&SharedContext.AcquiredEvent), 0);
1053 ok_eq_long(State.ActiveWriters, 1);
1054 ok_eq_long(State.ActiveReaders, 0);
1055
1056 /* While the x waiter owns the lock, the newer s waiter must still be
1057 the complete remaining wait chain */
1059 ExpectedShared,
1060 RTL_NUMBER_OF(ExpectedShared),
1061 NULL);
1062 ok(Success, "Shared waiter did not remain queued behind the exclusive owner\n");
1063
1064 /* Releasing the x owner now permits the remaining s waiter to acquire */
1065 PushLockReleaseAndFinishThread(ExclusiveThread, &ExclusiveContext);
1066 ExclusiveThread = NULL;
1067
1068 Status = PushLockWaitForEvent(&SharedContext.AcquiredEvent);
1070
1071 if (Status == STATUS_SUCCESS)
1072 {
1073 ok_eq_long(State.ActiveWriters, 0);
1074 ok_eq_long(State.ActiveReaders, 1);
1075 }
1076
1077 PushLockReleaseAndFinishThread(SharedThread, &SharedContext);
1078 SharedThread = NULL;
1079
1080 ok_eq_long(State.ActiveReaders, 0);
1081 ok_eq_long(State.ActiveWriters, 0);
1082 ok_eq_long(State.Violations, 0);
1084
1085 return;
1086
1087Cleanup:
1088
1089 /* Let any successfully started waiter leave immediately after acquiring,
1090 regardless of how far queue construction progressed */
1091 if (ExclusiveThread != NULL)
1092 {
1093 KeSetEvent(&ExclusiveContext.ReleaseEvent, IO_NO_INCREMENT, FALSE);
1094 }
1095
1096 if (SharedThread != NULL)
1097 {
1098 KeSetEvent(&SharedContext.ReleaseEvent, IO_NO_INCREMENT, FALSE);
1099 }
1100
1101 for (Count = 0; Count < 3; Count++)
1102 {
1103 PushLockRelease(&State.Lock, PushLockModeShared, ReleaseKind);
1104 }
1105
1107
1108 PushLockReleaseAndFinishThread(ExclusiveThread, &ExclusiveContext);
1109 PushLockReleaseAndFinishThread(SharedThread, &SharedContext);
1110}
static VOID PushLockReleaseAndFinishThread(_In_opt_ PKTHREAD Thread, _Inout_ PPUSH_LOCK_THREAD_CONTEXT Context)
Definition: ExPushLock.c:458
static BOOLEAN PushLockStartControlledThread(_Inout_ PPUSH_LOCK_THREAD_CONTEXT Context, _Out_ PKTHREAD *Thread)
Definition: ExPushLock.c:434
static BOOLEAN PushLockWaitForStableWaitChain(_In_ PEX_PUSH_LOCK PushLock, _In_reads_(ExpectedCount) const PUSH_LOCK_MODE *ExpectedNewestFirst, _In_ ULONG ExpectedCount, _Out_opt_ PEX_PUSH_LOCK_WAIT_BLOCK *OldestWaitBlock)
Definition: ExPushLock.c:676
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
unsigned char BOOLEAN
Definition: actypes.h:127
static const WCHAR Cleanup[]
Definition: register.c:80
@ Success
Definition: eventcreate.c:712
LONG NTAPI KeReadStateEvent(IN PKEVENT Event)
Definition: eventobj.c:121

Referenced by START_TEST().

◆ TestPushLockUncontended()

static VOID TestPushLockUncontended ( _In_ PUSH_LOCK_RELEASE_KIND  ReleaseKind)
static

Definition at line 716 of file ExPushLock.c.

718{
721 ULONG Count;
722
724 ok_eq_ulongptr(State.Lock.Value, 0);
725
727
728 /* An uncontended exclusive acquisition is represented by the Locked bit alone */
731
732 PushLockRelease(&State.Lock, PushLockModeExclusive, ReleaseKind);
734
735 /* In the uncontended shared form, the lock word contains Locked plus one
736 EX_PUSH_LOCK_SHARE_INC for each shared acquisition */
737 for (Count = 1; Count <= 4; Count++)
738 {
742 }
743
744 /* Verify every intermediate shared count, including the transition from the
745 final shared owner back to the zero lock word */
746 for (Count = 4; Count > 0; Count--)
747 {
748 PushLockRelease(&State.Lock, PushLockModeShared, ReleaseKind);
750
751 if (Count == 1)
752 {
753 ok_eq_ulongptr(Value.Value, 0);
754 }
755 else
756 {
757 ok_eq_ulongptr(Value.Value,
759 }
760 }
761
763}
#define EX_PUSH_LOCK_SHARE_INC
Definition: Object.c:33
#define EX_PUSH_LOCK_LOCK
Definition: Object.c:29

Referenced by START_TEST().

◆ TestPushLockWaiterArrivalDuringRelease()

static VOID TestPushLockWaiterArrivalDuringRelease ( VOID  )
static

Definition at line 1120 of file ExPushLock.c.

1121{
1122 static const PUSH_LOCK_MODE ExpectedOldest[] = {PushLockModeExclusive};
1124 PUSH_LOCK_THREAD_CONTEXT OldestContext;
1125 PUSH_LOCK_THREAD_CONTEXT NewestContext;
1126 PKTHREAD OldestThread;
1127 PKTHREAD NewestThread;
1128 KEVENT StartGate;
1129 PUSH_LOCK_RELEASE_KIND ReleaseKind;
1130 ULONG Iteration;
1131
1132 for (Iteration = 0; Iteration < PUSH_LOCK_RACE_ITERATIONS; Iteration++)
1133 {
1135 OldestThread = NULL;
1136 NewestThread = NULL;
1138
1141
1142 PushLockInitializeThreadContext(&OldestContext,
1143 &State,
1146 if (!PushLockStartControlledThread(&OldestContext, &OldestThread))
1147 {
1150 PushLockReleaseAndFinishThread(OldestThread, &OldestContext);
1151 continue;
1152 }
1153
1154 ok(PushLockWaitForStableWaitChain(&State.Lock, ExpectedOldest,
1155 RTL_NUMBER_OF(ExpectedOldest), NULL),
1156 "Oldest waiter did not stabilize at iteration %lu\n",
1157 Iteration);
1158
1159 PushLockInitializeThreadContext(&NewestContext,
1160 &State,
1163 NewestContext.StartGate = &StartGate;
1164
1165 if (!PushLockStartControlledThread(&NewestContext, &NewestThread))
1166 {
1167 KeSetEvent(&StartGate, IO_NO_INCREMENT, FALSE);
1170 PushLockReleaseAndFinishThread(OldestThread, &OldestContext);
1171 PushLockReleaseAndFinishThread(NewestThread, &NewestContext);
1172 continue;
1173 }
1174
1175 /* Don't hold either waiter after acquisition. The test is interested in
1176 completion of the entire queue, not in inspecting an intermediate owner... */
1177 KeSetEvent(&OldestContext.ReleaseEvent, IO_NO_INCREMENT, FALSE);
1178 KeSetEvent(&NewestContext.ReleaseEvent, IO_NO_INCREMENT, FALSE);
1179
1180 /* Exercise the same arrival window through both the s specific and
1181 generic release */
1182 ReleaseKind = (Iteration & 1)
1185
1186 /* Make the new waiter ready immediately before the final shared release.
1187 The scheduler may insert it before or during the release. This can't
1188 force the exact load/CAS interleaving, but repeatedly exposes the
1189 implementation to the execution found by the tla */
1190 KeSetEvent(&StartGate, IO_NO_INCREMENT, FALSE);
1191 PushLockRelease(&State.Lock, PushLockModeShared, ReleaseKind);
1192
1194
1195 PushLockReleaseAndFinishThread(OldestThread, &OldestContext);
1196 PushLockReleaseAndFinishThread(NewestThread, &NewestContext);
1197
1198 ok_eq_long(KeReadStateEvent(&OldestContext.AcquiredEvent), 1);
1199 ok_eq_long(KeReadStateEvent(&NewestContext.AcquiredEvent), 1);
1200 ok_eq_long(State.Violations, 0);
1202 }
1203}
#define PUSH_LOCK_RACE_ITERATIONS
Definition: ExPushLock.c:17

Referenced by START_TEST().

◆ TestPushLockWaiterSelection()

static VOID TestPushLockWaiterSelection ( VOID  )
static

Definition at line 772 of file ExPushLock.c.

773{
774 static const PUSH_LOCK_MODE Modes[] = {
778 };
779 static const PUSH_LOCK_MODE ExpectedOne[] = {PushLockModeExclusive};
780 static const PUSH_LOCK_MODE ExpectedTwo[] = {
783 };
784 static const PUSH_LOCK_MODE ExpectedThree[] = {
788 };
789 static const PUSH_LOCK_MODE ExpectedReaders[] = {
792 };
793 const PUSH_LOCK_MODE *Expected[] = {
794 ExpectedOne,
795 ExpectedTwo,
796 ExpectedThree
797 };
800 PKTHREAD Threads[RTL_NUMBER_OF(Modes)] = {NULL};
803 ULONG Index;
804
806 Started = 0;
807
808 /* Hold the lock while constructing the waiter chain. Starting each waiter
809 separately makes the newest-to-oldest order deterministic. */
810
812
814
815 /* The resulting chains are:
816 o exclusive
817 o shared -> exclusive
818 o shared -> shared -> exclusive
819 where the leftmost entry is the newest waiter */
820
821 for (Index = 0; Index < RTL_NUMBER_OF(Modes); Index++)
822 {
824 &State,
825 Modes[Index],
827
829 {
830 if (Threads[Index] != NULL)
831 {
832 Started++;
833 }
834 break;
835 }
836
837 Started++;
838
840 "Wait chain did not stabilize after waiter %lu\n", Index);
841 }
842
843 /* The oldest waiter is exclusive, so releasing the owner must select only
844 that waiter and leave both shared waiters queued */
846
848
850 {
851 Status = PushLockWaitForEvent(&Contexts[0].AcquiredEvent);
853
854 ok_eq_long(KeReadStateEvent(&Contexts[1].AcquiredEvent), 0);
855 ok_eq_long(KeReadStateEvent(&Contexts[2].AcquiredEvent), 0);
856
857 /* Once the x waiter owns the lock, the two newer s waiters must
858 still form the complete remaining wait chain */
859 ok(PushLockWaitForStableWaitChain(&State.Lock, ExpectedReaders,
860 RTL_NUMBER_OF(ExpectedReaders), NULL),
861 "Reader wait chain is invalid while the writer owns the lock\n");
862
863 /* Releasing the oldest x waiter permits the remaining s batch to acquire together */
865 Threads[0] = NULL;
866
867 Status = PushLockWaitForEvent(&Contexts[1].AcquiredEvent);
869 Status = PushLockWaitForEvent(&Contexts[2].AcquiredEvent);
871
872 ok_eq_long(State.ActiveReaders, 2);
873 ok_eq_long(State.ActiveWriters, 0);
876 }
877
878 for (Index = 0; Index < Started; Index++)
879 {
880 if (Threads[Index] != NULL)
881 {
883 Threads[Index] = NULL;
884 }
885 }
886
887 ok_eq_long(State.ActiveReaders, 0);
888 ok_eq_long(State.ActiveWriters, 0);
889 ok_eq_long(State.Violations, 0);
891}
BOOLEAN Expected
static const VBE_MODE Modes[VBE_MODE_COUNT]
Definition: vbe.c:189

Referenced by START_TEST().