diff --git a/reactos/include/ddk/winddk.h b/reactos/include/ddk/winddk.h index 750396dea33..0586737c55a 100644 --- a/reactos/include/ddk/winddk.h +++ b/reactos/include/ddk/winddk.h @@ -1167,20 +1167,27 @@ typedef struct _KGATE DISPATCHER_HEADER Header; } KGATE, *PKGATE, *RESTRICTED_POINTER PRKGATE; +#define GM_LOCK_BIT 0x1 +#define GM_LOCK_BIT_V 0x0 +#define GM_LOCK_WAITER_WOKEN 0x2 +#define GM_LOCK_WAITER_INC 0x4 + typedef struct _KGUARDED_MUTEX { - LONG Count; - struct _KTHREAD* Owner; + volatile LONG Count; + PKTHREAD Owner; ULONG Contention; KGATE Gate; - union { - struct { + union + { + struct + { SHORT KernelApcDisable; SHORT SpecialApcDisable; }; ULONG CombinedApcDisable; }; -} KGUARDED_MUTEX, *PKGUARDED_MUTEX, *RESTRICTED_POINTER PRKGUARDED_MUTEX; +} KGUARDED_MUTEX, *PKGUARDED_MUTEX; typedef struct _KTIMER { DISPATCHER_HEADER Header; @@ -5195,19 +5202,19 @@ NTOSAPI LONG DDKFASTAPI InterlockedIncrement( - IN PLONG VOLATILE Addend); + IN OUT LONG volatile *Addend); NTOSAPI LONG DDKFASTAPI InterlockedDecrement( - IN PLONG VOLATILE Addend); + IN OUT LONG volatile *Addend); NTOSAPI LONG DDKFASTAPI InterlockedCompareExchange( - IN OUT PLONG VOLATILE Destination, + IN OUT LONG volatile *Destination, IN LONG Exchange, IN LONG Comparand); @@ -5215,14 +5222,14 @@ NTOSAPI LONG DDKFASTAPI InterlockedExchange( - IN OUT PLONG VOLATILE Target, + IN OUT LONG volatile *Destination, IN LONG Value); NTOSAPI LONG DDKFASTAPI InterlockedExchangeAdd( - IN OUT PLONG VOLATILE Addend, + IN OUT LONG volatile *Addend, IN LONG Value); /* @@ -6315,48 +6322,52 @@ RtlxUnicodeStringToAnsiSize( /* Guarded Mutex routines */ -VOID +VOID FASTCALL KeAcquireGuardedMutex( - PKGUARDED_MUTEX GuardedMutex + IN OUT PKGUARDED_MUTEX GuardedMutex ); VOID FASTCALL KeAcquireGuardedMutexUnsafe( - PKGUARDED_MUTEX GuardedMutex + IN OUT PKGUARDED_MUTEX GuardedMutex ); -VOID -STDCALL -KeEnterGuardedRegion(VOID); - VOID -STDCALL -KeLeaveGuardedRegion(VOID); +NTAPI +KeEnterGuardedRegion( + VOID +); -VOID +VOID +NTAPI +KeLeaveGuardedRegion( + VOID +); + +VOID FASTCALL KeInitializeGuardedMutex( - PKGUARDED_MUTEX GuardedMutex + OUT PKGUARDED_MUTEX GuardedMutex ); -VOID +VOID FASTCALL KeReleaseGuardedMutexUnsafe( - PKGUARDED_MUTEX GuardedMutex + IN OUT PKGUARDED_MUTEX GuardedMutex ); -VOID +VOID FASTCALL KeReleaseGuardedMutex( - PKGUARDED_MUTEX GuardedMutex + IN OUT PKGUARDED_MUTEX GuardedMutex ); -BOOL +BOOLEAN FASTCALL KeTryToAcquireGuardedMutex( - PKGUARDED_MUTEX GuardedMutex + IN OUT PKGUARDED_MUTEX GuardedMutex ); /* Fast Mutex */ diff --git a/reactos/include/ndk/ketypes.h b/reactos/include/ndk/ketypes.h index a32400e29b4..cff284123d4 100644 --- a/reactos/include/ndk/ketypes.h +++ b/reactos/include/ndk/ketypes.h @@ -695,8 +695,8 @@ typedef struct _KTHREAD { struct { - USHORT KernelApcDisable; - USHORT SpecialApcDisable; + SHORT KernelApcDisable; + SHORT SpecialApcDisable; }; ULONG CombinedApcDisable; }; diff --git a/reactos/include/psdk/winnt.h b/reactos/include/psdk/winnt.h index bdabef7763e..49149f08e3e 100644 --- a/reactos/include/psdk/winnt.h +++ b/reactos/include/psdk/winnt.h @@ -3785,7 +3785,7 @@ static __inline PVOID GetFiberData(void) #if defined(__GNUC__) static __inline__ BOOLEAN -InterlockedBitTestAndSet(IN LONG *Base, +InterlockedBitTestAndSet(IN LONG volatile *Base, IN LONG Bit) { LONG OldBit; @@ -3800,7 +3800,7 @@ InterlockedBitTestAndSet(IN LONG *Base, } static __inline__ BOOLEAN -InterlockedBitTestAndReset(IN LONG *Base, +InterlockedBitTestAndReset(IN LONG volatile *Base, IN LONG Bit) { LONG OldBit; diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index b45333f78df..2799f04457c 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -709,4 +709,6 @@ KeV86Exception( ULONG address ); +#include "ke_x.h" + #endif /* __NTOSKRNL_INCLUDE_INTERNAL_KE_H */ diff --git a/reactos/ntoskrnl/include/internal/ke_x.h b/reactos/ntoskrnl/include/internal/ke_x.h new file mode 100644 index 00000000000..ae4c78b9205 --- /dev/null +++ b/reactos/ntoskrnl/include/internal/ke_x.h @@ -0,0 +1,59 @@ +/* +* PROJECT: ReactOS Kernel +* LICENSE: GPL - See COPYING in the top level directory +* FILE: ntoskrnl/include/ke_x.h +* PURPOSE: Internal Inlined Functions for the Kernel +* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) +*/ + +// +// Guarded Region Routines +// +#define KeEnterGuardedRegion() \ +{ \ + PKTHREAD Thread = KeGetCurrentThread(); \ + \ + /* Sanity checks */ \ + ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); \ + ASSERT(Thread == KeGetCurrentThread()); \ + ASSERT((Thread->SpecialApcDisable <= 0) && \ + (Thread->SpecialApcDisable != -32768)); \ + \ + /* Disable Special APCs */ \ + Thread->SpecialApcDisable--; \ +} + +#define KeLeaveGuardedRegion() \ +{ \ + PKTHREAD Thread = KeGetCurrentThread(); \ + \ + /* Sanity checks */ \ + ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); \ + ASSERT(Thread == KeGetCurrentThread()); \ + ASSERT(Thread->SpecialApcDisable < 0); \ + \ + /* Leave region and check if APCs are OK now */ \ + if (!(++Thread->SpecialApcDisable)) \ + { \ + /* Check for Kernel APCs on the list */ \ + if (!IsListEmpty(&Thread->ApcState. \ + ApcListHead[KernelMode])) \ + { \ + /* Check for APC Delivery */ \ + KiCheckForKernelApcDelivery(); \ + } \ + } \ +} + +// +// TODO: Guarded Mutex Routines +// + +// +// TODO: Critical Region Routines +// + +// +// TODO: Wait Routines +// + diff --git a/reactos/ntoskrnl/ke/gate.c b/reactos/ntoskrnl/ke/gate.c index 30bbc580fd0..e691cf7d56b 100644 --- a/reactos/ntoskrnl/ke/gate.c +++ b/reactos/ntoskrnl/ke/gate.c @@ -1,10 +1,9 @@ /* - * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ke/gate.c * PURPOSE: Implements the Gate Dispatcher Object - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ /* INCLUDES *****************************************************************/ @@ -18,10 +17,8 @@ VOID FASTCALL -KeInitializeGate(PKGATE Gate) +KeInitializeGate(IN PKGATE Gate) { - DPRINT("KeInitializeGate(Gate %x)\n", Gate); - /* Initialize the Dispatcher Header */ KeInitializeDispatcherHeader(&Gate->Header, GateObject, @@ -98,7 +95,7 @@ KeWaitForGate(IN PKGATE Gate, VOID FASTCALL -KeSignalGateBoostPriority(PKGATE Gate) +KeSignalGateBoostPriority(IN PKGATE Gate) { PKTHREAD WaitThread; PKWAIT_BLOCK WaitBlock; diff --git a/reactos/ntoskrnl/ke/gmutex.c b/reactos/ntoskrnl/ke/gmutex.c index 25f1eb58bd0..19d11cf7dbd 100644 --- a/reactos/ntoskrnl/ke/gmutex.c +++ b/reactos/ntoskrnl/ke/gmutex.c @@ -1,72 +1,139 @@ /* - * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel - * FILE: ntoskrnl/ke/gmutex.c + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ke/gate.c * PURPOSE: Implements Guarded Mutex - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) and - * Filip Navara (xnavara@volny.cz) + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Filip Navara (navaraf@reactos.org) */ -/* INCLUDES *****************************************************************/ +/* INCLUDES ******************************************************************/ +#define NTDDI_VERSION NTDDI_WS03SP1 #include +#define NDEBUG #include -UCHAR +/* PRIVATE FUNCTIONS *********************************************************/ + +VOID FASTCALL -InterlockedClearBit(PLONG Destination, - LONG Bit); - -typedef enum _KGUARDED_MUTEX_BITS +KiAcquireGuardedMutexContented(IN OUT PKGUARDED_MUTEX GuardedMutex) { - GM_LOCK_BIT = 1, - GM_LOCK_WAITER_WOKEN = 2, - GM_LOCK_WAITER_INC = 4 -} KGUARDED_MUTEX_BITS; + ULONG BitsToRemove, BitsToAdd; + LONG OldValue, NewValue; -/* FUNCTIONS *****************************************************************/ + /* Increase the contention count */ + GuardedMutex->Contention++; -/** - * @name KeEnterGuardedRegion - * - * Enters a guarded region. This causes all (incl. special kernel) APCs - * to be disabled. - */ -VOID -STDCALL -KeEnterGuardedRegion(VOID) -{ - /* Disable Special APCs */ - KeGetCurrentThread()->SpecialApcDisable--; -} + /* Start by unlocking the Guarded Mutex */ + BitsToRemove = GM_LOCK_BIT; + BitsToAdd = GM_LOCK_WAITER_INC; -/** - * @name KeLeaveGuardedRegion - * - * Leaves a guarded region and delivers pending APCs if possible. - */ -VOID -STDCALL -KeLeaveGuardedRegion(VOID) -{ - PKTHREAD Thread = KeGetCurrentThread(); + /* Get the Count Bits */ + OldValue = GuardedMutex->Count; - /* Boost the enable count and check if Special APCs are enabled */ - if (++Thread->SpecialApcDisable == 0) + /* Start change loop */ + for (;;) { - /* Check if there are Kernel APCs on the list */ - if (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) + /* Loop sanity checks */ + ASSERT((BitsToRemove == GM_LOCK_BIT) || + (BitsToRemove == (GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN))); + ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) || + (BitsToAdd == GM_LOCK_WAITER_WOKEN)); + + /* Check if the Guarded Mutex is locked */ + if (OldValue & GM_LOCK_BIT) { - /* Check for APC Delivery */ - KiCheckForKernelApcDelivery(); + /* Sanity check */ + ASSERT((BitsToRemove == GM_LOCK_BIT) || + ((OldValue & GM_LOCK_WAITER_WOKEN) != 0)); + + /* Unlock it by removing the Lock Bit */ + NewValue = InterlockedCompareExchange(&GuardedMutex->Count, + OldValue ^ BitsToRemove, + OldValue); + if (NewValue == OldValue) break; + + /* Value got changed behind our backs, start over */ + OldValue = NewValue; } + else + { + /* The Guarded Mutex isn't locked, so simply set the bits */ + NewValue = InterlockedCompareExchange(&GuardedMutex->Count, + OldValue + BitsToAdd, + OldValue); + if (NewValue != OldValue) + { + /* Value got changed behind our backs, start over */ + OldValue = NewValue; + continue; + } + + /* Now we have to wait for it */ + KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode); + ASSERT((GuardedMutex->Count & GM_LOCK_WAITER_WOKEN) != 0); + + /* Ok, the wait is done, so set the new bits */ + BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN; + BitsToAdd = GM_LOCK_WAITER_WOKEN; + } } } VOID +FORCEINLINE FASTCALL -KeInitializeGuardedMutex(PKGUARDED_MUTEX GuardedMutex) +KiAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex) +{ + BOOLEAN OldBit; + + /* Remove the lock */ + OldBit = InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V); + if (!OldBit) + { + /* The Guarded Mutex was already locked, enter contented case */ + KiAcquireGuardedMutexContented(GuardedMutex); + } +} + +VOID +FORCEINLINE +FASTCALL +KiReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex) +{ + LONG OldValue; + + /* Destroy the Owner */ + GuardedMutex->Owner = NULL; + + /* Add the Lock Bit */ + OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, 1); + ASSERT((OldValue & GM_LOCK_BIT) == 0); + + /* Check if it was already locked, but not woken */ + if ((OldValue) && !(OldValue & GM_LOCK_WAITER_WOKEN)) + { + /* Update the Oldvalue to what it should be now */ + OldValue |= GM_LOCK_BIT; + + /* Remove the Woken bit */ + if (InterlockedCompareExchange(&GuardedMutex->Count, + OldValue - GM_LOCK_WAITER_WOKEN, + OldValue) == OldValue) + { + /* Signal the Gate */ + KeSignalGateBoostPriority(&GuardedMutex->Gate); + } + } +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +VOID +FASTCALL +KeInitializeGuardedMutex(OUT PKGUARDED_MUTEX GuardedMutex) { /* Setup the Initial Data */ GuardedMutex->Count = GM_LOCK_BIT; @@ -79,143 +146,155 @@ KeInitializeGuardedMutex(PKGUARDED_MUTEX GuardedMutex) VOID FASTCALL -KiAcquireGuardedMutexContented(PKGUARDED_MUTEX GuardedMutex) +KeAcquireGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex) { - ULONG BitsToRemove; - ULONG BitsToAdd; - LONG OldValue; + PKTHREAD Thread = KeGetCurrentThread(); - /* Increase the contention count */ - InterlockedIncrement((PLONG)&GuardedMutex->Contention); + /* Sanity checks */ + ASSERT((KeGetCurrentIrql() == APC_LEVEL) || + (Thread->SpecialApcDisable < 0) || + (Thread->Teb == NULL) || + (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START)); + ASSERT(GuardedMutex->Owner != Thread); - /* Start by unlocking the Guarded Mutex */ - BitsToRemove = GM_LOCK_BIT; - BitsToAdd = GM_LOCK_WAITER_INC; - - while (1) - { - /* Get the Count Bits */ - OldValue = (volatile LONG)GuardedMutex->Count; - - /* Check if the Guarded Mutex is locked */ - if (OldValue & GM_LOCK_BIT) - { - /* Unlock it by removing the Lock Bit */ - if (InterlockedCompareExchange(&GuardedMutex->Count, - OldValue &~ BitsToRemove, - OldValue) == OldValue) - { - /* The Guarded Mutex is now unlocked */ - break; - } - } - else - { - /* The Guarded Mutex isn't locked, so simply set the bits */ - if (InterlockedCompareExchange(&GuardedMutex->Count, - OldValue | BitsToAdd, - OldValue) != OldValue) - { - /* The Guarded Mutex value changed behind our back, start over */ - continue; - } - - /* Now we have to wait for it */ - KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode); - - /* Ok, the wait is done, so set the new bits */ - BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN; - BitsToAdd = GM_LOCK_WAITER_WOKEN; - } - } -} - -VOID -FASTCALL -KeAcquireGuardedMutexUnsafe(PKGUARDED_MUTEX GuardedMutex) -{ - /* Remove the lock */ - if (!InterlockedBitTestAndReset(&GuardedMutex->Count, 0)) - { - /* The Guarded Mutex was already locked, enter contented case */ - KiAcquireGuardedMutexContented(GuardedMutex); - } + /* Do the actual acquire */ + KiAcquireGuardedMutex(GuardedMutex); /* Set the Owner */ - GuardedMutex->Owner = KeGetCurrentThread(); + GuardedMutex->Owner = Thread; } VOID FASTCALL -KeReleaseGuardedMutexUnsafe(PKGUARDED_MUTEX GuardedMutex) +KeReleaseGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex) { - LONG OldValue; + /* Sanity checks */ + ASSERT((KeGetCurrentIrql() == APC_LEVEL) || + (KeGetCurrentThread()->SpecialApcDisable < 0) || + (KeGetCurrentThread()->Teb == NULL) || + (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START)); + ASSERT(GuardedMutex->Owner == KeGetCurrentThread()); - /* Destroy the Owner */ - GuardedMutex->Owner = NULL; - - /* Add the Lock Bit */ - OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, 1); - - /* Check if it was already locked, but not woken */ - if (OldValue && !(OldValue & GM_LOCK_WAITER_WOKEN)) - { - /* Update the Oldvalue to what it should be now */ - OldValue |= GM_LOCK_BIT; - - /* Remove the Woken bit */ - if (InterlockedCompareExchange(&GuardedMutex->Count, - OldValue &~ GM_LOCK_WAITER_WOKEN, - OldValue) == OldValue) - { - /* Signal the Gate */ - KeSignalGateBoostPriority(&GuardedMutex->Gate); - } - } + /* Release the mutex */ + KiReleaseGuardedMutex(GuardedMutex); } VOID FASTCALL -KeAcquireGuardedMutex(PKGUARDED_MUTEX GuardedMutex) +KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex) { + PKTHREAD Thread = KeGetCurrentThread(); + + /* Sanity checks */ + ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); + ASSERT(GuardedMutex->Owner != Thread); + /* Disable Special APCs */ KeEnterGuardedRegion(); - /* Do the Unsafe Acquire */ - KeAcquireGuardedMutexUnsafe(GuardedMutex); + /* Do the actual acquire */ + KiAcquireGuardedMutex(GuardedMutex); + + /* Set the Owner and Special APC Disable state */ + GuardedMutex->Owner = Thread; + GuardedMutex->SpecialApcDisable = Thread->SpecialApcDisable; } VOID FASTCALL -KeReleaseGuardedMutex(PKGUARDED_MUTEX GuardedMutex) +KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex) { - /* Do the actual release */ - KeReleaseGuardedMutexUnsafe(GuardedMutex); + /* Sanity checks */ + ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); + ASSERT(GuardedMutex->Owner == KeGetCurrentThread()); + ASSERT(GuardedMutex->SpecialApcDisable == + KeGetCurrentThread()->SpecialApcDisable); + + /* Release the mutex */ + KiReleaseGuardedMutex(GuardedMutex); /* Re-enable APCs */ KeLeaveGuardedRegion(); } -BOOL +BOOLEAN FASTCALL -KeTryToAcquireGuardedMutex(PKGUARDED_MUTEX GuardedMutex) +KeTryToAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex) { + PKTHREAD Thread = KeGetCurrentThread(); + BOOLEAN OldBit; + /* Block APCs */ KeEnterGuardedRegion(); /* Remove the lock */ - if (InterlockedBitTestAndReset(&GuardedMutex->Count, 0)) + OldBit = InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V); + if (OldBit) { /* Re-enable APCs */ KeLeaveGuardedRegion(); + YieldProcessor(); /* Return failure */ return FALSE; } - /* Set the Owner */ - GuardedMutex->Owner = KeGetCurrentThread(); + /* Set the Owner and APC State */ + GuardedMutex->Owner = Thread; + GuardedMutex->SpecialApcDisable = Thread->SpecialApcDisable; return TRUE; } +/** + * @name KeEnterGuardedRegion + * + * Enters a guarded region. This causes all (incl. special kernel) APCs + * to be disabled. + */ +#undef KeEnterGuardedRegion +VOID +NTAPI +KeEnterGuardedRegion(VOID) +{ + PKTHREAD Thread = KeGetCurrentThread(); + + /* Sanity checks */ + ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); + ASSERT(Thread == KeGetCurrentThread()); + ASSERT((Thread->SpecialApcDisable <= 0) && + (Thread->SpecialApcDisable != -32768)); + + /* Disable Special APCs */ + Thread->SpecialApcDisable--; +} + +/** + * @name KeLeaveGuardedRegion + * + * Leaves a guarded region and delivers pending APCs if possible. + */ +#undef KeLeaveGuardedRegion +VOID +NTAPI +KeLeaveGuardedRegion(VOID) +{ + PKTHREAD Thread = KeGetCurrentThread(); + + /* Sanity checks */ + ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); + ASSERT(Thread == KeGetCurrentThread()); + ASSERT(Thread->SpecialApcDisable < 0); + + /* Boost the enable count and check if Special APCs are enabled */ + if (!(++Thread->SpecialApcDisable)) + { + /* Check if there are Kernel APCs on the list */ + if (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) + { + /* Check for APC Delivery */ + KiCheckForKernelApcDelivery(); + } + } +} + /* EOF */