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