2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/mutex.c
5 * PURPOSE: Implements the Mutant Dispatcher Object
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* FUNCTIONS *****************************************************************/
22 KeInitializeMutant(IN PKMUTANT Mutant
,
23 IN BOOLEAN InitialOwner
)
25 PKTHREAD CurrentThread
;
28 /* Check if we have an initial owner */
31 /* We also need to associate a thread */
32 CurrentThread
= KeGetCurrentThread();
33 Mutant
->OwnerThread
= CurrentThread
;
35 /* We're about to touch the Thread, so lock the Dispatcher */
36 OldIrql
= KiAcquireDispatcherLock();
38 /* And insert it into its list */
39 InsertTailList(&CurrentThread
->MutantListHead
,
40 &Mutant
->MutantListEntry
);
42 /* Release Dispatcher Lock */
43 KiReleaseDispatcherLock(OldIrql
);
47 /* In this case, we don't have an owner yet */
48 Mutant
->OwnerThread
= NULL
;
51 /* Now we set up the Dispatcher Header */
52 Mutant
->Header
.Type
= MutantObject
;
53 Mutant
->Header
.Size
= sizeof(KMUTANT
) / sizeof(ULONG
);
54 Mutant
->Header
.DpcActive
= FALSE
;
55 Mutant
->Header
.SignalState
= InitialOwner
? 0 : 1;
56 InitializeListHead(&(Mutant
->Header
.WaitListHead
));
58 /* Initialize the default data */
59 Mutant
->Abandoned
= FALSE
;
60 Mutant
->ApcDisable
= 0;
68 KeInitializeMutex(IN PKMUTEX Mutex
,
71 /* Set up the Dispatcher Header */
72 Mutex
->Header
.Type
= MutantObject
;
73 Mutex
->Header
.Size
= sizeof(KMUTEX
) / sizeof(ULONG
);
74 Mutex
->Header
.DpcActive
= FALSE
;
75 Mutex
->Header
.SignalState
= 1;
76 InitializeListHead(&(Mutex
->Header
.WaitListHead
));
78 /* Initialize the default data */
79 Mutex
->OwnerThread
= NULL
;
80 Mutex
->Abandoned
= FALSE
;
81 Mutex
->ApcDisable
= 1;
89 KeReadStateMutant(IN PKMUTANT Mutant
)
91 /* Return the Signal State */
92 return Mutant
->Header
.SignalState
;
100 KeReleaseMutant(IN PKMUTANT Mutant
,
101 IN KPRIORITY Increment
,
107 PKTHREAD CurrentThread
= KeGetCurrentThread();
108 BOOLEAN EnableApc
= FALSE
;
109 ASSERT_MUTANT(Mutant
);
110 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
112 /* Lock the Dispatcher Database */
113 OldIrql
= KiAcquireDispatcherLock();
115 /* Save the Previous State */
116 PreviousState
= Mutant
->Header
.SignalState
;
118 /* Check if it is to be abandonned */
119 if (Abandon
== FALSE
)
121 /* Make sure that the Owner Thread is the current Thread */
122 if (Mutant
->OwnerThread
!= CurrentThread
)
124 /* Release the lock */
125 KiReleaseDispatcherLock(OldIrql
);
127 /* Raise an exception */
128 ExRaiseStatus(Mutant
->Abandoned
? STATUS_ABANDONED
:
129 STATUS_MUTANT_NOT_OWNED
);
132 /* If the thread owns it, then increase the signal state */
133 Mutant
->Header
.SignalState
++;
137 /* It's going to be abandonned */
138 Mutant
->Header
.SignalState
= 1;
139 Mutant
->Abandoned
= TRUE
;
142 /* Check if the signal state is only single */
143 if (Mutant
->Header
.SignalState
== 1)
145 /* Check if it's below 0 now */
146 if (PreviousState
<= 0)
148 /* Remove the mutant from the list */
149 RemoveEntryList(&Mutant
->MutantListEntry
);
151 /* Save if we need to re-enable APCs */
152 EnableApc
= Mutant
->ApcDisable
;
155 /* Remove the Owning Thread and wake it */
156 Mutant
->OwnerThread
= NULL
;
158 /* Check if the Wait List isn't empty */
159 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
))
161 /* Wake the Mutant */
162 KiWaitTest(&Mutant
->Header
, Increment
);
166 /* Check if the caller wants to wait after this release */
169 /* Release the Lock */
170 KiReleaseDispatcherLock(OldIrql
);
175 CurrentThread
->WaitNext
= TRUE
;
176 CurrentThread
->WaitIrql
= OldIrql
;
179 /* Check if we need to re-enable APCs */
180 if (EnableApc
) KeLeaveCriticalRegion();
182 /* Return the previous state */
183 return PreviousState
;
191 KeReleaseMutex(IN PKMUTEX Mutex
,
194 ASSERT_MUTANT(Mutex
);
196 /* There's no difference at this level between the two */
197 return KeReleaseMutant(Mutex
, 1, FALSE
, Wait
);