/*++ Copyright (c) 2012 Minoca Corp. All Rights Reserved Module Name: ob.h Abstract: This header contains definitions for the kernel Object Manager. Author: Evan Green 4-Sep-2012 --*/ // // ------------------------------------------------------------------- Includes // // // --------------------------------------------------------------------- Macros // // // This macro signals the given object. The first parameter is a pointer to an // object (which always begins with an OBJECT_HEADER), and the second parameter // is a SIGNAL_OPTION. See the signal queue function. // #define ObSignalObject(_Object, _SignalOption) \ ObSignalQueue(&(((POBJECT_HEADER)(_Object))->WaitQueue), (_SignalOption)) // // This macro waits on the given object. The first parameter is a pointer to // an object header. The other parameters follow the "wait on queue" function // parameters. // #define ObWaitOnObject(_Object, _Flags, _TimeoutInMilliseconds) \ ObWaitOnQueue(&(((POBJECT_HEADER)(_Object))->WaitQueue), \ (_Flags), \ (_TimeoutInMilliseconds)) // // ---------------------------------------------------------------- Definitions // #define OBJECT_MANAGER_POOL_TAG 0x216A624F // '!jbO' // // This character represents the object directory separator. // #define OBJECT_PATH_SEPARATOR '/' // // Set this flag if the object manager should use the name parameter passed in // directly as the object's name buffer rather than allocating a copy. This // saves some memory for hardcoded strings. // #define OBJECT_FLAG_USE_NAME_DIRECTLY 0x00000001 // // Set this flag if all queues must be signaled before the wait is satisfied. // #define WAIT_FLAG_ALL 0x00000001 // // Set this flag if the wait can be interrupted by an asynchronous signal. // #define WAIT_FLAG_INTERRUPTIBLE 0x00000002 // // Define the number of built in wait block entries. // #define BUILTIN_WAIT_BLOCK_ENTRY_COUNT 8 // // Define a constant that can be passed to wait routines to indicate that the // wait should never time out. // #define WAIT_TIME_INDEFINITE MAX_ULONG // // Define the bitmask of usable flags in each handle table entry. // #define HANDLE_FLAG_MASK 0x7FFFFFFF // // Define the maximum number of handles. This is fairly arbitrary, and it should // be possible to raise this so long as it doesn't collide with INVALID_HANDLE. // #define OB_MAX_HANDLES 0x1000 typedef enum _OBJECT_TYPE { ObjectInvalid, ObjectDirectory, ObjectQueuedLock, ObjectEvent, ObjectProcess, ObjectThread, ObjectDriver, ObjectDevice, ObjectIrp, ObjectInterface, ObjectInterfaceInstance, ObjectInterfaceListener, ObjectVolume, ObjectImageSection, ObjectPipe, ObjectTimer, ObjectTerminalMaster, ObjectTerminalSlave, ObjectSharedMemoryObject, ObjectMaxTypes } OBJECT_TYPE, *POBJECT_TYPE; typedef enum _SIGNAL_STATE { InvalidSignalState, NotSignaledWithWaiters, NotSignaled, SignaledForOne, Signaled, } SIGNAL_STATE, *PSIGNAL_STATE; typedef enum _SIGNAL_OPTION { SignalOptionInvalid, SignalOptionSignalAll, SignalOptionSignalOne, SignalOptionPulse, SignalOptionUnsignal } SIGNAL_OPTION, *PSIGNAL_OPTION; // // ------------------------------------------------------ Data Type Definitions // typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE; typedef VOID (*PDESTROY_OBJECT_ROUTINE) ( PVOID Object ); /*++ Routine Description: This routine is called when an object's reference count drops to zero. It is responsible for cleaning up any auxiliary state inside the object. The object itself will be freed by the object manager. Arguments: Object - Supplies a pointer to the object being destroyed. Return Value: None. --*/ typedef VOID (*PHANDLE_TABLE_ITERATE_ROUTINE) ( PHANDLE_TABLE HandleTable, HANDLE Descriptor, ULONG Flags, PVOID HandleValue, PVOID Context ); /*++ Routine Description: This routine is called on each handle in the handle table for which it was invoked. The handle table will be locked during this call, so this call must not make any calls that would require accessing the handle table. Arguments: HandleTable - Supplies a pointer to the handle table being iterated through. Descriptor - Supplies the handle descriptor for the current handle. Flags - Supplies the flags associated with this handle. HandleValue - Supplies the handle value for the current handle. Context - Supplies an opaque pointer of context that was provided when the iteration was requested. Return Value: None. --*/ typedef VOID (*PHANDLE_TABLE_LOOKUP_CALLBACK) ( PHANDLE_TABLE HandleTable, HANDLE Descriptor, PVOID HandleValue ); /*++ Routine Description: This routine is called whenever a handle is looked up. It is called with the handle table lock still held. Arguments: HandleTable - Supplies a pointer to the handle table being iterated through. Descriptor - Supplies the handle descriptor for the current handle. HandleValue - Supplies the handle value for the current handle. Return Value: None. --*/ /*++ Structure Description: This structure defines a scheduler wait queue, upon which threads can block. Members: Lock - Stores the spin lock used to synchronize access to the structure. State - Stores the signaling state of the object. This is of type SIGNAL_STATE. Waiters - Stores a list of wait blocks waiting on this object. --*/ typedef struct _WAIT_QUEUE { KSPIN_LOCK Lock; volatile ULONG State; LIST_ENTRY Waiters; } WAIT_QUEUE, *PWAIT_QUEUE; /*++ Structure Description: This structure defines a generic kernel object. Members: Type - Stores the object type. NameLength - Stores the length of the name buffer in bytes, including the null terminator. Name - Stores an optional pointer to the pool allocated name. Parent - Stores a pointer to the parent object. SiblingEntry - Stores the list entry for its sibling objects. ChildListHead - Stores the list head for its child objects. Flags - Stores state flags regarding the object. ReferenceCount - Stores the reference count of the object, managed by the Object Manager. DestroyRoutine - Stores an optional pointer to a function to be called when the reference count drops to zero immediately before the object is deallocated. --*/ typedef struct _OBJECT_HEADER OBJECT_HEADER, *POBJECT_HEADER; struct _OBJECT_HEADER { OBJECT_TYPE Type; ULONG NameLength; PSTR Name; POBJECT_HEADER Parent; LIST_ENTRY SiblingEntry; LIST_ENTRY ChildListHead; ULONG Flags; WAIT_QUEUE WaitQueue; volatile ULONG ReferenceCount; PDESTROY_OBJECT_ROUTINE DestroyRoutine; }; typedef struct _WAIT_BLOCK WAIT_BLOCK, *PWAIT_BLOCK; // // -------------------------------------------------------------------- Globals // // // -------------------------------------------------------- Function Prototypes // KSTATUS ObInitialize ( VOID ); /*++ Routine Description: This routine initializes the Object Manager. It requires that the MM pools are online. Arguments: None. Return Value: Status code. --*/ PVOID ObGetRootObject ( VOID ); /*++ Routine Description: This routine returns the root object of the system. Arguments: None. Return Value: Returns a pointer to the root object. --*/ VOID ObInitializeWaitQueue ( PWAIT_QUEUE WaitQueue, SIGNAL_STATE InitialState ); /*++ Routine Description: This routine initializes a wait queue structure. Arguments: WaitQueue - Supplies a pointer to the wait queue to initialize. InitialState - Supplies the initial state to set the queue to. Return Value: None. --*/ PVOID ObCreateObject ( OBJECT_TYPE Type, PVOID Parent, PSTR ObjectName, ULONG NameLength, ULONG DataSize, PDESTROY_OBJECT_ROUTINE DestroyRoutine, ULONG Flags, ULONG Tag ); /*++ Routine Description: This routine creates a new system object. Arguments: Type - Supplies the type of object being created. Parent - Supplies a pointer to the object that this object is a child under. Supply NULL to create an object off the root node. ObjectName - Supplies an optional name for the object. A copy of this string will be made unless the flags specify otherwise. NameLength - Supplies the length of the name string in bytes, including the null terminator. DataSize - Supplies the size of the object body, *including* the object header. DestroyRoutine - Supplies an optional pointer to a function to be called when the reference count of the object drops to zero (immediately before the object is deallocated). Flags - Supplies optional flags indicating various properties of the object. See OBJECT_FLAG_* definitions. Tag - Supplies the pool tag that should be used for the memory allocation. Return Value: Returns a pointer to the new object, on success. The returned structure is assumed to start with an OBJECT_HEADER structure. NULL if the object could not be allocated, the object already exists, or an invalid parameter was passed in. --*/ KERNEL_API VOID ObAddReference ( PVOID Object ); /*++ Routine Description: This routine increases the reference count on an object by 1. Arguments: Object - Supplies a pointer to the object to add a reference to. Return Value: None. --*/ KERNEL_API VOID ObReleaseReference ( PVOID Object ); /*++ Routine Description: This routine decreases the reference count of an object by 1. If this causes the reference count of the object to drop to 0, the object will be freed. This may cascade up the tree. Arguments: Object - Supplies a pointer to the object to subtract a reference from. This structure is presumed to begin with an OBJECT_HEADER structure. Return Value: None. --*/ KSTATUS ObUnlinkObject ( PVOID Object ); /*++ Routine Description: This routine unlinks an object. Arguments: Object - Supplies a pointer to the object to unlink. Return Value: Status code. --*/ KSTATUS ObNameObject ( PVOID Object, PSTR Name, ULONG NameLength, ULONG Tag, BOOL UseNameDirectly ); /*++ Routine Description: This routine names an object. Arguments: Object - Supplies a pointer to the object to name. Name - Supplies a pointer to the object name. NameLength - Supplies the new name's length. Tag - Supplies the pool tag to use to allocate the name. UseNameDirectly - Supplies the new value of the "Use name directly" flag in the object. Return Value: Status code. --*/ PWAIT_BLOCK ObCreateWaitBlock ( ULONG Capacity ); /*++ Routine Description: This routine creates a wait block. While this can be done on the fly, creating a wait block ahead of time is potentially faster if the number of elements being waited on is fairly large (greater than approximately 7). Arguments: Capacity - Supplies the maximum number of queues that will be waited on with this wait block. Return Value: Returns a pointer to the wait block on success. NULL on allocation failure. --*/ VOID ObDestroyWaitBlock ( PWAIT_BLOCK WaitBlock ); /*++ Routine Description: This routine destroys an explicitly created wait block. The wait block must not be actively waiting on anything. Arguments: WaitBlock - Supplies a pointer to the wait block. Return Value: None. --*/ KSTATUS ObWait ( PWAIT_BLOCK WaitBlock, ULONG TimeoutInMilliseconds ); /*++ Routine Description: This routine executes a wait block, waiting on the given list of wait queues for the specified amount of time. Arguments: WaitBlock - Supplies a pointer to the wait block to wait for. TimeoutInMilliseconds - Supplies the number of milliseconds that the given queues should be waited on before timing out. Use WAIT_TIME_INDEFINITE to wait forever. Return Value: STATUS_SUCCESS if the wait completed successfully. STATUS_TIMEOUT if the wait timed out. STATUS_INTERRUPTED if the wait timed out early due to a signal. --*/ KERNEL_API KSTATUS ObWaitOnQueue ( PWAIT_QUEUE Queue, ULONG Flags, ULONG TimeoutInMilliseconds ); /*++ Routine Description: This routine waits on a given wait queue. It is assumed that the caller can ensure externally that the wait queue will remain allocated. Arguments: Queue - Supplies a pointer to the queue to wait on. Flags - Supplies a bitfield of flags governing the behavior of the wait. See WAIT_FLAG_* definitions. TimeoutInMilliseconds - Supplies the number of milliseconds that the given queues should be waited on before timing out. Use WAIT_TIME_INDEFINITE to wait forever. Return Value: Status code. --*/ KERNEL_API KSTATUS ObWaitOnObjects ( PVOID *ObjectArray, ULONG ObjectCount, ULONG Flags, ULONG TimeoutInMilliseconds, PWAIT_BLOCK PreallocatedWaitBlock, PVOID *SignalingObject ); /*++ Routine Description: This routine waits on multiple objects until one (or all in some cases) is signaled. The caller is responsible for maintaining references to these objects. Arguments: ObjectArray - Supplies an array of object pointers containing the objects to wait on. Each object must only be on the list once. ObjectCount - Supplies the number of elements in the array. Flags - Supplies a bitfield of flags governing the behavior of the wait. See WAIT_FLAG_* definitions. TimeoutInMilliseconds - Supplies the number of milliseconds that the given objects should be waited on before timing out. Use WAIT_TIME_INDEFINITE to wait forever on these objects. PreallocatedWaitBlock - Supplies an optional pointer to a pre-allocated wait block to use for the wait. This is optional, however if there are a large number of objects to wait on and this is a common operation, it is a little faster to pre-allocate a wait block and reuse it. SignalingObject - Supplies an optional pointer where the object that satisfied the wait will be returned on success. If the wait was interrupted, this returns NULL. If the WAIT_FLAG_ALL_OBJECTS flag was not specified, the first object to be signaled will be returned. If the WAIT_FLAG_ALL_OBJECTS was specified, the caller should not depend on a particular object being returned here. Return Value: Status code. --*/ KERNEL_API KSTATUS ObWaitOnQueues ( PWAIT_QUEUE *QueueArray, ULONG Count, ULONG Flags, ULONG TimeoutInMilliseconds, PWAIT_BLOCK PreallocatedWaitBlock, PWAIT_QUEUE *SignalingQueue ); /*++ Routine Description: This routine waits on multiple wait queues until one (or all in some cases) is signaled. The caller is responsible for ensuring externally that these wait queues will not somehow be deallocated over the course of the wait. Arguments: QueueArray - Supplies an array of wait queue pointers containing the queues to wait on. Each queue must only be on the list once. Count - Supplies the number of elements in the array. Flags - Supplies a bitfield of flags governing the behavior of the wait. See WAIT_FLAG_* definitions. TimeoutInMilliseconds - Supplies the number of milliseconds that the given queues should be waited on before timing out. Use WAIT_TIME_INDEFINITE to wait forever. PreallocatedWaitBlock - Supplies an optional pointer to a pre-allocated wait block to use for the wait. This is optional, however if there are a large number of queues to wait on and this is a common operation, it is a little faster to pre-allocate a wait block and reuse it. SignalingQueue - Supplies an optional pointer where the queue that satisfied the wait will be returned on success. If the wait was interrupted, this returns NULL. If the WAIT_FLAG_ALL_OBJECTS flag was not specified, the first queue to be signaled will be returned. If the WAIT_FLAG_ALL_OBJECTS was specified, the caller should not depend on a particular queue being returned here. Return Value: Status code. --*/ VOID ObSignalQueue ( PWAIT_QUEUE Queue, SIGNAL_OPTION Signal ); /*++ Routine Description: This routine signals (or unsignals) a wait queue, potentially releasing threads blocking on this object. Arguments: Queue - Supplies a pointer to the wait queue to signal. Signal - Supplies the type of signaling to provide on the queue. Valid values are: SignalOptionSignalAll - Sets the queue to a signaled state and leaves it that way. All threads waiting on this queue will continue. SignalOptionSignalOne - Wakes up one thread waiting on the queue. If no threads are waiting on the queue, the state will be signaled until one thread waits on the queue, at which point it will go back to being unsignaled. SignalOptionPulse - Satisfies all waiters currently waiting on the queue, but does not set the state to signaled. SignalOptionUnsignal - Sets the queue's state to unsignaled. Return Value: None. --*/ BOOL ObWakeBlockedThread ( PVOID ThreadToWake, BOOL OnlyWakeSuspendedThreads ); /*++ Routine Description: This routine wakes up a blocked or suspended thread, interrupting any wait it may have been performing. If the thread was not blocked or suspended or the wait is not interruptible, then this routine does nothing. Arguments: ThreadToWake - Supplies a pointer to the thread to poke. OnlyWakeSuspendedThreads - Supplies a boolean indicating that the thread should only be poked if it's in the suspended state (not if it's in the blocked state). Return Value: TRUE if the thread was actually pulled out of a blocked or suspended state. FALSE if no action was performed because the thread was not stopped. --*/ BOOL ObWakeBlockingThread ( PVOID ThreadToWake ); /*++ Routine Description: This routine wakes up a blocking or suspending thread, interrupting any wait it may have been performing. This routine assumes that the thread is either blocking or suspending. It should not be in another state. Arguments: ThreadToWake - Supplies a pointer to the thread to poke. Return Value: TRUE if the thread was actually pulled out of a blocking or suspending state. FALSE if no action was performed because the thread had already been awoken. --*/ PVOID ObFindObject ( PSTR ObjectName, ULONG BufferLength, POBJECT_HEADER ParentObject ); /*++ Routine Description: This routine locates an object by name. The found object will be returned with an incremented reference count as to ensure it does not disappear while the caller is handling it. It is the caller's responsibility to release this reference. Arguments: ObjectName - Supplies the name of the object to find, either fully-specified or relative. Fully specified names begin with a /. BufferLength - Supplies the length of the name buffer. ParentObject - Supplies the parent object for relative names. Return Value: Returns a pointer to the object with the specified name, or NULL if the object could not be found. --*/ PSTR ObGetFullPath ( PVOID Object, ULONG AllocationTag ); /*++ Routine Description: This routine returns the full path of the given object. The return value will be allocated from paged pool, and it is the caller's responsibility to free it. The object path must not have any unnamed objects anywhere in its parent chain. Arguments: Object - Supplies a pointer to the object whose path to return. AllocationTag - Supplies the allocation tag to use when allocating memory for the return value. Return Value: Returns a pointer to the full path of the object, allocated from paged pool. It is the caller's responsibility to free this memory. NULL on failure, usually a memory allocation failure or an unnamed object somewhere in the path. --*/ PWAIT_QUEUE ObGetBlockingQueue ( PVOID Thread ); /*++ Routine Description: This routine returns one of the wait queues the given thread is blocking on. The caller is not guaranteed that the queue returned has a reference on it and won't disappear before being accessed. Generally this routine is only used by the scheduler for profiling. Arguments: Thread - Supplies a pointer to the thread. Return Value: Returns a pointer to the first wait queue the thread is blocking on, if any. The built-in thread timer does not count. NULL if the thread's wait block is empty. --*/ // // Handle Table routines. // PHANDLE_TABLE ObCreateHandleTable ( PVOID Process, PHANDLE_TABLE_LOOKUP_CALLBACK LookupCallbackRoutine ); /*++ Routine Description: This routine creates a new handle table. This routine must be called at low level. Arguments: Process - Supplies an optional pointer to the process that owns the handle table. When in doubt, supply NULL. LookupCallbackRoutine - Supplies an optional pointer that if supplied points to a function that will get called whenever a handle value is looked up (but not on iterates). Return Value: Returns a pointer to the new handle table on success. NULL on insufficient resource conditions. --*/ VOID ObDestroyHandleTable ( PHANDLE_TABLE HandleTable ); /*++ Routine Description: This routine destroys a handle table. This routine must be called at low level. Arguments: HandleTable - Supplies a pointer to the handle table to destroy. Return Value: None. --*/ KSTATUS ObEnableHandleTableLocking ( PHANDLE_TABLE HandleTable ); /*++ Routine Description: This routine enables locking on the given handle table. Arguments: HandleTable - Supplies a pointer to the handle table to enable locking for. Return Value: Status code. --*/ KSTATUS ObCreateHandle ( PHANDLE_TABLE Table, PVOID HandleValue, ULONG Flags, PHANDLE NewHandle ); /*++ Routine Description: This routine creates a new handle table entry. This routine must be called at low level. Arguments: Table - Supplies a pointer to the handle table. HandleValue - Supplies the value to be associated with the handle. Flags - Supplies a bitfield of flags to set with the handle. This value will be ANDed with HANDLE_FLAG_MASK, so bits set outside of that range will not stick. NewHandle - Supplies a pointer where the handle will be returned. On input, contains the minimum required value for the handle. Supply INVALID_HANDLE as the initial contents to let the system decide (which should be almost always). Return Value: STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if memory could not be allocated for the handle table entry. --*/ VOID ObDestroyHandle ( PHANDLE_TABLE Table, HANDLE Handle ); /*++ Routine Description: This routine destroys a handle. Arguments: Table - Supplies a pointer to the handle table. Handle - Supplies the handle returned when the handle was created. Return Value: None. --*/ KSTATUS ObReplaceHandleValue ( PHANDLE_TABLE Table, HANDLE Handle, PVOID NewHandleValue, ULONG NewFlags, PVOID *OldHandleValue, PULONG OldFlags ); /*++ Routine Description: This routine replaces a handle table entry, or creates a handle if none was there before. This routine must be called at low level. Arguments: Table - Supplies a pointer to the handle table. Handle - Supplies the handle to replace or create. NewHandleValue - Supplies the value to be associated with the handle. NewFlags - Supplies the new handle flags to set. OldHandleValue - Supplies an optional pointer where the original handle value will be returned. OldFlags - Supplies an optional pointer where the original handle flags will be returned. Return Value: STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if memory could not be allocated for the handle table entry. STATUS_TOO_MANY_HANDLES if the given minimum handle value was too high. --*/ PVOID ObGetHandleValue ( PHANDLE_TABLE Table, HANDLE Handle, PULONG Flags ); /*++ Routine Description: This routine looks up the given handle and returns the value associated with that handle. Arguments: Table - Supplies a pointer to the handle table. Handle - Supplies the handle returned when the handle was created. Flags - Supplies an optional pointer that receives value of the handle's flags. Return Value: Returns the value associated with that handle upon success. NULL if the given handle is invalid. --*/ KSTATUS ObGetSetHandleFlags ( PHANDLE_TABLE Table, HANDLE Handle, BOOL Set, PULONG Flags ); /*++ Routine Description: This routine sets and/or returns the flags associated with a handle. The lookup callback routine initialized with the handle table is not called during this operation. Arguments: Table - Supplies a pointer to the handle table. Handle - Supplies the handle whose flags should be retrieved. Set - Supplies a boolean indicating if the value in the flags parameter should be set as the new value. Flags - Supplies a pointer that on input contains the value of the flags to set if the set parameter is TRUE. This value will be ANDed with HANDLE_FLAG_MASK, so bits set outside of that mask will not stick. On output, contains the original value of the flags before the set was performed. Return Value: STATUS_SUCCESS on success. STATUS_INVALID_HANDLE if no such handle could be found. --*/ HANDLE ObGetHighestHandle ( PHANDLE_TABLE Table ); /*++ Routine Description: This routine returns the highest allocated handle. Arguments: Table - Supplies a pointer to the handle table. Return Value: Returns the highest handle number (not the handle value). INVALID_HANDLE if the table is empty. --*/ VOID ObHandleTableIterate ( PHANDLE_TABLE Table, PHANDLE_TABLE_ITERATE_ROUTINE IterateRoutine, PVOID IterateRoutineContext ); /*++ Routine Description: This routine iterates through all handles in the given handle table, and calls the given handle table for each one. The table will be locked when the iterate routine is called, so the iterate routine must not make any calls that would require use of the handle table. Arguments: Table - Supplies a pointer to the handle table to iterate through. IterateRoutine - Supplies a pointer to the routine to be called for each handle in the table. IterateRoutineContext - Supplies an opaque context pointer that will get passed to the iterate routine each time it is called. Return Value: None. --*/