You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
822 lines
16 KiB
822 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
kx.h
|
|
|
|
Abstract:
|
|
|
|
This module contains the public (external) header file for the kernel
|
|
that must be included after all other header files.
|
|
|
|
WARNING: There is code in windows\core\ntgdi\gre\i386\locka.asm that
|
|
mimics the functions to enter and leave critical regions.
|
|
This is very unfortunate since any changes to the subject
|
|
routines must be reflected in locka.asm also.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 9-Jul-2002
|
|
|
|
--*/
|
|
|
|
#ifndef _KX_
|
|
#define _KX_
|
|
|
|
VOID
|
|
KiCheckForKernelApcDelivery (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
KiWaitForGuardedMutexEvent (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
);
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeEnterGuardedRegionThread (
|
|
IN PKTHREAD Thread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables special kernel APC's for the current thread.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
Thread - Supplies a pointer to the current thread.
|
|
|
|
N.B. This must be a pointer to the current thread.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
|
|
|
ASSERT(Thread == KeGetCurrentThread());
|
|
|
|
ASSERT((Thread->SpecialApcDisable <= 0) && (Thread->SpecialApcDisable != -32768));
|
|
|
|
Thread->SpecialApcDisable -= 1;
|
|
KeMemoryBarrierWithoutFence();
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeEnterGuardedRegion (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables special kernel APC's for the current thread.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KeEnterGuardedRegionThread(KeGetCurrentThread());
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeLeaveGuardedRegionThread (
|
|
IN PKTHREAD Thread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables special kernel APC's.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
Thread - Supplies a pointer to the current thread.
|
|
|
|
N.B. This must be a pointer to the current thread.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
|
|
|
ASSERT(Thread == KeGetCurrentThread());
|
|
|
|
ASSERT(Thread->SpecialApcDisable < 0);
|
|
|
|
KeMemoryBarrierWithoutFence();
|
|
if ((Thread->SpecialApcDisable = Thread->SpecialApcDisable + 1) == 0) {
|
|
KeMemoryBarrier();
|
|
if (Thread->ApcState.ApcListHead[KernelMode].Flink !=
|
|
&Thread->ApcState.ApcListHead[KernelMode]) {
|
|
|
|
KiCheckForKernelApcDelivery();
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeLeaveGuardedRegion (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables special kernel APC's.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KeLeaveGuardedRegionThread(KeGetCurrentThread());
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeEnterCriticalRegionThread (
|
|
PKTHREAD Thread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables kernel APC's for the current thread.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
Thread - Supplies a pointer to the current thread.
|
|
|
|
N.B. This must be a pointer to the current thread.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ASSERT(Thread == KeGetCurrentThread());
|
|
|
|
ASSERT((Thread->KernelApcDisable <= 0) && (Thread->KernelApcDisable != -32768));
|
|
|
|
Thread->KernelApcDisable -= 1;
|
|
KeMemoryBarrierWithoutFence();
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeEnterCriticalRegion (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables kernel APC's for the current thread.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KeEnterCriticalRegionThread(KeGetCurrentThread());
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeLeaveCriticalRegionThread (
|
|
IN PKTHREAD Thread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables normal kernel APC's for the current thread.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
Thread - Supplies a pointer to the current thread.
|
|
|
|
N.B. This must be a pointer to the current thread.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ASSERT(Thread == KeGetCurrentThread());
|
|
|
|
ASSERT(Thread->KernelApcDisable < 0);
|
|
|
|
KeMemoryBarrierWithoutFence();
|
|
if ((Thread->KernelApcDisable = Thread->KernelApcDisable + 1) == 0) {
|
|
KeMemoryBarrier();
|
|
if (Thread->ApcState.ApcListHead[KernelMode].Flink !=
|
|
&Thread->ApcState.ApcListHead[KernelMode]) {
|
|
|
|
if (Thread->SpecialApcDisable == 0) {
|
|
KiCheckForKernelApcDelivery();
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeLeaveCriticalRegion (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables normal kernel APC's for the current thread.
|
|
|
|
N.B. The following code does not require any interlocks. There are
|
|
two cases of interest: 1) On an MP system, the thread cannot
|
|
be running on two processors as once, and 2) if the thread is
|
|
is interrupted to deliver a kernel mode APC which also calls
|
|
this routine, the values read and stored will stack and unstack
|
|
properly.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KeLeaveCriticalRegionThread(KeGetCurrentThread());
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
BOOLEAN
|
|
KeAreApcsDisabled (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This function returns whether kernel are disabled for the current thread.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
If either the kernel or special APC disable count is nonzero, then a value
|
|
of TRUE is returned. Otherwise, a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return (BOOLEAN)(KeGetCurrentThread()->CombinedApcDisable != 0);
|
|
}
|
|
|
|
FORCEINLINE
|
|
BOOLEAN
|
|
KeAreAllApcsDisabled (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This function returns whether all APCs are disabled for the current thread.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
If either the special APC disable count is nonzero or the IRQL is greater
|
|
than or equal to APC_LEVEL, then a value of TRUE is returned. Otherwise,
|
|
a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return (BOOLEAN)((KeGetCurrentThread()->SpecialApcDisable != 0) ||
|
|
(KeGetCurrentIrql() >= APC_LEVEL));
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeInitializeGuardedMutex (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes a guarded mutex.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
Mutex->Owner = NULL;
|
|
Mutex->Count = 1;
|
|
Mutex->Contention = 0;
|
|
KeInitializeEvent(&Mutex->Event, SynchronizationEvent, FALSE);
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeAcquireGuardedMutex (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enters a guarded region and acquires ownership of a guarded
|
|
mutex.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
|
|
//
|
|
// Enter a guarded region and decrement the ownership count to determine
|
|
// if the guarded mutex is owned.
|
|
//
|
|
|
|
Thread = KeGetCurrentThread();
|
|
|
|
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
|
|
|
ASSERT(Mutex->Owner != Thread);
|
|
|
|
KeEnterGuardedRegionThread(Thread);
|
|
if (InterlockedDecrementAcquire(&Mutex->Count) != 0) {
|
|
|
|
//
|
|
// The guarded mutex is owned.
|
|
//
|
|
// Increment contention count and wait for ownership to be granted.
|
|
//
|
|
|
|
KiWaitForGuardedMutexEvent(Mutex);
|
|
}
|
|
|
|
//
|
|
// Grant ownership of the guarded mutext to the current thread.
|
|
//
|
|
|
|
Mutex->Owner = Thread;
|
|
|
|
#if DBG
|
|
|
|
Mutex->SpecialApcDisable = Thread->SpecialApcDisable;
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeReleaseGuardedMutex (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function releases ownership of a guarded mutex and leaves a guarded
|
|
region.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
|
|
//
|
|
// Clear the owner thread and increment the guarded mutex count to
|
|
// detemine if there are any threads waiting for ownership to be
|
|
// granted.
|
|
//
|
|
|
|
Thread = KeGetCurrentThread();
|
|
|
|
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
|
|
|
ASSERT(Mutex->Owner == Thread);
|
|
|
|
ASSERT(Thread->SpecialApcDisable == Mutex->SpecialApcDisable);
|
|
|
|
Mutex->Owner = NULL;
|
|
if (InterlockedIncrementRelease(&Mutex->Count) <= 0) {
|
|
|
|
//
|
|
// There are one or more threads waiting for ownership of the guarded
|
|
// mutex.
|
|
//
|
|
|
|
KeSetEventBoostPriority(&Mutex->Event, NULL);
|
|
}
|
|
|
|
//
|
|
// Leave guarded region.
|
|
//
|
|
|
|
KeLeaveGuardedRegionThread(Thread);
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
BOOLEAN
|
|
KeTryToAcquireGuardedMutex (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function attempts to acquire ownership of a guarded mutex, and if
|
|
successful, enters a guarded region.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
If the guarded mutex was successfully acquired, then a value of TRUE
|
|
is returned as the function value. Otherwise, a value of FALSE is
|
|
returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
|
|
//
|
|
// Enater a guarded region and attempt to acquire ownership of the guarded
|
|
// mutex.
|
|
//
|
|
|
|
Thread = KeGetCurrentThread();
|
|
|
|
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
|
|
|
KeEnterGuardedRegionThread(Thread);
|
|
if (InterlockedCompareExchange(&Mutex->Count, 0, 1) != 1) {
|
|
|
|
//
|
|
// The guarded mutex is owned.
|
|
//
|
|
// Leave guarded region and return FALSE.
|
|
//
|
|
|
|
KeLeaveGuardedRegionThread(Thread);
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Grant ownership of the guarded mutex to the current thread and
|
|
// return TRUE.
|
|
//
|
|
|
|
Mutex->Owner = Thread;
|
|
|
|
#if DBG
|
|
|
|
Mutex->SpecialApcDisable = Thread->SpecialApcDisable;
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeAcquireGuardedMutexUnsafe (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function acquires ownership of a guarded mutex, but does enter a
|
|
guarded region.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
|
|
//
|
|
// Decrement the ownership count to determine if the guarded mutex is
|
|
// owned.
|
|
//
|
|
|
|
Thread = KeGetCurrentThread();
|
|
|
|
ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
|
|
(Thread->SpecialApcDisable < 0) ||
|
|
(Thread->Teb == NULL) ||
|
|
(Thread->Teb >= MM_SYSTEM_RANGE_START));
|
|
|
|
ASSERT(Mutex->Owner != Thread);
|
|
|
|
if (InterlockedDecrement(&Mutex->Count) != 0) {
|
|
|
|
//
|
|
// The guarded mutex is owned.
|
|
//
|
|
// Increment contention count and wait for ownership to be granted.
|
|
//
|
|
|
|
KiWaitForGuardedMutexEvent(Mutex);
|
|
}
|
|
|
|
//
|
|
// Grant ownership of the guarded mutex to the current thread.
|
|
//
|
|
|
|
Mutex->Owner = Thread;
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
VOID
|
|
KeReleaseGuardedMutexUnsafe (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function releases ownership of a guarded mutex, and does not leave
|
|
a guarded region.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKTHREAD Thread;
|
|
|
|
//
|
|
// Clear the owner thread and increment the guarded mutex count to
|
|
// determine if there are any threads waiting for ownership to be
|
|
// granted.
|
|
//
|
|
|
|
Thread = KeGetCurrentThread();
|
|
|
|
ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
|
|
(Thread->SpecialApcDisable < 0) ||
|
|
(Thread->Teb == NULL) ||
|
|
(Thread->Teb >= MM_SYSTEM_RANGE_START));
|
|
|
|
ASSERT(Mutex->Owner == Thread);
|
|
|
|
Mutex->Owner = NULL;
|
|
if (InterlockedIncrement(&Mutex->Count) <= 0) {
|
|
|
|
//
|
|
// There are one or more threads waiting for ownership of the guarded
|
|
// mutex.
|
|
//
|
|
|
|
KeSetEventBoostPriority(&Mutex->Event, NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
FORCEINLINE
|
|
PKTHREAD
|
|
KeGetOwnerGuardedMutex (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the owner of the specified guarded mutex.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
If the guarded mutex is owned, then a pointer to the owner thread is
|
|
returned. Otherwise, NULL is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
return Mutex->Owner;
|
|
}
|
|
|
|
FORCEINLINE
|
|
BOOLEAN
|
|
KeIsGuardedMutexOwned (
|
|
IN PKGUARDED_MUTEX Mutex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function tests whether the specified guarded mutext is owned.
|
|
|
|
Arguments:
|
|
|
|
Mutex - Supplies a pointer to a guarded mutex.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned if the guarded mutex is owned. Otherwise,
|
|
a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
return (BOOLEAN)(Mutex->Count != 1);
|
|
}
|
|
|
|
#endif
|