1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel 4 * FILE: ntoskrnl/ex/sem.c 5 * PURPOSE: Semaphore Implementation 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, ExpInitializeSemaphoreImplementation) 18 #endif 19 20 /* GLOBALS ******************************************************************/ 21 22 POBJECT_TYPE ExSemaphoreObjectType; 23 24 GENERIC_MAPPING ExSemaphoreMapping = 25 { 26 STANDARD_RIGHTS_READ | SEMAPHORE_QUERY_STATE, 27 STANDARD_RIGHTS_WRITE | SEMAPHORE_MODIFY_STATE, 28 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, 29 SEMAPHORE_ALL_ACCESS 30 }; 31 32 static const INFORMATION_CLASS_INFO ExSemaphoreInfoClass[] = 33 { 34 /* SemaphoreBasicInformation */ 35 IQS_SAME(SEMAPHORE_BASIC_INFORMATION, ULONG, ICIF_QUERY), 36 }; 37 38 /* FUNCTIONS *****************************************************************/ 39 40 CODE_SEG("INIT") 41 BOOLEAN 42 NTAPI 43 ExpInitializeSemaphoreImplementation(VOID) 44 { 45 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 46 UNICODE_STRING Name; 47 NTSTATUS Status; 48 DPRINT("Creating Semaphore Object Type\n"); 49 50 /* Create the Event Pair Object Type */ 51 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 52 RtlInitUnicodeString(&Name, L"Semaphore"); 53 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 54 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KSEMAPHORE); 55 ObjectTypeInitializer.GenericMapping = ExSemaphoreMapping; 56 ObjectTypeInitializer.PoolType = NonPagedPool; 57 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 58 ObjectTypeInitializer.ValidAccessMask = SEMAPHORE_ALL_ACCESS; 59 Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExSemaphoreObjectType); 60 if (!NT_SUCCESS(Status)) return FALSE; 61 return TRUE; 62 } 63 64 /* 65 * @implemented 66 */ 67 NTSTATUS 68 NTAPI 69 NtCreateSemaphore(OUT PHANDLE SemaphoreHandle, 70 IN ACCESS_MASK DesiredAccess, 71 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 72 IN LONG InitialCount, 73 IN LONG MaximumCount) 74 { 75 PKSEMAPHORE Semaphore; 76 HANDLE hSemaphore; 77 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 78 NTSTATUS Status; 79 PAGED_CODE(); 80 81 /* Check if we were called from user-mode */ 82 if (PreviousMode != KernelMode) 83 { 84 /* Enter SEH Block */ 85 _SEH2_TRY 86 { 87 /* Check handle pointer */ 88 ProbeForWriteHandle(SemaphoreHandle); 89 } 90 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 91 { 92 /* Return the exception code */ 93 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 94 } 95 _SEH2_END; 96 } 97 98 /* Make sure the counts make sense */ 99 if ((MaximumCount <= 0) || 100 (InitialCount < 0) || 101 (InitialCount > MaximumCount)) 102 { 103 DPRINT("Invalid Count Data!\n"); 104 return STATUS_INVALID_PARAMETER; 105 } 106 107 /* Create the Semaphore Object */ 108 Status = ObCreateObject(PreviousMode, 109 ExSemaphoreObjectType, 110 ObjectAttributes, 111 PreviousMode, 112 NULL, 113 sizeof(KSEMAPHORE), 114 0, 115 0, 116 (PVOID*)&Semaphore); 117 118 /* Check for Success */ 119 if (NT_SUCCESS(Status)) 120 { 121 /* Initialize it */ 122 KeInitializeSemaphore(Semaphore, 123 InitialCount, 124 MaximumCount); 125 126 /* Insert it into the Object Tree */ 127 Status = ObInsertObject((PVOID)Semaphore, 128 NULL, 129 DesiredAccess, 130 0, 131 NULL, 132 &hSemaphore); 133 134 /* Check for success */ 135 if (NT_SUCCESS(Status)) 136 { 137 /* Enter SEH Block for return */ 138 _SEH2_TRY 139 { 140 /* Return the handle */ 141 *SemaphoreHandle = hSemaphore; 142 } 143 _SEH2_EXCEPT(ExSystemExceptionFilter()) 144 { 145 /* Get the exception code */ 146 Status = _SEH2_GetExceptionCode(); 147 } 148 _SEH2_END; 149 } 150 } 151 152 /* Return Status */ 153 return Status; 154 } 155 156 /* 157 * @implemented 158 */ 159 NTSTATUS 160 NTAPI 161 NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, 162 IN ACCESS_MASK DesiredAccess, 163 IN POBJECT_ATTRIBUTES ObjectAttributes) 164 { 165 HANDLE hSemaphore; 166 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 167 NTSTATUS Status; 168 PAGED_CODE(); 169 170 /* Check if we were called from user-mode */ 171 if (PreviousMode != KernelMode) 172 { 173 /* Enter SEH Block */ 174 _SEH2_TRY 175 { 176 /* Check handle pointer */ 177 ProbeForWriteHandle(SemaphoreHandle); 178 } 179 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 180 { 181 /* Return the exception code */ 182 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 183 } 184 _SEH2_END; 185 } 186 187 /* Open the Object */ 188 Status = ObOpenObjectByName(ObjectAttributes, 189 ExSemaphoreObjectType, 190 PreviousMode, 191 NULL, 192 DesiredAccess, 193 NULL, 194 &hSemaphore); 195 196 /* Check for success */ 197 if (NT_SUCCESS(Status)) 198 { 199 /* Enter SEH Block for return */ 200 _SEH2_TRY 201 { 202 /* Return the handle */ 203 *SemaphoreHandle = hSemaphore; 204 } 205 _SEH2_EXCEPT(ExSystemExceptionFilter()) 206 { 207 /* Get the exception code */ 208 Status = _SEH2_GetExceptionCode(); 209 } 210 _SEH2_END; 211 } 212 213 /* Return Status */ 214 return Status; 215 } 216 217 /* 218 * @implemented 219 */ 220 NTSTATUS 221 NTAPI 222 NtQuerySemaphore(IN HANDLE SemaphoreHandle, 223 IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, 224 OUT PVOID SemaphoreInformation, 225 IN ULONG SemaphoreInformationLength, 226 OUT PULONG ReturnLength OPTIONAL) 227 { 228 PKSEMAPHORE Semaphore; 229 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 230 NTSTATUS Status; 231 PAGED_CODE(); 232 233 /* Check buffers and class validity */ 234 Status = DefaultQueryInfoBufferCheck(SemaphoreInformationClass, 235 ExSemaphoreInfoClass, 236 sizeof(ExSemaphoreInfoClass) / 237 sizeof(ExSemaphoreInfoClass[0]), 238 ICIF_PROBE_READ_WRITE, 239 SemaphoreInformation, 240 SemaphoreInformationLength, 241 ReturnLength, 242 NULL, 243 PreviousMode); 244 if (!NT_SUCCESS(Status)) 245 { 246 /* Invalid buffers */ 247 DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status); 248 return Status; 249 } 250 251 /* Get the Object */ 252 Status = ObReferenceObjectByHandle(SemaphoreHandle, 253 SEMAPHORE_QUERY_STATE, 254 ExSemaphoreObjectType, 255 PreviousMode, 256 (PVOID*)&Semaphore, 257 NULL); 258 259 /* Check for success */ 260 if (NT_SUCCESS(Status)) 261 { 262 /* Entry SEH Block */ 263 _SEH2_TRY 264 { 265 PSEMAPHORE_BASIC_INFORMATION BasicInfo = 266 (PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation; 267 268 /* Return the basic information */ 269 BasicInfo->CurrentCount = KeReadStateSemaphore(Semaphore); 270 BasicInfo->MaximumCount = Semaphore->Limit; 271 272 /* Return the length */ 273 if (ReturnLength) *ReturnLength = sizeof(*BasicInfo); 274 } 275 _SEH2_EXCEPT(ExSystemExceptionFilter()) 276 { 277 /* Get the exception code */ 278 Status = _SEH2_GetExceptionCode(); 279 } 280 _SEH2_END; 281 282 /* Dereference the Object */ 283 ObDereferenceObject(Semaphore); 284 } 285 286 /* Return status */ 287 return Status; 288 } 289 290 /* 291 * @implemented 292 */ 293 NTSTATUS 294 NTAPI 295 NtReleaseSemaphore(IN HANDLE SemaphoreHandle, 296 IN LONG ReleaseCount, 297 OUT PLONG PreviousCount OPTIONAL) 298 { 299 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 300 PKSEMAPHORE Semaphore; 301 NTSTATUS Status; 302 PAGED_CODE(); 303 304 /* Check if we were called from user-mode */ 305 if ((PreviousCount) && (PreviousMode != KernelMode)) 306 { 307 /* Entry SEH Block */ 308 _SEH2_TRY 309 { 310 /* Make sure the state pointer is valid */ 311 ProbeForWriteLong(PreviousCount); 312 } 313 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 314 { 315 /* Return the exception code */ 316 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 317 } 318 _SEH2_END; 319 } 320 321 /* Make sure count makes sense */ 322 if (ReleaseCount <= 0) 323 { 324 DPRINT("Invalid Release Count\n"); 325 return STATUS_INVALID_PARAMETER; 326 } 327 328 /* Get the Object */ 329 Status = ObReferenceObjectByHandle(SemaphoreHandle, 330 SEMAPHORE_MODIFY_STATE, 331 ExSemaphoreObjectType, 332 PreviousMode, 333 (PVOID*)&Semaphore, 334 NULL); 335 336 /* Check for success */ 337 if (NT_SUCCESS(Status)) 338 { 339 /* Enter SEH Block */ 340 _SEH2_TRY 341 { 342 /* Release the semaphore */ 343 LONG PrevCount = KeReleaseSemaphore(Semaphore, 344 IO_NO_INCREMENT, 345 ReleaseCount, 346 FALSE); 347 348 /* Return the old count if requested */ 349 if (PreviousCount) *PreviousCount = PrevCount; 350 } 351 _SEH2_EXCEPT(ExSystemExceptionFilter()) 352 { 353 /* Get the exception code */ 354 Status = _SEH2_GetExceptionCode(); 355 } 356 _SEH2_END; 357 358 /* Dereference the Semaphore */ 359 ObDereferenceObject(Semaphore); 360 } 361 362 /* Return Status */ 363 return Status; 364 } 365 366 /* EOF */ 367