ef82931445f6775cbd81449e5c4d3cc8ffb59e44
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
.SignalState
= InitialOwner
? 0 : 1;
55 InitializeListHead(&(Mutant
->Header
.WaitListHead
));
57 /* Initialize the default data */
58 Mutant
->Abandoned
= FALSE
;
59 Mutant
->ApcDisable
= 0;
67 KeInitializeMutex(IN PKMUTEX Mutex
,
70 /* Set up the Dispatcher Header */
71 Mutex
->Header
.Type
= MutantObject
;
72 Mutex
->Header
.Size
= sizeof(KMUTEX
) / sizeof(ULONG
);
73 Mutex
->Header
.SignalState
= 1;
74 InitializeListHead(&(Mutex
->Header
.WaitListHead
));
76 /* Initialize the default data */
77 Mutex
->OwnerThread
= NULL
;
78 Mutex
->Abandoned
= FALSE
;
79 Mutex
->ApcDisable
= 1;
87 KeReadStateMutant(IN PKMUTANT Mutant
)
89 /* Return the Signal State */
90 return Mutant
->Header
.SignalState
;
98 KeReleaseMutant(IN PKMUTANT Mutant
,
99 IN KPRIORITY Increment
,
105 PKTHREAD CurrentThread
= KeGetCurrentThread();
106 BOOLEAN EnableApc
= FALSE
;
107 ASSERT_MUTANT(Mutant
);
108 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
110 /* Lock the Dispatcher Database */
111 OldIrql
= KiAcquireDispatcherLock();
113 /* Save the Previous State */
114 PreviousState
= Mutant
->Header
.SignalState
;
116 /* Check if it is to be abandonned */
117 if (Abandon
== FALSE
)
119 /* Make sure that the Owner Thread is the current Thread */
120 if (Mutant
->OwnerThread
!= CurrentThread
)
122 /* Release the lock */
123 KiReleaseDispatcherLock(OldIrql
);
125 /* Raise an exception */
126 ExRaiseStatus(Mutant
->Abandoned
? STATUS_ABANDONED
:
127 STATUS_MUTANT_NOT_OWNED
);
130 /* If the thread owns it, then increase the signal state */
131 Mutant
->Header
.SignalState
++;
135 /* It's going to be abandonned */
136 Mutant
->Header
.SignalState
= 1;
137 Mutant
->Abandoned
= TRUE
;
140 /* Check if the signal state is only single */
141 if (Mutant
->Header
.SignalState
== 1)
143 /* Check if it's below 0 now */
144 if (PreviousState
<= 0)
146 /* Remove the mutant from the list */
147 RemoveEntryList(&Mutant
->MutantListEntry
);
149 /* Save if we need to re-enable APCs */
150 EnableApc
= Mutant
->ApcDisable
;
153 /* Remove the Owning Thread and wake it */
154 Mutant
->OwnerThread
= NULL
;
156 /* Check if the Wait List isn't empty */
157 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
))
159 /* Wake the Mutant */
160 KiWaitTest(&Mutant
->Header
, Increment
);
164 /* Check if the caller wants to wait after this release */
167 /* Release the Lock */
168 KiReleaseDispatcherLock(OldIrql
);
173 CurrentThread
->WaitNext
= TRUE
;
174 CurrentThread
->WaitIrql
= OldIrql
;
177 /* Check if we need to re-enable APCs */
178 if (EnableApc
) KeLeaveCriticalRegion();
180 /* Return the previous state */
181 return PreviousState
;
189 KeReleaseMutex(IN PKMUTEX Mutex
,
192 ASSERT_MUTANT(Mutex
);
194 /* There's no difference at this level between the two */
195 return KeReleaseMutant(Mutex
, 1, FALSE
, Wait
);