Alex Ionescu <ionucu@videotron.ca>
[reactos.git] / reactos / ntoskrnl / ex / mutant.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/mutant.c
5 * PURPOSE: Executive Management of Mutants
6 *
7 * PROGRAMMERS: Alex Ionescu - Fix tab/space mismatching, tiny fixes to query function and
8 * add more debug output.
9 * David Welch (welch@cwcom.net)
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 POBJECT_TYPE ExMutantObjectType = NULL;
19
20 static GENERIC_MAPPING ExpMutantMapping = {
21 STANDARD_RIGHTS_READ | SYNCHRONIZE | MUTANT_QUERY_STATE,
22 STANDARD_RIGHTS_WRITE | SYNCHRONIZE,
23 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | MUTANT_QUERY_STATE,
24 MUTANT_ALL_ACCESS};
25
26 static const INFORMATION_CLASS_INFO ExMutantInfoClass[] = {
27
28 /* MutantBasicInformation */
29 ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ),
30 };
31
32 /* FUNCTIONS *****************************************************************/
33
34 VOID
35 STDCALL
36 ExpDeleteMutant(PVOID ObjectBody)
37 {
38
39 DPRINT("ExpDeleteMutant(ObjectBody %x)\n", ObjectBody);
40
41 /* Make sure to release the Mutant */
42 KeReleaseMutant((PKMUTANT)ObjectBody,
43 MUTANT_INCREMENT,
44 TRUE,
45 FALSE);
46 }
47
48 VOID
49 INIT_FUNCTION
50 ExpInitializeMutantImplementation(VOID)
51 {
52
53 /* Allocate the Object Type */
54 ExMutantObjectType = ExAllocatePoolWithTag(NonPagedPool, sizeof(OBJECT_TYPE), TAG('M', 't', 'n', 't'));
55
56 /* Create the Object Type */
57 RtlInitUnicodeString(&ExMutantObjectType->TypeName, L"Mutant");
58 ExMutantObjectType->Tag = TAG('M', 't', 'n', 't');
59 ExMutantObjectType->PeakObjects = 0;
60 ExMutantObjectType->PeakHandles = 0;
61 ExMutantObjectType->TotalObjects = 0;
62 ExMutantObjectType->TotalHandles = 0;
63 ExMutantObjectType->PagedPoolCharge = 0;
64 ExMutantObjectType->NonpagedPoolCharge = sizeof(KMUTANT);
65 ExMutantObjectType->Mapping = &ExpMutantMapping;
66 ExMutantObjectType->Dump = NULL;
67 ExMutantObjectType->Open = NULL;
68 ExMutantObjectType->Close = NULL;
69 ExMutantObjectType->Delete = ExpDeleteMutant;
70 ExMutantObjectType->Parse = NULL;
71 ExMutantObjectType->Security = NULL;
72 ExMutantObjectType->QueryName = NULL;
73 ExMutantObjectType->OkayToClose = NULL;
74 ExMutantObjectType->Create = NULL;
75 ExMutantObjectType->DuplicationNotify = NULL;
76 ObpCreateTypeObject(ExMutantObjectType);
77 }
78
79 /*
80 * @implemented
81 */
82 NTSTATUS
83 STDCALL
84 NtCreateMutant(OUT PHANDLE MutantHandle,
85 IN ACCESS_MASK DesiredAccess,
86 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
87 IN BOOLEAN InitialOwner)
88 {
89 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
90 HANDLE hMutant;
91 PKMUTANT Mutant;
92 NTSTATUS Status = STATUS_SUCCESS;
93
94 PAGED_CODE();
95 DPRINT("NtCreateMutant(0x%x, 0x%x, 0x%x)\n", MutantHandle, DesiredAccess, ObjectAttributes);
96
97 /* Check Output Safety */
98 if(PreviousMode == UserMode) {
99
100 _SEH_TRY {
101
102 ProbeForWrite(MutantHandle,
103 sizeof(HANDLE),
104 sizeof(ULONG));
105 } _SEH_HANDLE {
106
107 Status = _SEH_GetExceptionCode();
108
109 } _SEH_END;
110
111 if(!NT_SUCCESS(Status)) return Status;
112 }
113
114 /* Create the Mutant Object*/
115 Status = ObCreateObject(PreviousMode,
116 ExMutantObjectType,
117 ObjectAttributes,
118 PreviousMode,
119 NULL,
120 sizeof(KMUTANT),
121 0,
122 0,
123 (PVOID*)&Mutant);
124
125 /* Check for success */
126 if(NT_SUCCESS(Status)) {
127
128 /* Initalize the Kernel Mutant */
129 DPRINT("Initializing the Mutant\n");
130 KeInitializeMutant(Mutant, InitialOwner);
131
132 /* Insert the Object */
133 Status = ObInsertObject((PVOID)Mutant,
134 NULL,
135 DesiredAccess,
136 0,
137 NULL,
138 &hMutant);
139 ObDereferenceObject(Mutant);
140
141 /* Check for success and return handle */
142 if(NT_SUCCESS(Status)) {
143
144 _SEH_TRY {
145
146 *MutantHandle = hMutant;
147
148 } _SEH_HANDLE {
149
150 Status = _SEH_GetExceptionCode();
151
152 } _SEH_END;
153 }
154 }
155
156 /* Return Status */
157 return Status;
158 }
159
160 /*
161 * @implemented
162 */
163 NTSTATUS
164 STDCALL
165 NtOpenMutant(OUT PHANDLE MutantHandle,
166 IN ACCESS_MASK DesiredAccess,
167 IN POBJECT_ATTRIBUTES ObjectAttributes)
168 {
169 HANDLE hMutant;
170 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
171 NTSTATUS Status = STATUS_SUCCESS;
172
173 PAGED_CODE();
174 DPRINT("NtOpenMutant(0x%x, 0x%x, 0x%x)\n", MutantHandle, DesiredAccess, ObjectAttributes);
175
176 /* Check Output Safety */
177 if(PreviousMode == UserMode) {
178
179 _SEH_TRY {
180
181 ProbeForWrite(MutantHandle,
182 sizeof(HANDLE),
183 sizeof(ULONG));
184 } _SEH_HANDLE {
185
186 Status = _SEH_GetExceptionCode();
187
188 } _SEH_END;
189
190 if(!NT_SUCCESS(Status)) return Status;
191 }
192
193 /* Open the Object */
194 Status = ObOpenObjectByName(ObjectAttributes,
195 ExMutantObjectType,
196 NULL,
197 PreviousMode,
198 DesiredAccess,
199 NULL,
200 &hMutant);
201
202 /* Check for success and return handle */
203 if(NT_SUCCESS(Status)) {
204
205 _SEH_TRY {
206
207 *MutantHandle = hMutant;
208
209 } _SEH_HANDLE {
210
211 Status = _SEH_GetExceptionCode();
212
213 } _SEH_END;
214 }
215
216 /* Return Status */
217 return Status;
218 }
219
220 /*
221 * @implemented
222 */
223 NTSTATUS
224 STDCALL
225 NtQueryMutant(IN HANDLE MutantHandle,
226 IN MUTANT_INFORMATION_CLASS MutantInformationClass,
227 OUT PVOID MutantInformation,
228 IN ULONG MutantInformationLength,
229 OUT PULONG ResultLength OPTIONAL)
230 {
231 PKMUTANT Mutant;
232 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
233 NTSTATUS Status = STATUS_SUCCESS;
234 PMUTANT_BASIC_INFORMATION BasicInfo = (PMUTANT_BASIC_INFORMATION)MutantInformation;
235
236 PAGED_CODE();
237
238 /* Check buffers and parameters */
239 DefaultQueryInfoBufferCheck(MutantInformationClass,
240 ExMutantInfoClass,
241 MutantInformation,
242 MutantInformationLength,
243 ResultLength,
244 PreviousMode,
245 &Status);
246 if(!NT_SUCCESS(Status)) {
247
248 DPRINT("NtQueryMutant() failed, Status: 0x%x\n", Status);
249 return Status;
250 }
251
252 /* Open the Object */
253 Status = ObReferenceObjectByHandle(MutantHandle,
254 MUTANT_QUERY_STATE,
255 ExMutantObjectType,
256 PreviousMode,
257 (PVOID*)&Mutant,
258 NULL);
259 /* Check for Status */
260 if(NT_SUCCESS(Status)) {
261
262 _SEH_TRY {
263
264 /* Fill out the Basic Information Requested */
265 DPRINT("Returning Mutant Information\n");
266 BasicInfo->CurrentCount = KeReadStateMutant(Mutant);
267 BasicInfo->OwnedByCaller = (Mutant->OwnerThread == KeGetCurrentThread());
268 BasicInfo->AbandonedState = Mutant->Abandoned;
269
270 /* Return the Result Length if requested */
271 if(ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION);
272
273 } _SEH_HANDLE {
274
275 Status = _SEH_GetExceptionCode();
276
277 } _SEH_END;
278
279 /* Release the Object */
280 ObDereferenceObject(Mutant);
281 }
282
283 /* Return Status */
284 return Status;
285 }
286
287
288 /*
289 * @implemented
290 */
291 NTSTATUS
292 STDCALL
293 NtReleaseMutant(IN HANDLE MutantHandle,
294 IN PLONG PreviousCount OPTIONAL)
295 {
296 PKMUTANT Mutant;
297 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
298 NTSTATUS Status = STATUS_SUCCESS;
299
300 PAGED_CODE();
301 DPRINT("NtReleaseMutant(MutantHandle 0%x PreviousCount 0%x)\n",
302 MutantHandle,
303 PreviousCount);
304
305 /* Check Output Safety */
306 if(PreviousMode == UserMode && PreviousCount) {
307
308 _SEH_TRY {
309
310 ProbeForWrite(PreviousCount,
311 sizeof(LONG),
312 sizeof(ULONG));
313 } _SEH_HANDLE {
314
315 Status = _SEH_GetExceptionCode();
316
317 } _SEH_END;
318
319 if(!NT_SUCCESS(Status)) return Status;
320 }
321
322 /* Open the Object */
323 Status = ObReferenceObjectByHandle(MutantHandle,
324 MUTANT_QUERY_STATE,
325 ExMutantObjectType,
326 PreviousMode,
327 (PVOID*)&Mutant,
328 NULL);
329
330 /* Check for Success and release if such */
331 if(NT_SUCCESS(Status)) {
332
333 LONG Prev;
334
335 /* Save the Old State */
336 DPRINT("Releasing Mutant\n");
337 Prev = KeReleaseMutant(Mutant, MUTANT_INCREMENT, FALSE, FALSE);
338 ObDereferenceObject(Mutant);
339
340 /* Return it */
341 if(PreviousCount) {
342
343 _SEH_TRY {
344
345 *PreviousCount = Prev;
346
347 } _SEH_HANDLE {
348
349 Status = _SEH_GetExceptionCode();
350
351 } _SEH_END;
352 }
353 }
354
355 /* Return Status */
356 return Status;
357 }
358
359 /* EOF */