2005-03-14 02:08:17 +00:00
|
|
|
/*
|
2006-09-10 18:47:53 +00:00
|
|
|
* PROJECT: ReactOS Kernel
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
1998-09-05 17:34:23 +00:00
|
|
|
* FILE: ntoskrnl/ke/mutex.c
|
2006-09-10 18:47:53 +00:00
|
|
|
* PURPOSE: Implements the Mutant Dispatcher Object
|
|
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
1998-08-25 04:27:26 +00:00
|
|
|
*/
|
|
|
|
|
2006-09-10 19:14:03 +00:00
|
|
|
/* INCLUDES ******************************************************************/
|
1998-08-25 04:27:26 +00:00
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
2005-03-14 02:08:17 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
1998-08-25 04:27:26 +00:00
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2003-07-10 17:44:06 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-05-09 01:38:29 +00:00
|
|
|
VOID
|
2006-09-10 18:47:53 +00:00
|
|
|
NTAPI
|
2005-03-14 02:08:17 +00:00
|
|
|
KeInitializeMutant(IN PKMUTANT Mutant,
|
|
|
|
IN BOOLEAN InitialOwner)
|
1998-08-25 04:27:26 +00:00
|
|
|
{
|
2005-10-01 08:58:49 +00:00
|
|
|
PKTHREAD CurrentThread;
|
2005-03-14 02:08:17 +00:00
|
|
|
KIRQL OldIrql;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Check if we have an initial owner */
|
2006-09-10 18:47:53 +00:00
|
|
|
if (InitialOwner)
|
2005-10-01 08:58:49 +00:00
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* We also need to associate a thread */
|
|
|
|
CurrentThread = KeGetCurrentThread();
|
2005-10-01 08:58:49 +00:00
|
|
|
Mutant->OwnerThread = CurrentThread;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* We're about to touch the Thread, so lock the Dispatcher */
|
2006-09-10 18:26:50 +00:00
|
|
|
OldIrql = KiAcquireDispatcherLock();
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* And insert it into its list */
|
2005-10-01 08:58:49 +00:00
|
|
|
InsertTailList(&CurrentThread->MutantListHead,
|
|
|
|
&Mutant->MutantListEntry);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Release Dispatcher Lock */
|
2006-09-10 18:26:50 +00:00
|
|
|
KiReleaseDispatcherLock(OldIrql);
|
2005-10-01 08:58:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* In this case, we don't have an owner yet */
|
|
|
|
Mutant->OwnerThread = NULL;
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Now we set up the Dispatcher Header */
|
2011-10-07 16:18:52 +00:00
|
|
|
Mutant->Header.Type = MutantObject;
|
|
|
|
Mutant->Header.Size = sizeof(KMUTANT) / sizeof(ULONG);
|
|
|
|
Mutant->Header.SignalState = InitialOwner ? 0 : 1;
|
|
|
|
InitializeListHead(&(Mutant->Header.WaitListHead));
|
2005-03-14 02:08:17 +00:00
|
|
|
|
|
|
|
/* Initialize the default data */
|
|
|
|
Mutant->Abandoned = FALSE;
|
|
|
|
Mutant->ApcDisable = 0;
|
1998-08-25 04:27:26 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 17:44:06 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-05-09 01:38:29 +00:00
|
|
|
VOID
|
2006-09-10 18:47:53 +00:00
|
|
|
NTAPI
|
2005-03-14 02:08:17 +00:00
|
|
|
KeInitializeMutex(IN PKMUTEX Mutex,
|
|
|
|
IN ULONG Level)
|
1998-08-25 04:27:26 +00:00
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Set up the Dispatcher Header */
|
2011-10-07 16:18:52 +00:00
|
|
|
Mutex->Header.Type = MutantObject;
|
|
|
|
Mutex->Header.Size = sizeof(KMUTEX) / sizeof(ULONG);
|
|
|
|
Mutex->Header.SignalState = 1;
|
|
|
|
InitializeListHead(&(Mutex->Header.WaitListHead));
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Initialize the default data */
|
|
|
|
Mutex->OwnerThread = NULL;
|
|
|
|
Mutex->Abandoned = FALSE;
|
|
|
|
Mutex->ApcDisable = 1;
|
1998-08-25 04:27:26 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 17:44:06 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-05-09 01:38:29 +00:00
|
|
|
LONG
|
2006-09-10 18:47:53 +00:00
|
|
|
NTAPI
|
2005-03-14 02:08:17 +00:00
|
|
|
KeReadStateMutant(IN PKMUTANT Mutant)
|
1998-08-25 04:27:26 +00:00
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Return the Signal State */
|
2006-09-10 18:47:53 +00:00
|
|
|
return Mutant->Header.SignalState;
|
1998-08-25 04:27:26 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 17:44:06 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-05-09 01:38:29 +00:00
|
|
|
LONG
|
2006-09-10 18:47:53 +00:00
|
|
|
NTAPI
|
2005-03-14 02:08:17 +00:00
|
|
|
KeReleaseMutant(IN PKMUTANT Mutant,
|
|
|
|
IN KPRIORITY Increment,
|
|
|
|
IN BOOLEAN Abandon,
|
|
|
|
IN BOOLEAN Wait)
|
2001-11-04 00:18:40 +00:00
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
KIRQL OldIrql;
|
|
|
|
LONG PreviousState;
|
|
|
|
PKTHREAD CurrentThread = KeGetCurrentThread();
|
2006-09-10 18:47:53 +00:00
|
|
|
BOOLEAN EnableApc = FALSE;
|
|
|
|
ASSERT_MUTANT(Mutant);
|
|
|
|
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
2005-03-14 02:08:17 +00:00
|
|
|
|
|
|
|
/* Lock the Dispatcher Database */
|
2006-09-10 18:26:50 +00:00
|
|
|
OldIrql = KiAcquireDispatcherLock();
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Save the Previous State */
|
|
|
|
PreviousState = Mutant->Header.SignalState;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Check if it is to be abandonned */
|
2005-10-01 08:58:49 +00:00
|
|
|
if (Abandon == FALSE)
|
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Make sure that the Owner Thread is the current Thread */
|
2005-10-01 08:58:49 +00:00
|
|
|
if (Mutant->OwnerThread != CurrentThread)
|
|
|
|
{
|
|
|
|
/* Release the lock */
|
2006-09-10 18:26:50 +00:00
|
|
|
KiReleaseDispatcherLock(OldIrql);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-10-01 08:58:49 +00:00
|
|
|
/* Raise an exception */
|
|
|
|
ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED :
|
|
|
|
STATUS_MUTANT_NOT_OWNED);
|
2005-03-14 02:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If the thread owns it, then increase the signal state */
|
|
|
|
Mutant->Header.SignalState++;
|
2005-10-01 08:58:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* It's going to be abandonned */
|
|
|
|
Mutant->Header.SignalState = 1;
|
|
|
|
Mutant->Abandoned = TRUE;
|
2001-11-04 00:18:40 +00:00
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Check if the signal state is only single */
|
2005-10-01 08:58:49 +00:00
|
|
|
if (Mutant->Header.SignalState == 1)
|
|
|
|
{
|
2005-03-22 03:06:03 +00:00
|
|
|
/* Check if it's below 0 now */
|
2005-10-01 08:58:49 +00:00
|
|
|
if (PreviousState <= 0)
|
|
|
|
{
|
2005-03-22 03:06:03 +00:00
|
|
|
/* Remove the mutant from the list */
|
2005-03-14 02:08:17 +00:00
|
|
|
RemoveEntryList(&Mutant->MutantListEntry);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2006-09-10 18:47:53 +00:00
|
|
|
/* Save if we need to re-enable APCs */
|
|
|
|
EnableApc = Mutant->ApcDisable;
|
2005-03-14 02:08:17 +00:00
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Remove the Owning Thread and wake it */
|
|
|
|
Mutant->OwnerThread = NULL;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Check if the Wait List isn't empty */
|
2005-10-01 08:58:49 +00:00
|
|
|
if (!IsListEmpty(&Mutant->Header.WaitListHead))
|
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Wake the Mutant */
|
Dispatching & Queue Rewrite II:
- Rewrote wait code. It is now cleaner, more optimized and faster. All waiting
functions are now clearly differentiated instead of sharing code. These functions
are called up to a dozen times a second, so having dedicated code for each of
them is a real boost in speed.
- Fixed several queue issues, made a dedicated queue wait/wake function (you are not
supposed to use KeWaitFor on a queue, and this is also a speed boost), and make it
compatible with new wait code.
- Optimized Work Queue code to be much smaller and better organized, by using an
array instead of hard-coded multiple static variables. Also, add support for the
real NT structures and implementation, paving the road for Dynamic Work Items, which
also have timeouts, and deadlock dection + debug info.
- Simplified PsBlockThread and made it compatible with wait code.
- Added support for priority boosting when unwaiting a thread; will use later, as well
as put proper boosting for dispatch objects.
- Inlined all dispatcher lock functions and header initialization for speed.
- Moved executive wait code into ob.
svn path=/trunk/; revision=14047
2005-03-14 05:54:32 +00:00
|
|
|
KiWaitTest(&Mutant->Header, Increment);
|
2005-03-14 02:08:17 +00:00
|
|
|
}
|
2001-11-04 00:18:40 +00:00
|
|
|
}
|
2005-03-14 02:08:17 +00:00
|
|
|
|
2006-09-10 18:47:53 +00:00
|
|
|
/* Check if the caller wants to wait after this release */
|
2005-10-01 08:58:49 +00:00
|
|
|
if (Wait == FALSE)
|
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Release the Lock */
|
2006-09-10 18:26:50 +00:00
|
|
|
KiReleaseDispatcherLock(OldIrql);
|
2005-10-01 08:58:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Set a wait */
|
|
|
|
CurrentThread->WaitNext = TRUE;
|
|
|
|
CurrentThread->WaitIrql = OldIrql;
|
|
|
|
}
|
|
|
|
|
2006-09-10 18:47:53 +00:00
|
|
|
/* Check if we need to re-enable APCs */
|
|
|
|
if (EnableApc) KeLeaveCriticalRegion();
|
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* Return the previous state */
|
|
|
|
return PreviousState;
|
2001-11-04 00:18:40 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 17:44:06 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-05-09 01:38:29 +00:00
|
|
|
LONG
|
2006-09-10 18:47:53 +00:00
|
|
|
NTAPI
|
2005-03-14 02:08:17 +00:00
|
|
|
KeReleaseMutex(IN PKMUTEX Mutex,
|
|
|
|
IN BOOLEAN Wait)
|
2001-11-04 00:18:40 +00:00
|
|
|
{
|
2006-09-10 18:47:53 +00:00
|
|
|
ASSERT_MUTANT(Mutex);
|
|
|
|
|
2005-03-14 02:08:17 +00:00
|
|
|
/* There's no difference at this level between the two */
|
2020-10-16 14:09:08 +00:00
|
|
|
return KeReleaseMutant(Mutex, MUTANT_INCREMENT, FALSE, Wait);
|
1998-08-25 04:27:26 +00:00
|
|
|
}
|
|
|
|
|
2000-06-04 19:51:05 +00:00
|
|
|
/* EOF */
|