ReactOS 0.4.16-dev-338-g34e76ad
condvar.c File Reference
#include <rtl_vista.h>
#include <debug.h>
Include dependency graph for condvar.c:

Go to the source code of this file.

Classes

struct  _COND_VAR_WAIT_ENTRY
 

Macros

#define NDEBUG
 
#define COND_VAR_UNUSED_FLAG   ((ULONG_PTR)1)
 
#define COND_VAR_LOCKED_FLAG   ((ULONG_PTR)2)
 
#define COND_VAR_FLAGS_MASK   ((ULONG_PTR)3)
 
#define COND_VAR_ADDRESS_MASK   (~COND_VAR_FLAGS_MASK)
 
#define CONTAINING_COND_VAR_WAIT_ENTRY(address, field)    CONTAINING_RECORD(address, COND_VAR_WAIT_ENTRY, field)
 

Typedefs

typedef struct _COND_VAR_WAIT_ENTRY COND_VAR_WAIT_ENTRY
 
typedef struct _COND_VAR_WAIT_ENTRYPCOND_VAR_WAIT_ENTRY
 

Functions

FORCEINLINE ULONG_PTR InternalCmpXChgCondVarAcq (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN ULONG_PTR Exchange, IN ULONG_PTR Comperand)
 
FORCEINLINE ULONG_PTR InternalCmpXChgCondVarRel (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN ULONG_PTR Exchange, IN ULONG_PTR Comperand)
 
FORCEINLINE BOOLEANInternalGetListRemovalHandledFlag (IN PCOND_VAR_WAIT_ENTRY Entry)
 
static PCOND_VAR_WAIT_ENTRY InternalLockCondVar (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN PCOND_VAR_WAIT_ENTRY InsertEntry OPTIONAL, IN BOOLEAN *AbortIfLocked OPTIONAL)
 
static VOID InternalUnlockCondVar (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN PCOND_VAR_WAIT_ENTRY RemoveEntry OPTIONAL)
 
static VOID InternalWake (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN BOOLEAN ReleaseAll)
 
VOID NTAPI RtlAcquireSRWLockExclusive (IN OUT PRTL_SRWLOCK SRWLock)
 
VOID NTAPI RtlAcquireSRWLockShared (IN OUT PRTL_SRWLOCK SRWLock)
 
VOID NTAPI RtlReleaseSRWLockExclusive (IN OUT PRTL_SRWLOCK SRWLock)
 
VOID NTAPI RtlReleaseSRWLockShared (IN OUT PRTL_SRWLOCK SRWLock)
 
static NTSTATUS InternalSleep (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN OUT PRTL_CRITICAL_SECTION CriticalSection OPTIONAL, IN OUT PRTL_SRWLOCK SRWLock OPTIONAL, IN ULONG SRWFlags, IN const LARGE_INTEGER *TimeOut OPTIONAL)
 
VOID NTAPI RtlpInitializeKeyedEvent (VOID)
 
VOID NTAPI RtlpCloseKeyedEvent (VOID)
 
VOID NTAPI RtlInitializeConditionVariable (OUT PRTL_CONDITION_VARIABLE ConditionVariable)
 
VOID NTAPI RtlWakeConditionVariable (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable)
 
VOID NTAPI RtlWakeAllConditionVariable (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable)
 
NTSTATUS NTAPI RtlSleepConditionVariableCS (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN OUT PRTL_CRITICAL_SECTION CriticalSection, IN PLARGE_INTEGER TimeOut OPTIONAL)
 
NTSTATUS NTAPI RtlSleepConditionVariableSRW (IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN OUT PRTL_SRWLOCK SRWLock, IN PLARGE_INTEGER TimeOut OPTIONAL, IN ULONG Flags)
 

Variables

static HANDLE CondVarKeyedEventHandle = NULL
 

Macro Definition Documentation

◆ COND_VAR_ADDRESS_MASK

#define COND_VAR_ADDRESS_MASK   (~COND_VAR_FLAGS_MASK)

Definition at line 26 of file condvar.c.

◆ COND_VAR_FLAGS_MASK

#define COND_VAR_FLAGS_MASK   ((ULONG_PTR)3)

Definition at line 25 of file condvar.c.

◆ COND_VAR_LOCKED_FLAG

#define COND_VAR_LOCKED_FLAG   ((ULONG_PTR)2)

Definition at line 24 of file condvar.c.

◆ COND_VAR_UNUSED_FLAG

#define COND_VAR_UNUSED_FLAG   ((ULONG_PTR)1)

Definition at line 23 of file condvar.c.

◆ CONTAINING_COND_VAR_WAIT_ENTRY

#define CONTAINING_COND_VAR_WAIT_ENTRY (   address,
  field 
)     CONTAINING_RECORD(address, COND_VAR_WAIT_ENTRY, field)

Definition at line 37 of file condvar.c.

◆ NDEBUG

#define NDEBUG

Definition at line 18 of file condvar.c.

Typedef Documentation

◆ COND_VAR_WAIT_ENTRY

◆ PCOND_VAR_WAIT_ENTRY

Function Documentation

◆ InternalCmpXChgCondVarAcq()

