Release the rmap list lock after cleaning the head entry in MmDeleteAllRmaps. This...
[reactos.git] / reactos / ntoskrnl / ke / mutex.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/mutex.c
5 * PURPOSE: Implements Mutexes and Mutants (that silly davec...)
6 *
7 * PROGRAMMERS:
8 * Alex Ionescu (alex@relsoft.net) - Reorganized/commented some of the code.
9 * Simplified some functions, fixed some return values and
10 * corrected some minor bugs, added debug output.
11 * David Welch (welch@mcmail.com)
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* FUNCTIONS *****************************************************************/
21
22 /*
23 * @implemented
24 */
25 VOID
26 STDCALL
27 KeInitializeMutant(IN PKMUTANT Mutant,
28 IN BOOLEAN InitialOwner)
29 {
30 PKTHREAD CurrentThread;
31 KIRQL OldIrql;
32 DPRINT("KeInitializeMutant: %x\n", Mutant);
33
34 /* Check if we have an initial owner */
35 if (InitialOwner == TRUE)
36 {
37 /* We also need to associate a thread */
38 CurrentThread = KeGetCurrentThread();
39 Mutant->OwnerThread = CurrentThread;
40
41 /* We're about to touch the Thread, so lock the Dispatcher */
42 OldIrql = KeAcquireDispatcherDatabaseLock();
43
44 /* And insert it into its list */
45 InsertTailList(&CurrentThread->MutantListHead,
46 &Mutant->MutantListEntry);
47
48 /* Release Dispatcher Lock */
49 KeReleaseDispatcherDatabaseLock(OldIrql);
50 DPRINT("Mutant with Initial Owner\n");
51 }
52 else
53 {
54 /* In this case, we don't have an owner yet */
55 Mutant->OwnerThread = NULL;
56 }
57
58 /* Now we set up the Dispatcher Header */
59 KeInitializeDispatcherHeader(&Mutant->Header,
60 MutantObject,
61 sizeof(KMUTANT) / sizeof(ULONG),
62 InitialOwner ? FALSE : TRUE);
63
64 /* Initialize the default data */
65 Mutant->Abandoned = FALSE;
66 Mutant->ApcDisable = 0;
67 }
68
69 /*
70 * @implemented
71 */
72 VOID
73 STDCALL
74 KeInitializeMutex(IN PKMUTEX Mutex,
75 IN ULONG Level)
76 {
77 DPRINT("KeInitializeMutex: %x\n", Mutex);
78
79 /* Set up the Dispatcher Header */
80 KeInitializeDispatcherHeader(&Mutex->Header,
81 MutantObject,
82 sizeof(KMUTEX) / sizeof(ULONG),
83 TRUE);
84
85 /* Initialize the default data */
86 Mutex->OwnerThread = NULL;
87 Mutex->Abandoned = FALSE;
88 Mutex->ApcDisable = 1;
89 }
90
91 /*
92 * @implemented
93 */
94 LONG
95 STDCALL
96 KeReadStateMutant(IN PKMUTANT Mutant)
97 {
98 /* Return the Signal State */
99 return(Mutant->Header.SignalState);
100 }
101
102 /*
103 * @implemented
104 */
105 LONG
106 STDCALL
107 KeReleaseMutant(IN PKMUTANT Mutant,
108 IN KPRIORITY Increment,
109 IN BOOLEAN Abandon,
110 IN BOOLEAN Wait)
111 {
112 KIRQL OldIrql;
113 LONG PreviousState;
114 PKTHREAD CurrentThread = KeGetCurrentThread();
115 DPRINT("KeReleaseMutant: %x\n", Mutant);
116
117 /* Lock the Dispatcher Database */
118 OldIrql = KeAcquireDispatcherDatabaseLock();
119
120 /* Save the Previous State */
121 PreviousState = Mutant->Header.SignalState;
122
123 /* Check if it is to be abandonned */
124 if (Abandon == FALSE)
125 {
126 /* Make sure that the Owner Thread is the current Thread */
127 if (Mutant->OwnerThread != CurrentThread)
128 {
129 DPRINT1("Trying to touch a Mutant that the caller doesn't own!\n");
130
131 /* Release the lock */
132 KeReleaseDispatcherDatabaseLock(OldIrql);
133
134 /* Raise an exception */
135 ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED :
136 STATUS_MUTANT_NOT_OWNED);
137 }
138
139 /* If the thread owns it, then increase the signal state */
140 Mutant->Header.SignalState++;
141 }
142 else
143 {
144 /* It's going to be abandonned */
145 DPRINT("Abandonning the Mutant\n");
146 Mutant->Header.SignalState = 1;
147 Mutant->Abandoned = TRUE;
148 }
149
150 /* Check if the signal state is only single */
151 if (Mutant->Header.SignalState == 1)
152 {
153 /* Check if it's below 0 now */
154 if (PreviousState <= 0)
155 {
156 /* Remove the mutant from the list */
157 DPRINT("Removing Mutant %p\n", Mutant);
158 RemoveEntryList(&Mutant->MutantListEntry);
159
160 /* Reenable APCs */
161 DPRINT("Re-enabling APCs\n");
162 CurrentThread->KernelApcDisable += Mutant->ApcDisable;
163
164 /* Check if the thread has APCs enabled */
165 if (!CurrentThread->KernelApcDisable)
166 {
167 /* Check if any are pending */
168 if (!IsListEmpty(&CurrentThread->ApcState.ApcListHead[KernelMode]))
169 {
170 /* Set Kernel APC Pending */
171 CurrentThread->ApcState.KernelApcPending = TRUE;
172
173 /* Request the Interrupt */
174 DPRINT("Requesting APC Interupt\n");
175 HalRequestSoftwareInterrupt(APC_LEVEL);
176 }
177 }
178 }
179
180 /* Remove the Owning Thread and wake it */
181 Mutant->OwnerThread = NULL;
182
183 /* Check if the Wait List isn't empty */
184 DPRINT("Checking whether to wake the Mutant\n");
185 if (!IsListEmpty(&Mutant->Header.WaitListHead))
186 {
187 /* Wake the Mutant */
188 DPRINT("Waking the Mutant\n");
189 KiWaitTest(&Mutant->Header, Increment);
190 }
191 }
192
193 /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
194 if (Wait == FALSE)
195 {
196 /* Release the Lock */
197 KeReleaseDispatcherDatabaseLock(OldIrql);
198 }
199 else
200 {
201 /* Set a wait */
202 CurrentThread->WaitNext = TRUE;
203 CurrentThread->WaitIrql = OldIrql;
204 }
205
206 /* Return the previous state */
207 return PreviousState;
208 }
209
210 /*
211 * @implemented
212 */
213 LONG
214 STDCALL
215 KeReleaseMutex(IN PKMUTEX Mutex,
216 IN BOOLEAN Wait)
217 {
218 /* There's no difference at this level between the two */
219 return KeReleaseMutant(Mutex, 1, FALSE, Wait);
220 }
221
222 /* EOF */