2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/gmutex.c
5 * PURPOSE: Implements Guarded Mutex
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) and
8 * Filip Navara (xnavara@volny.cz)
11 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
18 InterlockedClearBit(PLONG Destination
,
21 typedef enum _KGUARDED_MUTEX_BITS
24 GM_LOCK_WAITER_WOKEN
= 2,
25 GM_LOCK_WAITER_INC
= 4
26 } KGUARDED_MUTEX_BITS
;
28 /* FUNCTIONS *****************************************************************/
31 * @name KeEnterGuardedRegion
33 * Enters a guarded region. This causes all (incl. special kernel) APCs
38 KeEnterGuardedRegion(VOID
)
40 /* Disable Special APCs */
41 KeGetCurrentThread()->SpecialApcDisable
--;
45 * @name KeLeaveGuardedRegion
47 * Leaves a guarded region and delivers pending APCs if possible.
51 KeLeaveGuardedRegion(VOID
)
53 PKTHREAD Thread
= KeGetCurrentThread();
55 /* Boost the enable count and check if Special APCs are enabled */
56 if (++Thread
->SpecialApcDisable
== 0)
58 /* Check if there are Kernel APCs on the list */
59 if (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
]))
61 /* Check for APC Delivery */
62 KiCheckForKernelApcDelivery();
69 KeInitializeGuardedMutex(PKGUARDED_MUTEX GuardedMutex
)
71 /* Setup the Initial Data */
72 GuardedMutex
->Count
= GM_LOCK_BIT
;
73 GuardedMutex
->Owner
= NULL
;
74 GuardedMutex
->Contention
= 0;
76 /* Initialize the Wait Gate */
77 KeInitializeGate(&GuardedMutex
->Gate
);
82 KiAcquireGuardedMutexContented(PKGUARDED_MUTEX GuardedMutex
)
88 /* Increase the contention count */
89 InterlockedIncrement((PLONG
)&GuardedMutex
->Contention
);
91 /* Start by unlocking the Guarded Mutex */
92 BitsToRemove
= GM_LOCK_BIT
;
93 BitsToAdd
= GM_LOCK_WAITER_INC
;
97 /* Get the Count Bits */
98 OldValue
= (volatile LONG
)GuardedMutex
->Count
;
100 /* Check if the Guarded Mutex is locked */
101 if (OldValue
& GM_LOCK_BIT
)
103 /* Unlock it by removing the Lock Bit */
104 if (InterlockedCompareExchange(&GuardedMutex
->Count
,
105 OldValue
&~ BitsToRemove
,
106 OldValue
) == OldValue
)
108 /* The Guarded Mutex is now unlocked */
114 /* The Guarded Mutex isn't locked, so simply set the bits */
115 if (InterlockedCompareExchange(&GuardedMutex
->Count
,
116 OldValue
| BitsToAdd
,
117 OldValue
) != OldValue
)
119 /* The Guarded Mutex value changed behind our back, start over */
123 /* Now we have to wait for it */
124 KeWaitForGate(&GuardedMutex
->Gate
, WrGuardedMutex
, KernelMode
);
126 /* Ok, the wait is done, so set the new bits */
127 BitsToRemove
= GM_LOCK_BIT
| GM_LOCK_WAITER_WOKEN
;
128 BitsToAdd
= GM_LOCK_WAITER_WOKEN
;
135 KeAcquireGuardedMutexUnsafe(PKGUARDED_MUTEX GuardedMutex
)
137 /* Remove the lock */
138 if (!InterlockedClearBit(&GuardedMutex
->Count
, 0))
140 /* The Guarded Mutex was already locked, enter contented case */
141 KiAcquireGuardedMutexContented(GuardedMutex
);
145 GuardedMutex
->Owner
= KeGetCurrentThread();
150 KeReleaseGuardedMutexUnsafe(PKGUARDED_MUTEX GuardedMutex
)
154 /* Destroy the Owner */
155 GuardedMutex
->Owner
= NULL
;
157 /* Add the Lock Bit */
158 OldValue
= InterlockedExchangeAdd(&GuardedMutex
->Count
, 1);
160 /* Check if it was already locked, but not woken */
161 if (OldValue
&& !(OldValue
& GM_LOCK_WAITER_WOKEN
))
163 /* Update the Oldvalue to what it should be now */
164 OldValue
|= GM_LOCK_BIT
;
166 /* Remove the Woken bit */
167 if (InterlockedCompareExchange(&GuardedMutex
->Count
,
168 OldValue
&~ GM_LOCK_WAITER_WOKEN
,
169 OldValue
) == OldValue
)
171 /* Signal the Gate */
172 KeSignalGateBoostPriority(&GuardedMutex
->Gate
);
179 KeAcquireGuardedMutex(PKGUARDED_MUTEX GuardedMutex
)
181 /* Disable Special APCs */
182 KeEnterGuardedRegion();
184 /* Do the Unsafe Acquire */
185 KeAcquireGuardedMutexUnsafe(GuardedMutex
);
190 KeReleaseGuardedMutex(PKGUARDED_MUTEX GuardedMutex
)
192 /* Do the actual release */
193 KeReleaseGuardedMutexUnsafe(GuardedMutex
);
196 KeLeaveGuardedRegion();
201 KeTryToAcquireGuardedMutex(PKGUARDED_MUTEX GuardedMutex
)
204 KeEnterGuardedRegion();
206 /* Remove the lock */
207 if (InterlockedClearBit(&GuardedMutex
->Count
, 0))
210 KeLeaveGuardedRegion();
217 GuardedMutex
->Owner
= KeGetCurrentThread();