FORCEINLINE ULONG_PTR InternalCmpXChgCondVarAcq ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN ULONG_PTR  Exchange,
IN ULONG_PTR  Comperand 
)

Definition at line 48 of file condvar.c.

51{
52 return (ULONG_PTR)InterlockedCompareExchangePointerAcquire(&ConditionVariable->Ptr,
53 (PVOID)Exchange,
54 (PVOID)Comperand);
55}
#define InterlockedCompareExchangePointerAcquire
Definition: interlocked.h:130
uint32_t ULONG_PTR
Definition: typedefs.h:65

Referenced by InternalLockCondVar().

◆ InternalCmpXChgCondVarRel()

FORCEINLINE ULONG_PTR InternalCmpXChgCondVarRel ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN ULONG_PTR  Exchange,
IN ULONG_PTR  Comperand 
)

Definition at line 59 of file condvar.c.

62{
63 return (ULONG_PTR)InterlockedCompareExchangePointerRelease(&ConditionVariable->Ptr,
64 (PVOID)Exchange,
65 (PVOID)Comperand);
66}
#define InterlockedCompareExchangePointerRelease
Definition: interlocked.h:131

Referenced by InternalUnlockCondVar().

◆ InternalGetListRemovalHandledFlag()

FORCEINLINE BOOLEAN * InternalGetListRemovalHandledFlag ( IN PCOND_VAR_WAIT_ENTRY  Entry)

Definition at line 70 of file condvar.c.

71{
72 return (BOOLEAN *)&Entry->ListRemovalHandled;
73}
unsigned char BOOLEAN
base of all file and directory entries
Definition: entries.h:83

Referenced by InternalSleep(), and InternalWake().

◆ InternalLockCondVar()

static PCOND_VAR_WAIT_ENTRY InternalLockCondVar ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN PCOND_VAR_WAIT_ENTRY InsertEntry  OPTIONAL,
IN BOOLEAN *AbortIfLocked  OPTIONAL 
)
static

Definition at line 77 of file condvar.c.

80{
81 /* InsertEntry and AbortIfLocked may be NULL on entry. This routine
82 will return NULL if the lock was not acquired. Otherwise it has
83 successfully acquired the lock and the return value is a valid
84 reference to the list head associated with ConditionVariable.
85 The caller must in this case call InternalUnlockCondVar later
86 in order to unlock the condition variable.
87
88 If InsertEntry is NULL and there are no entries on the list, this
89 routine will not acquire the lock and return NULL. If InsertEntry
90 is not NULL this routine ensures that InsertEntry will be on the
91 list when it returns successfully.
92
93 If the lock is owned by another thread and AbortIfLocked is NULL,
94 this routine will block until it acquires the lock. If AbortIfLocked
95 is not NULL and the lock is owned by another thread, this routine
96 will periodically check if *AbortIfLocked is nonzero and if so, will
97 return NULL instead of continuing the wait. */
98
99 ULONG_PTR OldVal = (ULONG_PTR)ConditionVariable->Ptr;
100
101 for (;;)
102 {
103 ULONG_PTR NewVal, LockRes;
104 PLIST_ENTRY OldListHead;
105
106 if (OldVal & COND_VAR_LOCKED_FLAG)
107 {
108 /* The locked flag is set, indicating someone else currently
109 holds the lock. We'll spin until this flag becomes
110 clear or we're asked to abort. */
112
113 if ((AbortIfLocked != NULL) && *AbortIfLocked)
114 {
115 /* The caller wants us to abort in this case. */
116 return NULL;
117 }
118
119 /* Refresh OldVal and try again. */
120 OldVal = *(ULONG_PTR *)&ConditionVariable->Ptr;
121 continue;
122 }
123
124 /* Retrieve the list head currently associated with the
125 condition variable. */
126 OldListHead = (PLIST_ENTRY)(OldVal & COND_VAR_ADDRESS_MASK);
127 if (InsertEntry == NULL)
128 {
129 /* The caller doesn't want to put any entry on the list. */
130 if (OldListHead == NULL)
131 {
132 /* The list is empty, so there is nothing to lock. */
133 return NULL;
134 }
135
136 /* The list isn't empty. In this case we need to preserve
137 all of OldVal. */
138 NewVal = OldVal;
139 }
140 else
141 {
142 /* Let InsertEntry be the new list head. Preserve only the
143 bits inside the COND_VAR_FLAGS_MASK range. */
144 NewVal = ((OldVal & COND_VAR_FLAGS_MASK) |
145 (ULONG_PTR)&InsertEntry->ListEntry);
146 }
147
148 /* Set the flag that indicates someone is holding the lock and
149 try to update the condition variable thread-safe. */
150 NewVal |= COND_VAR_LOCKED_FLAG;
151 LockRes = InternalCmpXChgCondVarAcq(ConditionVariable, NewVal, OldVal);
152 if (LockRes == OldVal)
153 {
154 /* We successfully updated ConditionVariable the way we
155 wanted and now hold the lock. */
156 if (InsertEntry == NULL)
157 {
158 /* We know that OldVal contains a valid address in
159 this case. */
160 ASSERT(OldListHead != NULL);
161 return CONTAINING_COND_VAR_WAIT_ENTRY(OldListHead, ListEntry);
162 }
163
164 /* InsertEntry is not on the list yet, so add it. In any
165 case InsertEntry will be the new list head. */
166 if (OldListHead == NULL)
167 {
168 /* List was empty before. */
169 InitializeListHead(&InsertEntry->ListEntry);
170 }
171 else
172 {
173 /* Make InsertEntry the last entry of the old list.
174 As InsertEntry will take the role as new list head,
175 OldListHead will become the second entry (InsertEntry->Flink)
176 on the new list. */
177 InsertTailList(OldListHead, &InsertEntry->ListEntry);
178 }
179
180 return InsertEntry;
181 }
182
183 /* We didn't manage to update ConditionVariable, so try again. */
184 OldVal = LockRes;
185 }
186}
#define COND_VAR_FLAGS_MASK
Definition: condvar.c:25
FORCEINLINE ULONG_PTR InternalCmpXChgCondVarAcq(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN ULONG_PTR Exchange, IN ULONG_PTR Comperand)
Definition: condvar.c:48
#define COND_VAR_ADDRESS_MASK
Definition: condvar.c:26
#define CONTAINING_COND_VAR_WAIT_ENTRY(address, field)
Definition: condvar.c:37
#define COND_VAR_LOCKED_FLAG
Definition: condvar.c:24
#define NULL
Definition: types.h:112
#define ULONG_PTR
Definition: config.h:101
#define InsertTailList(ListHead, Entry)
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define ASSERT(a)
Definition: mode.c:44
#define for
Definition: utility.h:88
#define YieldProcessor
Definition: ke.h:48
Definition: typedefs.h:120
struct _LIST_ENTRY * PLIST_ENTRY

