/*++ Copyright (c) 1989 Microsoft Corporation Module Name: semphore.c Abstract: This module implements the executive semaphore object. Functions are provided to create, open, release, and query semaphore objects. Author: David N. Cutler (davec) 8-May-1989 Environment: Kernel mode only. Revision History: --*/ #include "exp.h" // // Temporary so boost is patchable // ULONG ExpSemaphoreBoost = SEMAPHORE_INCREMENT; // // Address of semaphore object type descriptor. // POBJECT_TYPE ExSemaphoreObjectType; // // Structure that describes the mapping of generic access rights to object // specific access rights for semaphore objects. // #ifdef ALLOC_DATA_PRAGMA #pragma const_seg("INITCONST") #endif const GENERIC_MAPPING ExpSemaphoreMapping = { STANDARD_RIGHTS_READ | SEMAPHORE_QUERY_STATE, STANDARD_RIGHTS_WRITE | SEMAPHORE_MODIFY_STATE, STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, SEMAPHORE_ALL_ACCESS }; #ifdef ALLOC_DATA_PRAGMA #pragma const_seg() #endif #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, ExpSemaphoreInitialization) #pragma alloc_text(PAGE, NtCreateSemaphore) #pragma alloc_text(PAGE, NtOpenSemaphore) #pragma alloc_text(PAGE, NtQuerySemaphore) #pragma alloc_text(PAGE, NtReleaseSemaphore) #endif BOOLEAN ExpSemaphoreInitialization ( ) /*++ Routine Description: This function creates the semaphore object type descriptor at system initialization and stores the address of the object type descriptor in local static storage. Arguments: None. Return Value: A value of TRUE is returned if the semaphore object type descriptor is successfully created. Otherwise a value of FALSE is returned. --*/ { OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; NTSTATUS Status; UNICODE_STRING TypeName; // // Initialize string descriptor. // RtlInitUnicodeString(&TypeName, L"Semaphore"); // // Create semaphore object type descriptor. // RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.GenericMapping = ExpSemaphoreMapping; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KSEMAPHORE); ObjectTypeInitializer.ValidAccessMask = SEMAPHORE_ALL_ACCESS; Status = ObCreateObjectType(&TypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ExSemaphoreObjectType); // // If the semaphore object type descriptor was successfully created, then // return a value of TRUE. Otherwise return a value of FALSE. // return (BOOLEAN)(NT_SUCCESS(Status)); } NTSTATUS NtCreateSemaphore ( IN PHANDLE SemaphoreHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN LONG InitialCount, IN LONG MaximumCount ) /*++ Routine Description: This function creates a semaphore object, sets its initial count to the specified value, sets its maximum count to the specified value, and opens a handle to the object with the specified desired access. Arguments: SemaphoreHandle - Supplies a pointer to a variable that will receive the semaphore object handle. DesiredAccess - Supplies the desired types of access for the semaphore object. ObjectAttributes - Supplies a pointer to an object attributes structure. InitialCount - Supplies the initial count of the semaphore object. MaximumCount - Supplies the maximum count of the semaphore object. Return Value: NTSTATUS. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; PVOID Semaphore; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create a semaphore object. If the probe fails, then return // the exception code as the service status. Otherwise return the status // value returned by the object insertion routine. // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(SemaphoreHandle); } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } } // // Check argument validity. // if ((MaximumCount <= 0) || (InitialCount < 0) || (InitialCount > MaximumCount)) { return STATUS_INVALID_PARAMETER; } // // Allocate semaphore object. // Status = ObCreateObject(PreviousMode, ExSemaphoreObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KSEMAPHORE), 0, 0, (PVOID *)&Semaphore); // // If the semaphore object was successfully allocated, then initialize // the semaphore object and attempt to insert the semaphore object in // the current process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeSemaphore((PKSEMAPHORE)Semaphore, InitialCount, MaximumCount); Status = ObInsertObject(Semaphore, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the semaphore object was successfully inserted in the current // process' handle table, then attempt to write the semaphore handle // value. If the write attempt fails, then do not report an error. // When the caller attempts to access the handle value, an access // violation will occur. // if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *SemaphoreHandle = Handle; } except(ExSystemExceptionFilter()) { NOTHING; } } else { *SemaphoreHandle = Handle; } } } // // Return service status. // return Status; } NTSTATUS NtOpenSemaphore ( OUT PHANDLE SemaphoreHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes ) /*++ Routine Description: This function opens a handle to a semaphore object with the specified desired access. Arguments: SemaphoreHandle - Supplies a pointer to a variable that will receive the semaphore object handle. DesiredAccess - Supplies the desired types of access for the semaphore object. ObjectAttributes - Supplies a pointer to an object attributes structure. Return Value: NTSTATUS. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to open a semaphore object. If the probe fails, then return // the exception code as the service status. Otherwise return the status // value returned by the object open routine. // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(SemaphoreHandle); } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } } // // Open handle to the semaphore object with the specified desired access. // Status = ObOpenObjectByName(ObjectAttributes, ExSemaphoreObjectType, PreviousMode, NULL, DesiredAccess, NULL, &Handle); // // If the open was successful, then attempt to write the semaphore // object handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, an // access violation will occur. // if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *SemaphoreHandle = Handle; } except(ExSystemExceptionFilter()) { NOTHING; } } else { *SemaphoreHandle = Handle; } } // // Return service status. // return Status; } NTSTATUS NtQuerySemaphore ( IN HANDLE SemaphoreHandle, IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, OUT PVOID SemaphoreInformation, IN ULONG SemaphoreInformationLength, OUT PULONG ReturnLength OPTIONAL ) /*++ Routine Description: This function queries the state of a semaphore object and returns the requested information in the specified record structure. Arguments: SemaphoreHandle - Supplies a handle to a semaphore object. SemaphoreInformationClass - Supplies the class of information being requested. SemaphoreInformation - Supplies a pointer to a record that is to receive the requested information. SemaphoreInformationLength - Supplies the length of the record that is to receive the requested information. ReturnLength - Supplies an optional pointer to a variable that will receive the actual length of the information that is returned. Return Value: NTSTATUS. --*/ { PVOID Semaphore; LONG Count; LONG Maximum; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output arguments, reference // the semaphore object, and return the specified information. If the probe // fails, then return the exception code as the service status. Otherwise // return the status value returned by the reference object by handle // routine. // // Get previous processor mode and probe output arguments if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteSmallStructure (SemaphoreInformation, sizeof(SEMAPHORE_BASIC_INFORMATION), sizeof(ULONG)); if (ARGUMENT_PRESENT(ReturnLength)) { ProbeForWriteUlong(ReturnLength); } } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } } // // Check argument validity. // if (SemaphoreInformationClass != SemaphoreBasicInformation) { return STATUS_INVALID_INFO_CLASS; } if (SemaphoreInformationLength != sizeof(SEMAPHORE_BASIC_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } // // Reference semaphore object by handle. // Status = ObReferenceObjectByHandle(SemaphoreHandle, SEMAPHORE_QUERY_STATE, ExSemaphoreObjectType, PreviousMode, &Semaphore, NULL); // // If the reference was successful, then read the current state and // maximum count of the semaphore object, dereference semaphore object, // fill in the information structure, and return the length of the // information structure if specified. If the write of the semaphore // information or the return length fails, then do not report an error. // When the caller accesses the information structure or length an // access violation will occur. // if (NT_SUCCESS(Status)) { Count = KeReadStateSemaphore((PKSEMAPHORE)Semaphore); Maximum = ((PKSEMAPHORE)Semaphore)->Limit; ObDereferenceObject(Semaphore); if (PreviousMode != KernelMode) { try { ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->CurrentCount = Count; ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->MaximumCount = Maximum; if (ARGUMENT_PRESENT(ReturnLength)) { *ReturnLength = sizeof(SEMAPHORE_BASIC_INFORMATION); } } except(ExSystemExceptionFilter()) { NOTHING; } } else { ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->CurrentCount = Count; ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->MaximumCount = Maximum; if (ARGUMENT_PRESENT(ReturnLength)) { *ReturnLength = sizeof(SEMAPHORE_BASIC_INFORMATION); } } } // // Return service status. // return Status; } NTSTATUS NtReleaseSemaphore ( IN HANDLE SemaphoreHandle, IN LONG ReleaseCount, OUT PLONG PreviousCount OPTIONAL ) /*++ Routine Description: This function releases a semaphore object by adding the specified release count to the current value. Arguments: Semaphore - Supplies a handle to a semaphore object. ReleaseCount - Supplies the release count that is to be added to the current semaphore count. PreviousCount - Supplies an optional pointer to a variable that will receive the previous semaphore count. Return Value: NTSTATUS. --*/ { LONG Count; PVOID Semaphore; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the previous count address if // specified, reference the semaphore object, and release the semaphore // object. If the probe fails, then return the exception code as the // service status. Otherwise return the status value returned by the // reference object by handle routine. // // Get previous processor mode and probe previous count address // if necessary. // PreviousMode = KeGetPreviousMode(); if ((ARGUMENT_PRESENT(PreviousCount)) && (PreviousMode != KernelMode)) { try { ProbeForWriteLong(PreviousCount); } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } } // // Check argument validity. // if (ReleaseCount <= 0) { return STATUS_INVALID_PARAMETER; } // // Reference semaphore object by handle. // Status = ObReferenceObjectByHandle(SemaphoreHandle, SEMAPHORE_MODIFY_STATE, ExSemaphoreObjectType, PreviousMode, &Semaphore, NULL); // // If the reference was successful, then release the semaphore object. // If an exception occurs because the maximum count of the semaphore // has been exceeded, then dereference the semaphore object and return // the exception code as the service status. Otherwise write the previous // count value if specified. If the write of the previous count fails, // then do not report an error. When the caller attempts to access the // previous count value, an access violation will occur. // if (NT_SUCCESS(Status)) { // // Initialize Count to keep W4 compiler happy. // Count = 0; try { PERFINFO_DECLARE_OBJECT(Semaphore); Count = KeReleaseSemaphore((PKSEMAPHORE)Semaphore, ExpSemaphoreBoost, ReleaseCount, FALSE); } except(ExSystemExceptionFilter()) { Status = GetExceptionCode(); } ObDereferenceObject(Semaphore); if (NT_SUCCESS(Status) && ARGUMENT_PRESENT(PreviousCount)) { if (PreviousMode != KernelMode) { try { *PreviousCount = Count; } except(ExSystemExceptionFilter()) { NOTHING; } } else { *PreviousCount = Count; } } } // // Return service status. // return Status; }