[CLT2012]
[reactos.git] / ntoskrnl / ke / mutex.c
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 /*
18 * @implemented
19 */
20 VOID
21 NTAPI
22 KeInitializeMutant(IN PKMUTANT Mutant,
23 IN BOOLEAN InitialOwner)
24 {
25 PKTHREAD CurrentThread;
26 KIRQL OldIrql;
27
28 /* Check if we have an initial owner */
29 if (InitialOwner)
30 {
31 /* We also need to associate a thread */
32 CurrentThread = KeGetCurrentThread();
33 Mutant->OwnerThread = CurrentThread;
34
35 /* We're about to touch the Thread, so lock the Dispatcher */
36 OldIrql = KiAcquireDispatcherLock();
37
38 /* And insert it into its list */
39 InsertTailList(&CurrentThread->MutantListHead,
40 &Mutant->MutantListEntry);
41
42 /* Release Dispatcher Lock */
43 KiReleaseDispatcherLock(OldIrql);
44 }
45 else
46 {
47 /* In this case, we don't have an owner yet */
48 Mutant->OwnerThread = NULL;
49 }
50
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));
57
58 /* Initialize the default data */
59 Mutant->Abandoned = FALSE;
60 Mutant->ApcDisable = 0;
61 }
62
63 /*
64 * @implemented
65 */
66 VOID
67 NTAPI
68 KeInitializeMutex(IN PKMUTEX Mutex,
69 IN ULONG Level)
70 {
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));
77
78 /* Initialize the default data */
79 Mutex->OwnerThread = NULL;
80 Mutex->Abandoned = FALSE;
81 Mutex->ApcDisable = 1;
82 }
83
84 /*
85 * @implemented
86 */
87 LONG
88 NTAPI
89 KeReadStateMutant(IN PKMUTANT Mutant)
90 {
91 /* Return the Signal State */
92 return Mutant->Header.SignalState;
93 }
94
95 /*
96 * @implemented
97 */
98 LONG
99 NTAPI
100 KeReleaseMutant(IN PKMUTANT Mutant,
101 IN KPRIORITY Increment,
102 IN BOOLEAN Abandon,
103 IN BOOLEAN Wait)
104 {
105 KIRQL OldIrql;
106 LONG PreviousState;
107 PKTHREAD CurrentThread = KeGetCurrentThread();
108 BOOLEAN EnableApc = FALSE;
109 ASSERT_MUTANT(Mutant);
110 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
111
112 /* Lock the Dispatcher Database */
113 OldIrql = KiAcquireDispatcherLock();
114
115 /* Save the Previous State */
116 PreviousState = Mutant->Header.SignalState;
117
118 /* Check if it is to be abandonned */
119 if (Abandon == FALSE)
120 {
121 /* Make sure that the Owner Thread is the current Thread */
122 if (Mutant->OwnerThread != CurrentThread)
123 {
124 /* Release the lock */
125 KiReleaseDispatcherLock(OldIrql);
126
127 /* Raise an exception */
128 ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED :
129 STATUS_MUTANT_NOT_OWNED);
130 }
131
132 /* If the thread owns it, then increase the signal state */
133 Mutant->Header.SignalState++;
134 }
135 else
136 {
137 /* It's going to be abandonned */
138 Mutant->Header.SignalState = 1;
139 Mutant->Abandoned = TRUE;
140 }
141
142 /* Check if the signal state is only single */
143 if (Mutant->Header.SignalState == 1)
144 {
145 /* Check if it's below 0 now */
146 if (PreviousState <= 0)
147 {
148 /* Remove the mutant from the list */
149 RemoveEntryList(&Mutant->MutantListEntry);
150
151 /* Save if we need to re-enable APCs */
152 EnableApc = Mutant->ApcDisable;
153 }
154
155 /* Remove the Owning Thread and wake it */
156 Mutant->OwnerThread = NULL;
157
158 /* Check if the Wait List isn't empty */
159 if (!IsListEmpty(&Mutant->Header.WaitListHead))
160 {
161 /* Wake the Mutant */
162 KiWaitTest(&Mutant->Header, Increment);
163 }
164 }
165
166 /* Check if the caller wants to wait after this release */
167 if (Wait == FALSE)
168 {
169 /* Release the Lock */
170 KiReleaseDispatcherLock(OldIrql);
171 }
172 else
173 {
174 /* Set a wait */
175 CurrentThread->WaitNext = TRUE;
176 CurrentThread->WaitIrql = OldIrql;
177 }
178
179 /* Check if we need to re-enable APCs */
180 if (EnableApc) KeLeaveCriticalRegion();
181
182 /* Return the previous state */
183 return PreviousState;
184 }
185
186 /*
187 * @implemented
188 */
189 LONG
190 NTAPI
191 KeReleaseMutex(IN PKMUTEX Mutex,
192 IN BOOLEAN Wait)
193 {
194 ASSERT_MUTANT(Mutex);
195
196 /* There's no difference at this level between the two */
197 return KeReleaseMutant(Mutex, 1, FALSE, Wait);
198 }
199
200 /* EOF */