If you are a driver developer, you probably are familiar with fast mutexes. Fast mutexes, also known as executive mutexes, are a faster alternative to regular kernel mutexes with some important differences -

  • Fast mutexes cannot be recursively acquired in the same thread like the regular mutexes can. So you can only use fast mutexes when reentrancy while holding the mutex is not a possibility.
  • Fast mutexes can be acquired at PASSIVE_LEVEL or APC_LEVEL unlike regular mutexes which can be acquired only at PASSIVE_LEVEL.
  • Fast mutex acquisition raises IRQL to APC_LEVEL unlike regular mutexes which do not change IRQL.
  • Fast mutex acquisition disables all APCs whereas regular mutex acquisition still permits special kernel APCs.

Fast mutexes must be allocated in non-paged pool memory and are represented by FAST_MUTEX structure which is defined as below

typedef struct _FAST_MUTEX {
LONG Count;
PKTHREAD Owner;
ULONG Contention;
KEVENT Gate;
ULONG OldIrql;
} FAST_MUTEX, *PFAST_MUTEX;

The Count member is key to acquiring the fast mutex. If it is 1, the fast mutex is unclaimed. If it is 0, the fast mutex is claimed. If it is negative, so many threads are waiting on acquiring the fast mutex.

The Owner member is a pointer to KTHREAD that owns the fast mutex. Many times this will have the stack pointer address of the thread that successfully acquired the thread (instead of KTHREAD pointer). Since that is unique for a thread, you can still identify the thread that owns the fast mutex.

The Contention member keeps a count of how many times threads intending to acquire the fast mutex found the mutex to be acquired by some other thread. For best performance, you would want this to be as low as possible.

The Gate member (aka Event) has a KEVENT that is waited on when FAST_MUTEX is already claimed by another thread. This is key to finding out which other threads are waiting to claim the fast mutex.

The OldIrql member stores the original IRQL (before acquisition) so it can be restored when fast mutex is released. This is necessary since fast mutex can be acquired in PASSIVE_LEVEL or APC_LEVEL.

The DDK calls involving fast mutex are few and are named nicely making their purpose obvious. Initialization is done via ExInitializeFastMutex whereas acquisition can be done 3 ways - ExAcquireFastMutex if caller wants to block if the fast mutex is claimed by another thread, ExTryToAcquireFastMutex if caller does not wish to block if mutex is already claimed, ExAcquireFastMutexUnsafe if caller wants to take the responsibility of making sure APCs are not delivered to the thread after owning the unsafe fast mutex. There are corresponding release DDIs namely ExReleaseFastMutex and ExReleaseFastMutexUnsafe for releasing an owned fast mutex.

Fast mutex DDIs (barring the unsafe mutex DDIs) are implemented in hal in Windows XP (and before).  These have been moved to ntoskrnl in Vista, which makes more sense. If anyone knows why they were in hal in the first place, pray tell.

Tagged with →  
Share →

One Response to Inside fast mutex

  1. […] claim the push lock will block on an in-stack gate object (KGATE) via KeWaitForGate. That is very similar to fast mutexes using event synchronization object to implement contention […]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Looking for something?

Use the form below to search the site:


Still not finding what you're looking for? Drop us a note so we can take care of it!

Visit our friends!

A few highly recommended friends...

Set your Twitter account name in your settings to use the TwitterBar Section.