diff options
Diffstat (limited to 'private/ntos/ex/semphore.c')
-rw-r--r-- | private/ntos/ex/semphore.c | 614 |
1 files changed, 614 insertions, 0 deletions
diff --git a/private/ntos/ex/semphore.c b/private/ntos/ex/semphore.c new file mode 100644 index 000000000..d2812f368 --- /dev/null +++ b/private/ntos/ex/semphore.c @@ -0,0 +1,614 @@ +/*++ + +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. +// + +GENERIC_MAPPING ExpSemaphoreMapping = { + STANDARD_RIGHTS_READ | + SEMAPHORE_QUERY_STATE, + STANDARD_RIGHTS_WRITE | + SEMAPHORE_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | + SYNCHRONIZE, + SEMAPHORE_ALL_ACCESS +}; + +#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: + + TBS + +--*/ + +{ + + 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. + // + + try { + + // + // Get previous processor mode and probe output handle address if + // necessary. + // + + PreviousMode = KeGetPreviousMode(); + if (PreviousMode != KernelMode) { + ProbeForWriteHandle(SemaphoreHandle); + } + + // + // 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)) { + try { + *SemaphoreHandle = Handle; + } except(ExSystemExceptionFilter()) { + } + } + } + + // + // If an exception occurs during the probe of the output handle address, + // then always handle the exception and return the exception code as the + // status value. + // + + } except(ExSystemExceptionFilter()) { + return GetExceptionCode(); + } + + // + // 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: + + TBS + +--*/ + +{ + + 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. + // + + try { + + // + // Get previous processor mode and probe output handle address if + // necessary. + // + + PreviousMode = KeGetPreviousMode(); + if (PreviousMode != KernelMode) { + ProbeForWriteHandle(SemaphoreHandle); + } + + // + // 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)) { + try { + *SemaphoreHandle = Handle; + } except(ExSystemExceptionFilter()) { + } + } + + // + // If an exception occurs during the probe of the output handle address, + // then always handle the exception and return the exception code as the + // status value. + // + + } except(ExSystemExceptionFilter()) { + return GetExceptionCode(); + } + + + // + // 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: + + TBS + +--*/ + +{ + + 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. + // + + try { + + // + // Get previous processor mode and probe output arguments if necessary. + // + + PreviousMode = KeGetPreviousMode(); + if (PreviousMode != KernelMode) { + ProbeForWrite(SemaphoreInformation, + sizeof(SEMAPHORE_BASIC_INFORMATION), + sizeof(ULONG)); + + if (ARGUMENT_PRESENT(ReturnLength)) { + ProbeForWriteUlong(ReturnLength); + } + } + + // + // 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); + try { + ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->CurrentCount = Count; + ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->MaximumCount = Maximum; + if (ARGUMENT_PRESENT(ReturnLength)) { + *ReturnLength = sizeof(SEMAPHORE_BASIC_INFORMATION); + } + } except(ExSystemExceptionFilter()) { + } + } + + // + // If an exception occurs during the probe of the output arguments, then + // always handle the exception and return the exception code as the status + // value. + // + + } except(ExSystemExceptionFilter()) { + return GetExceptionCode(); + } + + // + // 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: + + TBS + +--*/ + +{ + + 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. + // + + try { + + // + // Get previous processor mode and probe previous count address + // if necessary. + // + + PreviousMode = KeGetPreviousMode(); + if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(PreviousCount))) { + ProbeForWriteLong(PreviousCount); + } + + // + // 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)) { + try { + Count = KeReleaseSemaphore((PKSEMAPHORE)Semaphore, + ExpSemaphoreBoost, + ReleaseCount, + FALSE); + + ObDereferenceObject(Semaphore); + if (ARGUMENT_PRESENT(PreviousCount)) { + try { + *PreviousCount = Count; + } except(ExSystemExceptionFilter()) { + } + } + } except(ExSystemExceptionFilter()) { + ObDereferenceObject(Semaphore); + return GetExceptionCode(); + } + } + + // + // If an exception occurs during the probe of the previous count, then + // always handle the exception and return the exception code as the status + // value. + // + + } except(ExSystemExceptionFilter()) { + return GetExceptionCode(); + } + + // + // Return service status. + // + + return Status; +} |