Referenced by InternalSleep(), and InternalWake().

◆ InternalSleep()

static NTSTATUS InternalSleep ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN OUT PRTL_CRITICAL_SECTION CriticalSection  OPTIONAL,
IN OUT PRTL_SRWLOCK SRWLock  OPTIONAL,
IN ULONG  SRWFlags,
IN const LARGE_INTEGER *TimeOut  OPTIONAL 
)
static

Definition at line 367 of file condvar.c.

372{
373 /* Either CriticalSection or SRWLock must be NULL, but not both.
374 These caller provided lock must be held on entry and will be
375 held again on return. */
376
377 COND_VAR_WAIT_ENTRY OwnEntry;
379
381 ASSERT((CriticalSection == NULL) != (SRWLock == NULL));
382
383 RtlZeroMemory(&OwnEntry, sizeof(OwnEntry));
384
385 /* Put OwnEntry on the list. */
386 InternalLockCondVar(ConditionVariable, &OwnEntry, NULL);
387 InternalUnlockCondVar(ConditionVariable, NULL);
388
389 /* We can now drop the caller provided lock as a preparation for
390 going to sleep. */
391 if (CriticalSection == NULL)
392 {
393 if (0 == (RTL_CONDITION_VARIABLE_LOCKMODE_SHARED & SRWFlags))
394 {
396 }
397 else
398 {
400 }
401 }
402 else
403 {
405 }
406
407 /* Now sleep using the caller provided timeout. */
409 &OwnEntry.WaitKey,
410 FALSE,
411 (PLARGE_INTEGER)TimeOut);
412
414
415 if (!*InternalGetListRemovalHandledFlag(&OwnEntry))
416 {
417 /* Remove OwnEntry from the list again, since it still seems to
418 be on the list. We will know for sure once we've acquired
419 the lock. */
420 if (InternalLockCondVar(ConditionVariable,
421 NULL,
423 {
424 /* Unlock and potentially remove OwnEntry. Self-removal is
425 usually only necessary when a timeout occurred. */
426 InternalUnlockCondVar(ConditionVariable,
427 !OwnEntry.ListRemovalHandled ?
428 &OwnEntry : NULL);
429 }
430 }
431
432#ifdef _DEBUG
433 /* Clear OwnEntry to aid in detecting bugs. */
434 RtlZeroMemory(&OwnEntry, sizeof(OwnEntry));
435#endif
436
437 /* Reacquire the caller provided lock, as we are about to return. */
438 if (CriticalSection == NULL)
439 {
440 if (0 == (RTL_CONDITION_VARIABLE_LOCKMODE_SHARED & SRWFlags))
441 {
443 }
444 else
445 {
447 }
448 }
449 else
450 {
452 }
453
454 /* Return whatever NtWaitForKeyedEvent returned. */
455 return Status;
456}
LONG NTSTATUS
Definition: precomp.h:26
static VOID InternalUnlockCondVar(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN PCOND_VAR_WAIT_ENTRY RemoveEntry OPTIONAL)
Definition: condvar.c:190
VOID NTAPI RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:710
static HANDLE CondVarKeyedEventHandle
Definition: condvar.c:42
VOID NTAPI RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:591
static PCOND_VAR_WAIT_ENTRY InternalLockCondVar(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN PCOND_VAR_WAIT_ENTRY InsertEntry OPTIONAL, IN BOOLEAN *AbortIfLocked OPTIONAL)
Definition: condvar.c:77
VOID NTAPI RtlReleaseSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:526
VOID NTAPI RtlAcquireSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:325
FORCEINLINE BOOLEAN * InternalGetListRemovalHandledFlag(IN PCOND_VAR_WAIT_ENTRY Entry)
Definition: condvar.c:70
#define STATUS_INVALID_HANDLE
Definition: d3dkmdt.h:40
#define FALSE
Definition: types.h:117
Status
Definition: gdiplustypes.h:25
NTSYSAPI NTSTATUS WINAPI NtWaitForKeyedEvent(HANDLE, const void *, BOOLEAN, const LARGE_INTEGER *)
CRITICAL_SECTION CriticalSection
Definition: iprtprio.c:40
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
Definition: condvar.c:29
BOOLEAN ListRemovalHandled
Definition: condvar.c:34
PVOID WaitKey
Definition: condvar.c:33
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
Definition: rtltypes.h:283

Referenced by RtlSleepConditionVariableCS(), and RtlSleepConditionVariableSRW().

◆ InternalUnlockCondVar()

static VOID InternalUnlockCondVar ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN PCOND_VAR_WAIT_ENTRY RemoveEntry  OPTIONAL 
)
static

