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 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Thomas Weidenmueller 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 #if defined (ALLOC_PRAGMA) 17 #pragma alloc_text(INIT, ExpInitializeMutantImplementation) 18 #endif 19 20 /* DATA **********************************************************************/ 21 22 POBJECT_TYPE ExMutantObjectType = NULL; 23 24 GENERIC_MAPPING ExpMutantMapping = 25 { 26 STANDARD_RIGHTS_READ | MUTANT_QUERY_STATE, 27 STANDARD_RIGHTS_WRITE, 28 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, 29 MUTANT_ALL_ACCESS 30 }; 31 32 static const INFORMATION_CLASS_INFO ExMutantInfoClass[] = 33 { 34 /* MutantBasicInformation */ 35 ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY), 36 }; 37 38 /* FUNCTIONS *****************************************************************/ 39 40 VOID 41 NTAPI 42 ExpDeleteMutant(PVOID ObjectBody) 43 { 44 DPRINT("ExpDeleteMutant(ObjectBody 0x%p)\n", ObjectBody); 45 46 /* Make sure to release the Mutant */ 47 KeReleaseMutant((PKMUTANT)ObjectBody, 48 MUTANT_INCREMENT, 49 TRUE, 50 FALSE); 51 } 52 53 INIT_FUNCTION 54 BOOLEAN 55 NTAPI 56 ExpInitializeMutantImplementation(VOID) 57 { 58 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 59 UNICODE_STRING Name; 60 NTSTATUS Status; 61 DPRINT("Creating Mutant Object Type\n"); 62 63 /* Create the Event Pair Object Type */ 64 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 65 RtlInitUnicodeString(&Name, L"Mutant"); 66 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 67 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KMUTANT); 68 ObjectTypeInitializer.GenericMapping = ExpMutantMapping; 69 ObjectTypeInitializer.PoolType = NonPagedPool; 70 ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant; 71 ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS; 72 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 73 Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExMutantObjectType); 74 if (!NT_SUCCESS(Status)) return FALSE; 75 return TRUE; 76 } 77 78 /* 79 * @implemented 80 */ 81 NTSTATUS 82 NTAPI 83 NtCreateMutant(OUT PHANDLE MutantHandle, 84 IN ACCESS_MASK DesiredAccess, 85 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 86 IN BOOLEAN InitialOwner) 87 { 88 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 89 HANDLE hMutant; 90 PKMUTANT Mutant; 91 NTSTATUS Status; 92 PAGED_CODE(); 93 DPRINT("NtCreateMutant(0x%p, 0x%x, 0x%p)\n", 94 MutantHandle, DesiredAccess, ObjectAttributes); 95 96 /* Check if we were called from user-mode */ 97 if (PreviousMode != KernelMode) 98 { 99 /* Enter SEH Block */ 100 _SEH2_TRY 101 { 102 /* Check handle pointer */ 103 ProbeForWriteHandle(MutantHandle); 104 } 105 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 106 { 107 /* Return the exception code */ 108 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 109 } 110 _SEH2_END; 111 } 112 113 /* Create the Mutant Object*/ 114 Status = ObCreateObject(PreviousMode, 115 ExMutantObjectType, 116 ObjectAttributes, 117 PreviousMode, 118 NULL, 119 sizeof(KMUTANT), 120 0, 121 0, 122 (PVOID*)&Mutant); 123 124 /* Check for success */ 125 if(NT_SUCCESS(Status)) 126 { 127 /* Initialize the Kernel Mutant */ 128 DPRINT("Initializing the Mutant\n"); 129 KeInitializeMutant(Mutant, InitialOwner); 130 131 /* Insert the Object */ 132 Status = ObInsertObject((PVOID)Mutant, 133 NULL, 134 DesiredAccess, 135 0, 136 NULL, 137 &hMutant); 138 139 /* Check for success */ 140 if (NT_SUCCESS(Status)) 141 { 142 /* Enter SEH for return */ 143 _SEH2_TRY 144 { 145 /* Return the handle to the caller */ 146 *MutantHandle = hMutant; 147 } 148 _SEH2_EXCEPT(ExSystemExceptionFilter()) 149 { 150 /* Get the exception code */ 151 Status = _SEH2_GetExceptionCode(); 152 } 153 _SEH2_END; 154 } 155 } 156 157 /* Return Status */ 158 return Status; 159 } 160 161 /* 162 * @implemented 163 */ 164 NTSTATUS 165 NTAPI 166 NtOpenMutant(OUT PHANDLE MutantHandle, 167 IN ACCESS_MASK DesiredAccess, 168 IN POBJECT_ATTRIBUTES ObjectAttributes) 169 { 170 HANDLE hMutant; 171 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 172 NTSTATUS Status; 173 PAGED_CODE(); 174 DPRINT("NtOpenMutant(0x%p, 0x%x, 0x%p)\n", 175 MutantHandle, DesiredAccess, ObjectAttributes); 176 177 /* Check if we were called from user-mode */ 178 if (PreviousMode != KernelMode) 179 { 180 /* Enter SEH Block */ 181 _SEH2_TRY 182 { 183 /* Check handle pointer */ 184 ProbeForWriteHandle(MutantHandle); 185 } 186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 187 { 188 /* Return the exception code */ 189 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 190 } 191 _SEH2_END; 192 } 193 194 /* Open the Object */ 195 Status = ObOpenObjectByName(ObjectAttributes, 196 ExMutantObjectType, 197 PreviousMode, 198 NULL, 199 DesiredAccess, 200 NULL, 201 &hMutant); 202 203 /* Check for success */ 204 if(NT_SUCCESS(Status)) 205 { 206 /* Enter SEH for return */ 207 _SEH2_TRY 208 { 209 /* Return the handle to the caller */ 210 *MutantHandle = hMutant; 211 } 212 _SEH2_EXCEPT(ExSystemExceptionFilter()) 213 { 214 Status = _SEH2_GetExceptionCode(); 215 } 216 _SEH2_END; 217 } 218 219 /* Return Status */ 220 return Status; 221 } 222 223 /* 224 * @implemented 225 */ 226 NTSTATUS 227 NTAPI 228 NtQueryMutant(IN HANDLE MutantHandle, 229 IN MUTANT_INFORMATION_CLASS MutantInformationClass, 230 OUT PVOID MutantInformation, 231 IN ULONG MutantInformationLength, 232 OUT PULONG ResultLength OPTIONAL) 233 { 234 PKMUTANT Mutant; 235 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 236 NTSTATUS Status; 237 PMUTANT_BASIC_INFORMATION BasicInfo = 238 (PMUTANT_BASIC_INFORMATION)MutantInformation; 239 PAGED_CODE(); 240 241 /* Check buffers and parameters */ 242 Status = DefaultQueryInfoBufferCheck(MutantInformationClass, 243 ExMutantInfoClass, 244 sizeof(ExMutantInfoClass) / 245 sizeof(ExMutantInfoClass[0]), 246 MutantInformation, 247 MutantInformationLength, 248 ResultLength, 249 NULL, 250 PreviousMode); 251 if(!NT_SUCCESS(Status)) 252 { 253 DPRINT("NtQueryMutant() failed, Status: 0x%x\n", Status); 254 return Status; 255 } 256 257 /* Open the Object */ 258 Status = ObReferenceObjectByHandle(MutantHandle, 259 MUTANT_QUERY_STATE, 260 ExMutantObjectType, 261 PreviousMode, 262 (PVOID*)&Mutant, 263 NULL); 264 /* Check for Status */ 265 if (NT_SUCCESS(Status)) 266 { 267 /* Enter SEH Block for return */ 268 _SEH2_TRY 269 { 270 /* Fill out the Basic Information Requested */ 271 DPRINT("Returning Mutant Information\n"); 272 BasicInfo->CurrentCount = KeReadStateMutant(Mutant); 273 BasicInfo->OwnedByCaller = (Mutant->OwnerThread == 274 KeGetCurrentThread()); 275 BasicInfo->AbandonedState = Mutant->Abandoned; 276 277 /* Return the Result Length if requested */ 278 if (ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION); 279 } 280 _SEH2_EXCEPT(ExSystemExceptionFilter()) 281 { 282 Status = _SEH2_GetExceptionCode(); 283 } 284 _SEH2_END; 285 286 /* Release the Object */ 287 ObDereferenceObject(Mutant); 288 } 289 290 /* Return Status */ 291 return Status; 292 } 293 294 /* 295 * @implemented 296 */ 297 NTSTATUS 298 NTAPI 299 NtReleaseMutant(IN HANDLE MutantHandle, 300 IN PLONG PreviousCount OPTIONAL) 301 { 302 PKMUTANT Mutant; 303 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 304 NTSTATUS Status; 305 PAGED_CODE(); 306 DPRINT("NtReleaseMutant(MutantHandle 0x%p PreviousCount 0x%p)\n", 307 MutantHandle, 308 PreviousCount); 309 310 /* Check if we were called from user-mode */ 311 if ((PreviousCount) && (PreviousMode != KernelMode)) 312 { 313 /* Entry SEH Block */ 314 _SEH2_TRY 315 { 316 /* Make sure the state pointer is valid */ 317 ProbeForWriteLong(PreviousCount); 318 } 319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 320 { 321 /* Return the exception code */ 322 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 323 } 324 _SEH2_END; 325 } 326 327 /* Open the Object */ 328 Status = ObReferenceObjectByHandle(MutantHandle, 329 0, /* No access rights required */ 330 ExMutantObjectType, 331 PreviousMode, 332 (PVOID*)&Mutant, 333 NULL); 334 335 /* Check for Success and release if such */ 336 if (NT_SUCCESS(Status)) 337 { 338 /* 339 * Release the mutant. doing so might raise an exception which we're 340 * required to catch! 341 */ 342 _SEH2_TRY 343 { 344 /* Release the mutant */ 345 LONG Prev = KeReleaseMutant(Mutant, 346 MUTANT_INCREMENT, 347 FALSE, 348 FALSE); 349 350 /* Return the previous count if requested */ 351 if (PreviousCount) *PreviousCount = Prev; 352 } 353 _SEH2_EXCEPT(ExSystemExceptionFilter()) 354 { 355 /* Get the exception code */ 356 Status = _SEH2_GetExceptionCode(); 357 } 358 _SEH2_END; 359 360 /* Dereference it */ 361 ObDereferenceObject(Mutant); 362 } 363 364 /* Return Status */ 365 return Status; 366 } 367 368 /* EOF */ 369