Definition at line 190 of file condvar.c.

192{
193 /* This routine assumes that the lock is being held on entry.
194 RemoveEntry may be NULL. If it is not NULL, this routine
195 assumes that RemoveEntry is on the list and will remove it
196 before releasing the lock. */
197 ULONG_PTR OldVal = (ULONG_PTR)ConditionVariable->Ptr;
198 PLIST_ENTRY NewHeadEntry;
199
200 ASSERT((OldVal & COND_VAR_LOCKED_FLAG) &&
201 (OldVal & COND_VAR_ADDRESS_MASK));
202
203 NewHeadEntry = (PLIST_ENTRY)(OldVal & COND_VAR_ADDRESS_MASK);
204 if (RemoveEntry != NULL)
205 {
206 /* We have to drop RemoveEntry from the list. */
207 if (&RemoveEntry->ListEntry == NewHeadEntry)
208 {
209 /* RemoveEntry is the list head. */
210 if (!IsListEmpty(NewHeadEntry))
211 {
212 /* The second entry in the list will become the new
213 list head. It's from the thread that arrived
214 right before the owner of RemoveEntry. */
215 NewHeadEntry = NewHeadEntry->Flink;
216 RemoveEntryList(&RemoveEntry->ListEntry);
217 }
218 else
219 {
220 /* The list will be empty, so discard the list. */
221 NewHeadEntry = NULL;
222 }
223 }
224 else
225 {
226 /* RemoveEntry is not the list head. The current list head
227 will remain. */
228 RemoveEntryList(&RemoveEntry->ListEntry);
229 }
230
231 /* Indicate to the owner of RemoveEntry that the entry
232 was removed from the list. RemoveEntry may not be touched
233 from here on. We don't use volatile semantics here since
234 the cache will anyway be flushed soon when we update
235 ConditionVariable. */
236 RemoveEntry->ListRemovalHandled = TRUE;
237 }
238
239 /* Now unlock thread-safe, while preserving any flags within the
240 COND_VAR_FLAGS_MASK range except for COND_VAR_LOCKED_FLAG. */
241 for (;;)
242 {
243 ULONG_PTR NewVal = ((OldVal & (COND_VAR_FLAGS_MASK ^ COND_VAR_LOCKED_FLAG)) |
244 (ULONG_PTR)NewHeadEntry);
245 ULONG_PTR LockRes = InternalCmpXChgCondVarRel(ConditionVariable, NewVal, OldVal);
246 if (LockRes == OldVal)
247 {
248 /* We unlocked. */
249 break;
250 }
251
252 /* Try again. */
253 OldVal = LockRes;
254 }
255}
FORCEINLINE ULONG_PTR InternalCmpXChgCondVarRel(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN ULONG_PTR Exchange, IN ULONG_PTR Comperand)
Definition: condvar.c:59
#define TRUE
Definition: types.h:120
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954

Referenced by InternalSleep(), and InternalWake().

◆ InternalWake()

static VOID InternalWake ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN BOOLEAN  ReleaseAll 
)
static

Definition at line 259 of file condvar.c.

261{
262 /* If ReleaseAll is zero on entry, one thread at most will be woken.
263 Otherwise all waiting threads are woken. Wakeups happen in FIFO
264 order. */
265 PCOND_VAR_WAIT_ENTRY CONST HeadEntry = InternalLockCondVar(ConditionVariable, NULL, NULL);
267 PCOND_VAR_WAIT_ENTRY NextEntry;
269 PCOND_VAR_WAIT_ENTRY RemoveOnUnlockEntry;
270
272
273 if (HeadEntry == NULL)
274 {
275 /* There is noone there to wake up. In this case do nothing
276 and return immediately. We don't stockpile releases. */
277 return;
278 }
279
280 Timeout.QuadPart = 0;
281 RemoveOnUnlockEntry = NULL;
282
283 /* Release sleeping threads. We will iterate from the last entry on
284 the list to the first. Note that the loop condition is always
285 true for the initial test. */
286 for (Entry = CONTAINING_COND_VAR_WAIT_ENTRY(HeadEntry->ListEntry.Blink, ListEntry);
287 Entry != NULL;
288 Entry = NextEntry)
289 {
291
292 if (HeadEntry == Entry)
293 {
294 /* After the current entry we've iterated through the
295 entire list in backward direction. Then exit.*/
296 NextEntry = NULL;
297 }
298 else
299 {
300 /* Store away the next reference right now, since we may
301 not touch Entry anymore at the end of the block. */
302 NextEntry = CONTAINING_COND_VAR_WAIT_ENTRY(Entry->ListEntry.Blink, ListEntry);
303 }
304
305 /* Wake the thread associated with this event. We will
306 immediately return if we failed (zero timeout). */
308 &Entry->WaitKey,
309 FALSE,
310 &Timeout);
311
312 if (!NT_SUCCESS(Status))
313 {
314 /* We failed to wake a thread. We'll keep trying. */
316 continue;
317 }
318
319 /* We've woken a thread and will make sure this thread
320 is removed from the list. */
321 if (HeadEntry == Entry)
322 {
323 /* This is the list head. We can't remove it as easily as
324 other entries and will pass it to the unlock routine
325 later (we will exit the loop after this round anyway). */
326 RemoveOnUnlockEntry = HeadEntry;
327 }
328 else
329 {
330 /* We can remove the entry right away. */
331 RemoveEntryList(&Entry->ListEntry);
332
333 /* Now tell the woken thread that removal from the list was
334 already taken care of here so that this thread can resume
335 its normal operation more quickly. We may not touch
336 Entry after signaling this, since it may lie in invalid
337 memory from there on. */
339 }
340
341 if (!ReleaseAll)
342 {
343 /* We've successfully woken one thread as the caller
344 demanded. */
345 break;
346 }
347 }
348
349 InternalUnlockCondVar(ConditionVariable, RemoveOnUnlockEntry);
350}
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
NTSYSAPI NTSTATUS WINAPI NtReleaseKeyedEvent(HANDLE, const void *, BOOLEAN, const LARGE_INTEGER *)
#define CONST
Definition: pedump.c:81
static ULONG Timeout
Definition: ping.c:61

Referenced by RtlWakeAllConditionVariable(), and RtlWakeConditionVariable().

◆ RtlAcquireSRWLockExclusive()

VOID NTAPI RtlAcquireSRWLockExclusive ( IN OUT PRTL_SRWLOCK  SRWLock)

Definition at line 591 of file srw.c.

592{
593 __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock;
595
598 {
599 LONG_PTR CurrentValue, NewValue;
600
601 while (1)
602 {
603 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
604
605 if (CurrentValue & RTL_SRWLOCK_SHARED)
606 {
607 /* A shared lock is being held right now. We need to add a wait block! */
608
609 if (CurrentValue & RTL_SRWLOCK_CONTENDED)
610 {
611 goto AddWaitBlock;
612 }
613 else
614 {
615 /* There are no wait blocks so far, we need to add ourselves as the first
616 wait block. We need to keep the shared count! */
617 StackWaitBlock.Exclusive = TRUE;
618 StackWaitBlock.SharedCount = (LONG)(CurrentValue >> RTL_SRWLOCK_BITS);
619 StackWaitBlock.Next = NULL;
620 StackWaitBlock.Last = &StackWaitBlock;
621 StackWaitBlock.Wake = 0;
622
624
626 (PVOID)NewValue,
627 (PVOID)CurrentValue) == CurrentValue)
628 {
630 &StackWaitBlock);
631
632 /* Successfully acquired the exclusive lock */
633 break;
634 }
635 }
636 }
637 else
638 {
639 if (CurrentValue & RTL_SRWLOCK_OWNED)
640 {
641 /* An exclusive lock is being held right now. We need to add a wait block! */
642
643 if (CurrentValue & RTL_SRWLOCK_CONTENDED)
644 {
645AddWaitBlock:
646 StackWaitBlock.Exclusive = TRUE;
647 StackWaitBlock.SharedCount = 0;
648 StackWaitBlock.Next = NULL;
649 StackWaitBlock.Last = &StackWaitBlock;
650 StackWaitBlock.Wake = 0;
651
653 if (First != NULL)
654 {
655 Last = First->Last;
656 Last->Next = &StackWaitBlock;
657 First->Last = &StackWaitBlock;
658
660
662 &StackWaitBlock);
663
664 /* Successfully acquired the exclusive lock */
665 break;
666 }
667 }
668 else
669 {
670 /* There are no wait blocks so far, we need to add ourselves as the first
671 wait block. We need to keep the shared count! */
672 StackWaitBlock.Exclusive = TRUE;
673 StackWaitBlock.SharedCount = 0;
674 StackWaitBlock.Next = NULL;
675 StackWaitBlock.Last = &StackWaitBlock;
676 StackWaitBlock.Wake = 0;
677
678 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED;
680 (PVOID)NewValue,
681 (PVOID)CurrentValue) == CurrentValue)
682 {
684 &StackWaitBlock);
685
686 /* Successfully acquired the exclusive lock */
687 break;
688 }
689 }
690 }
691 else
692 {
693 if (!InterlockedBitTestAndSetPointer(&SRWLock->Ptr,
695 {
696 /* We managed to get hold of a simple exclusive lock! */
697 break;
698 }
699 }
700 }
701
703 }
704 }
705}
WCHAR First[]
Definition: FormatMessage.c:11
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
if(dx< 0)
Definition: linetemp.h:194
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
typedef __ALIGNED(16) struct _EX_PUSH_LOCK_WAIT_BLOCK
Definition: extypes.h:483
long LONG
Definition: pedump.c:60
#define RTL_SRWLOCK_CONTENDED
Definition: srw.c:42
static VOID NTAPI RtlpReleaseWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:190
#define RTL_SRWLOCK_BITS
Definition: srw.c:47
static VOID NTAPI RtlpAcquireSRWLockExclusiveWait(IN OUT PRTL_SRWLOCK SRWLock, IN PRTLP_SRWLOCK_WAITBLOCK WaitBlock)
Definition: srw.c:232
#define RTL_SRWLOCK_SHARED
Definition: srw.c:43
#define RTL_SRWLOCK_OWNED
Definition: srw.c:41
#define InterlockedBitTestAndSetPointer(ptr, val)
Definition: srw.c:30
#define RTL_SRWLOCK_OWNED_BIT
Definition: srw.c:37
static PRTLP_SRWLOCK_WAITBLOCK NTAPI RtlpAcquireWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:199
volatile struct _RTLP_SRWLOCK_WAITBLOCK * Last
Definition: srw.c:62
BOOLEAN Exclusive
Definition: srw.c:79
volatile struct _RTLP_SRWLOCK_WAITBLOCK * Next
Definition: srw.c:65

Referenced by InternalSleep().

◆ RtlAcquireSRWLockShared()

VOID NTAPI RtlAcquireSRWLockShared ( IN OUT PRTL_SRWLOCK  SRWLock)

Definition at line 325 of file srw.c.

326{
327 __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock;
328 RTLP_SRWLOCK_SHARED_WAKE SharedWake;
329 LONG_PTR CurrentValue, NewValue;
330 PRTLP_SRWLOCK_WAITBLOCK First, Shared, FirstWait;
331
332 while (1)
333 {
334 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
335
336 if (CurrentValue & RTL_SRWLOCK_SHARED)
337 {
338 /* NOTE: It is possible that the RTL_SRWLOCK_OWNED bit is set! */
339
340 if (CurrentValue & RTL_SRWLOCK_CONTENDED)
341 {
342 /* There's other waiters already, lock the wait blocks and
343 increment the shared count */
345 if (First != NULL)
346 {
347 FirstWait = NULL;
348
349 if (First->Exclusive)
350 {
351 /* We need to setup a new wait block! Although
352 we're currently in a shared lock and we're acquiring
353 a shared lock, there are exclusive locks queued. We need
354 to wait until those are released. */
355 Shared = First->Last;
356
357 if (Shared->Exclusive)
358 {
359 StackWaitBlock.Exclusive = FALSE;
360 StackWaitBlock.SharedCount = 1;
361 StackWaitBlock.Next = NULL;
362 StackWaitBlock.Last = &StackWaitBlock;
363 StackWaitBlock.SharedWakeChain = &SharedWake;
364
365 Shared->Next = &StackWaitBlock;
366 First->Last = &StackWaitBlock;
367
368 Shared = &StackWaitBlock;
369 FirstWait = &StackWaitBlock;
370 }
371 else
372 {
373 Shared->LastSharedWake->Next = &SharedWake;
374 Shared->SharedCount++;
375 }
376 }
377 else
378 {
379 Shared = First;
380 Shared->LastSharedWake->Next = &SharedWake;
381 Shared->SharedCount++;
382 }
383
384 SharedWake.Next = NULL;
385 SharedWake.Wake = 0;
386
387 Shared->LastSharedWake = &SharedWake;
388
390
392 FirstWait,
393 &SharedWake);
394
395 /* Successfully incremented the shared count, we acquired the lock */
396 break;
397 }
398 }
399 else
400 {
401 /* This is a fastest path, just increment the number of
402 current shared locks */
403
404 /* Since the RTL_SRWLOCK_SHARED bit is set, the RTL_SRWLOCK_OWNED bit also has
405 to be set! */
406
407 ASSERT(CurrentValue & RTL_SRWLOCK_OWNED);
408
409 NewValue = (CurrentValue >> RTL_SRWLOCK_BITS) + 1;
410 NewValue = (NewValue << RTL_SRWLOCK_BITS) | (CurrentValue & RTL_SRWLOCK_MASK);
411
413 (PVOID)NewValue,
414 (PVOID)CurrentValue) == CurrentValue)
415 {
416 /* Successfully incremented the shared count, we acquired the lock */
417 break;
418 }
419 }
420 }
421 else
422 {
423 if (CurrentValue & RTL_SRWLOCK_OWNED)
424 {
425 /* The resource is currently acquired exclusively */
426 if (CurrentValue & RTL_SRWLOCK_CONTENDED)
427 {
428 SharedWake.Next = NULL;
429 SharedWake.Wake = 0;
430
431 /* There's other waiters already, lock the wait blocks and
432 increment the shared count. If the last block in the chain
433 is an exclusive lock, add another block. */
434
435 StackWaitBlock.Exclusive = FALSE;
436 StackWaitBlock.SharedCount = 0;
437 StackWaitBlock.Next = NULL;
438 StackWaitBlock.Last = &StackWaitBlock;
439 StackWaitBlock.SharedWakeChain = &SharedWake;
440
442 if (First != NULL)
443 {
444 Shared = First->Last;
445 if (Shared->Exclusive)
446 {
447 Shared->Next = &StackWaitBlock;
448 First->Last = &StackWaitBlock;
449
450 Shared = &StackWaitBlock;
451 FirstWait = &StackWaitBlock;
452 }
453 else
454 {
455 FirstWait = NULL;
456 Shared->LastSharedWake->Next = &SharedWake;
457 }
458
459 Shared->SharedCount++;
460 Shared->LastSharedWake = &SharedWake;
461
463
465 FirstWait,
466 &SharedWake);
467
468 /* Successfully incremented the shared count, we acquired the lock */
469 break;
470 }
471 }
472 else
473 {
474 SharedWake.Next = NULL;
475 SharedWake.Wake = 0;
476
477 /* We need to setup the first wait block. Currently an exclusive lock is
478 held, change the lock to contended mode. */
479 StackWaitBlock.Exclusive = FALSE;
480 StackWaitBlock.SharedCount = 1;
481 StackWaitBlock.Next = NULL;
482 StackWaitBlock.Last = &StackWaitBlock;
483 StackWaitBlock.SharedWakeChain = &SharedWake;
484 StackWaitBlock.LastSharedWake = &SharedWake;
485
486 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED;
488 (PVOID)NewValue,
489 (PVOID)CurrentValue) == CurrentValue)
490 {
492 &StackWaitBlock,
493 &SharedWake);
494
495 /* Successfully set the shared count, we acquired the lock */
496 break;
497 }
498 }
499 }
500 else
501 {
502 /* This is a fast path, we can simply try to set the shared count to 1 */
504
505 /* The RTL_SRWLOCK_CONTENDED bit should never be set if neither the
506 RTL_SRWLOCK_SHARED nor the RTL_SRWLOCK_OWNED bit is set */
507 ASSERT(!(CurrentValue & RTL_SRWLOCK_CONTENDED));
508
510 (PVOID)NewValue,
511 (PVOID)CurrentValue) == CurrentValue)
512 {
513 /* Successfully set the shared count, we acquired the lock */
514 break;
515 }
516 }
517 }
518
520 }
521}
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
static VOID NTAPI RtlpAcquireSRWLockSharedWait(IN OUT PRTL_SRWLOCK SRWLock, IN OUT PRTLP_SRWLOCK_WAITBLOCK FirstWait OPTIONAL, IN OUT PRTLP_SRWLOCK_SHARED_WAKE WakeChain)
Definition: srw.c:267
#define RTL_SRWLOCK_MASK
Definition: srw.c:45
volatile struct _RTLP_SRWLOCK_SHARED_WAKE * Next
Definition: srw.c:52
PRTLP_SRWLOCK_SHARED_WAKE SharedWakeChain
Definition: srw.c:74
PRTLP_SRWLOCK_SHARED_WAKE LastSharedWake
Definition: srw.c:75

Referenced by InternalSleep().

◆ RtlInitializeConditionVariable()

VOID NTAPI RtlInitializeConditionVariable ( OUT PRTL_CONDITION_VARIABLE  ConditionVariable)

Definition at line 479 of file condvar.c.

480{
481 ConditionVariable->Ptr = NULL;
482}

◆ RtlpCloseKeyedEvent()

VOID NTAPI RtlpCloseKeyedEvent ( VOID  )

Definition at line 468 of file condvar.c.

469{
473}
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402

Referenced by DllMain().

◆ RtlpInitializeKeyedEvent()

VOID NTAPI RtlpInitializeKeyedEvent ( VOID  )

Definition at line 460 of file condvar.c.

461{
464}
NTSYSAPI NTSTATUS WINAPI NtCreateKeyedEvent(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, ULONG)
#define EVENT_ALL_ACCESS
Definition: isotest.c:82

Referenced by DllMain(), and LdrpInitializeProcess().

◆ RtlReleaseSRWLockExclusive()

VOID NTAPI RtlReleaseSRWLockExclusive ( IN OUT PRTL_SRWLOCK  SRWLock)

Definition at line 710 of file srw.c.

711{
712 LONG_PTR CurrentValue, NewValue;
713 PRTLP_SRWLOCK_WAITBLOCK WaitBlock;
714
715 while (1)
716 {
717 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
718
719 if (!(CurrentValue & RTL_SRWLOCK_OWNED))
720 {
722 }
723
724 if (!(CurrentValue & RTL_SRWLOCK_SHARED))
725 {
726 if (CurrentValue & RTL_SRWLOCK_CONTENDED)
727 {
728 /* There's a wait block, we need to wake the next pending
729 acquirer (exclusive or shared) */
730 WaitBlock = RtlpAcquireWaitBlockLock(SRWLock);
731 if (WaitBlock != NULL)
732 {
734 WaitBlock);
735
736 /* We released the lock */
737 break;
738 }
739 }
740 else
741 {
742 /* This is a fast path, we can simply clear the RTL_SRWLOCK_OWNED
743 bit. All other bits should be 0 now because this is a simple
744 exclusive lock and no one is waiting. */
745
746 ASSERT(!(CurrentValue & ~RTL_SRWLOCK_OWNED));
747
748 NewValue = 0;
750 (PVOID)NewValue,
751 (PVOID)CurrentValue) == CurrentValue)
752 {
753 /* We released the lock */
754 break;
755 }
756 }
757 }
758 else
759 {
760 /* The RTL_SRWLOCK_SHARED bit must not be present now,
761 not even in the contended case! */
763 }
764
766 }
767}
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
#define STATUS_RESOURCE_NOT_OWNED
Definition: ntstatus.h:737
static VOID NTAPI RtlpReleaseWaitBlockLockExclusive(IN OUT PRTL_SRWLOCK SRWLock, IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock)
Definition: srw.c:85

Referenced by InternalSleep().

◆ RtlReleaseSRWLockShared()

VOID NTAPI RtlReleaseSRWLockShared ( IN OUT PRTL_SRWLOCK  SRWLock)

Definition at line 526 of file srw.c.

527{
528 LONG_PTR CurrentValue, NewValue;
529 PRTLP_SRWLOCK_WAITBLOCK WaitBlock;
530 BOOLEAN LastShared;
531
532 while (1)
533 {
534 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
535
536 if (CurrentValue & RTL_SRWLOCK_SHARED)
537 {
538 if (CurrentValue & RTL_SRWLOCK_CONTENDED)
539 {
540 /* There's a wait block, we need to wake a pending
541 exclusive acquirer if this is the last shared release */
542 WaitBlock = RtlpAcquireWaitBlockLock(SRWLock);
543 if (WaitBlock != NULL)
544 {
545 LastShared = (--WaitBlock->SharedCount == 0);
546
547 if (LastShared)
549 WaitBlock);
550 else
552
553 /* We released the lock */
554 break;
555 }
556 }
557 else
558 {
559 /* This is a fast path, we can simply decrement the shared
560 count and store the pointer */
561 NewValue = CurrentValue >> RTL_SRWLOCK_BITS;
562
563 if (--NewValue != 0)
564 {
565 NewValue = (NewValue << RTL_SRWLOCK_BITS) | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED;
566 }
567
569 (PVOID)NewValue,
570 (PVOID)CurrentValue) == CurrentValue)
571 {
572 /* Successfully released the lock */
573 break;
574 }
575 }
576 }
577 else
578 {
579 /* The RTL_SRWLOCK_SHARED bit has to be present now,
580 even in the contended case! */
582 }
583
585 }
586}
static VOID NTAPI RtlpReleaseWaitBlockLockLastShared(IN OUT PRTL_SRWLOCK SRWLock, IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock)
Definition: srw.c:155

Referenced by InternalSleep().

◆ RtlSleepConditionVariableCS()

NTSTATUS NTAPI RtlSleepConditionVariableCS ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN OUT PRTL_CRITICAL_SECTION  CriticalSection,
IN PLARGE_INTEGER TimeOut  OPTIONAL 
)

Definition at line 500 of file condvar.c.

503{
504 return InternalSleep(ConditionVariable,
507 0,
508 TimeOut);
509}
static NTSTATUS InternalSleep(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN OUT PRTL_CRITICAL_SECTION CriticalSection OPTIONAL, IN OUT PRTL_SRWLOCK SRWLock OPTIONAL, IN ULONG SRWFlags, IN const LARGE_INTEGER *TimeOut OPTIONAL)
Definition: condvar.c:367

◆ RtlSleepConditionVariableSRW()

NTSTATUS NTAPI RtlSleepConditionVariableSRW ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable,
IN OUT PRTL_SRWLOCK  SRWLock,
IN PLARGE_INTEGER TimeOut  OPTIONAL,
IN ULONG  Flags 
)

Definition at line 513 of file condvar.c.

517{
518 return InternalSleep(ConditionVariable,
520 SRWLock,
521 Flags,
522 TimeOut);
523}
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170

◆ RtlWakeAllConditionVariable()

VOID NTAPI RtlWakeAllConditionVariable ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable)

Definition at line 493 of file condvar.c.

494{
495 InternalWake(ConditionVariable, TRUE);
496}
static VOID InternalWake(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN BOOLEAN ReleaseAll)
Definition: condvar.c:259

◆ RtlWakeConditionVariable()

VOID NTAPI RtlWakeConditionVariable ( IN OUT PRTL_CONDITION_VARIABLE  ConditionVariable)

Definition at line 486 of file condvar.c.

487{
488 InternalWake(ConditionVariable, FALSE);
489}

Variable Documentation

◆ CondVarKeyedEventHandle

HANDLE CondVarKeyedEventHandle = NULL
static