/* * Copyright (c) 2009 NVIDIA Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NVIDIA Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ /** * \file nvreftrack.h * \brief NVIDIA kernel object reference tracking utility * * \mainpage * * NvRefTrack implements a database of client to object * references. The sole purpose of the utility is to provide a * mechanism for freeing up kernel mode driver objects on abnormal * client termination. * * This utility is intended to be used together with the NV IDL * automatic call dispatcher generation. 'refadd' and 'refdel' * modifiers for function parameters instruct the IDL generation to * instrument the dispatcher functions with appropriate calls to * NvRtStoreObjRef() and NvRtFreeObjRef(). * * The OS specific kernel driver's responsibility is to create the * NvRt context and to register and unregister clients (user mode * processes accessing the driver). Additionally the context and the * calling client handle need to be passed to the master dispatcher. */ #ifndef INCLUDED_NVREFTRACK_H #define INCLUDED_NVREFTRACK_H #include "nvcommon.h" #include "nverror.h" #ifndef NVRT_ENABLE_LEAK_PRINT #define NVRT_ENABLE_LEAK_PRINT NV_DEBUG #endif /*---------------------------------------------------------*/ /** \defgroup objtype Tracked object types * * NvRefTrack must be able to identify the object types * stored in the database. As the IDL generator can not * produce a list of the types they are statically defined * here. Note that this list of enumerations is not actually * a part of the NvRefTrack public interface - it could be * stored separately. Ideally these enumerations would be * generated by the IDL dispatcher generator. * * The exact syntax of these enumerations is important, as * the IDL generator will refer to these names when creating * reference add/del code in the dispatcher. * * 1) There must a an enumeration for every package that * contains objects to be tracked. The enumeration should * be called NvRtObjType_. * 2) For every object type tracked in the package (every * object type that may have refadd and refdel modifiers * in the idl description) there needs to be an entry in * the enumeration called NvRtObjType__. * 3) The enumerations should start from value 0 and fill * the number space completely up to * NvRtObjType__Num, which will be equal to the * number of tracked object types in the package. */ /** * Tracked object types for package NvRm * \ingroup objtype */ typedef enum { NvRtObjType_NvRm_NvRmMemHandle = 0, NvRtObjType_NvRm_NvRmDmaHandle, NvRtObjType_NvRm_Num, NvRtObjType_NvRm_ForceWord = 0x7FFFFFFF } NvRtObjType_NvRm; /** * Tracked handles for package NvRmGraphics * \ingroup objtype */ typedef enum { NvRtObjType_NvRmGraphics_NvRmChannelHandle = 0, NvRtObjType_NvRmGraphics_NvRmContextHandle, NvRtObjType_NvRmGraphics_Num, NvRtObjType_NvRmGraphics_ForceWord = 0x7FFFFFFF } NvRtObjType_NvRmGraphics; /** * Tracked handles for package NvMM * * Tentative handles to track: * - NvMMManagerHandle, this does not exist - API failure? * - NvMMIRAMScratchHandle, this does not exist - API failure? * Can possibly use references to CodecType, a bit dodgy * - pBlock, why is this not a handle? * - pClientId, why is this not a handle? * \ingroup objtype */ typedef enum { NvRtObjType_NvMM_NvmmPowerClientHandle = 0, NvRtObjType_NvMM_NvmmManagerHandle, NvRtObjType_NvMM_NvmmMgrBlockHandle, NvRtObjType_NvMM_Num, NvRtObjType_NvMM_ForceWord = 0x7FFFFFFF } NvRtObjType_NvMM; /** * Tracked handles for package NvECPackage * * Tentative handles to track: * - NvEcHandle * - NvEcEventRegistrationHandle * \ingroup objtype */ typedef enum { NvRtObjType_NvECPackage_NvEcHandle = 0, NvRtObjType_NvECPackage_NvEcEventRegistrationHandle, NvRtObjType_NvECPackage_Num, NvRtObjType_NvECPackage_ForceWord = 0x7FFFFFFF } NvRtObjType_NvECPackage; /** * Tracked handles for package NvStorManager * * Tentative handles to track: * - NvStorMgrFileHandle * \ingroup objtype */ typedef enum { NvRtObjType_NvStorManager_NvStorMgrFileHandle = 0, NvRtObjType_NvStorManager_Num, NvRtObjType_NvStorManager_ForceWord = 0x7FFFFFFF } NvRtObjType_NvStorManager; /** * Tracked handles for package NvDDKAudio * \ingroup objtype */ typedef enum { NvRtObjType_NvDDKAudio_Num = 0, NvRtObjType_NvDDKAudio_ForceWord = 0x7FFFFFFF } NvRtObjType_NvDDKAudio; /** * Tracked handles for package NvDispMgr * \ingroup objtype */ typedef enum { NvRtObjType_NvDispMgr_Client = 0, NvRtObjType_NvDispMgr_Num, NvRtObjType_NvDispMgr_ForceWord = 0x7FFFFFFF } NvRtObjType_NvDispMgr; /** * Tracked object types for package NvDdkAes * \ingroup objtype */ typedef enum { NvRtObjType_NvDdkAes_NvDdkAesHandle = 0, NvRtObjType_NvDdkAes_Num, NvRtObjType_NvDdkAes_ForceWord = 0x7FFFFFFF } NvRtObjType_NvDdkAes; /*---------------------------------------------------------*/ /** \defgroup os_driver Public interface for os driver */ #if NVRT_ENABLE_LEAK_PRINT #define NVRT_LEAK(driver, objtype, ptr) \ NvOsDebugPrintf("[%s] Leaked reference on client exit: (%s) 0x%08x\n", \ driver, objtype, ptr); #else #define NVRT_LEAK(driver, objtype, ptr) #endif typedef struct NvRtRec* NvRtHandle; typedef NvU32 NvRtClientHandle; typedef NvU32 NvRtObjRefHandle; typedef struct { NvRtHandle Rt; NvRtClientHandle Client; NvU32 PackageIdx; } NvDispatchCtx; #if defined(__cplusplus) extern "C" { #endif /** * Create a reference tracking database. * * The OS driver should create a single database upon driver init for * all the IDL packages that the driver is responsible for. The * created handle should be stored in the global driver context. * * @param NumPackages Number of IDL packages that the driver is * responsible for. * @param NumObjTypesPerPackage A list of the amount of tracked handles * for each of the IDL packages. The order * of the list needs to match the package * indices passed in to the reference * manipulation functions. The XXX_Num value * of the object type enumerations can be used * in constructing the list. * @param RtOut A newly created reference database handle. * @return NvSuccess on success. * * \ingroup os_driver */ NvError NvRtCreate( NvU32 NumPackages, const NvU32* NumObjTypesPerPackage, NvRtHandle* RtOut); /** * Destroy a reference tracking database. * * This frees all resources associated to a reference database and should * be called on driver deinitialization. Note that this function makes no * attempt at freeing any outstanding references, the user must make sure * that references to driver objects have been freed prior to destroying * the database. * * @param Rt The reference database handle. * * \ingroup os_driver */ void NvRtDestroy( NvRtHandle Rt); /** * Register a new client to the reference database. * * For all practical purposes, a client refers to a single entity in the * system that uses the driver via the IDL interface and may terminate * unexpectedly, without freeing the driver resource references it holds. * It makes no sense, for example, to register potential kernel-side users * of the driver into the database as it should be impossible to terminate * such a client unexpectedly without resulting in a complete system failure. * Most commonly, but not necessarily, client == usermode process. * * The client ID returned by this function in the location pointed to by the * ClientOut parameter must be stored in a way that it can be passed along * to the master dispatcher function (in the NvDispatchCtx struct) for all * calls originating from the client. This may, for example, be the return * value from a file handle open (XXX_Open) operation passed back as the * "open context" parameter into XXX_Ioctl calls. * * @param Rt The reference database handle. * @param ClientOut A unique ID for the newly registered client. This * value never equals 0 on success. * @return NvSuccess on success. * * \ingroup os_driver */ NvError NvRtRegisterClient( NvRtHandle Rt, NvRtClientHandle* ClientOut); /** * Add a reference to the already registered client. * * Multiple references to a client may be needed when a single client * can be accessed from multiple entities (processes). * * @param Rt The reference database handle. * @param Client The unique ID of the client. * @return NvSuccess on success. * * \ingroup os_driver */ NvError NvRtAddClientRef( NvRtHandle Rt, NvRtClientHandle Client); /** * Unregister a client from the reference database. * * As client handles are refcounted the caller and nvreftrack must * conspire to know when to process possibly leaked resources. The library * signals the caller about the correct time to free leaked resources by * returning NV_TRUE (standing for: yes, please do cleanup now). * * Upon a return value of NV_TRUE, it is the responsibility of the OS driver to * iterate over the possibly remaining references and implement the tearing * down of those references appropriately. This is accomplished by calling * NvRtFreeObjRef() until no further object pointers are returned by it for * the given (client, package, objtype). After doing the cleanup, the caller * should call NvRtUnregisterClient() once more to actually free the client * handle. * * @param Rt The reference database handle. * @param Client The unique ID of the Client. * @return NV_TRUE if the caller should clean up leaked objects * and call NvRtUnregisterClient() again, NV_FALSE * otherwise. * * \ingroup os_driver */ NvBool NvRtUnregisterClient( NvRtHandle Rt, NvRtClientHandle Client); /** * Set/Get opaque user data associated to a client * * \ingroup os_driver */ void NvRtSetClientUserData( NvRtHandle Rt, NvRtClientHandle Client, void* UserData); void* NvRtGetClientUserData( NvRtHandle Rt, NvRtClientHandle Client); /*---------------------------------------------------------*/ /** \defgroup idl_iface Interface used by generated IDL code * * These functions are mainly intended to be called from the * generated IDL dispatcher code. It is of course possible * to use this interface directly from handwritten driver * code as well. * * An exception to this rule is the NvRtFreeObjRef(), which * the os driver uses to iterate over remaining object * references of a client to be unregistered. **/ /** * Allocate an object reference handle. * * Adding an object reference is broken into two parts, * NvRtAllocObjRef() and NvRtStoreObjRef(). This is so that all * resource allocations for the object reference can be done in * advance to eliminate the need to be able to rollback a driver * object reference add in the generated IDL code. * * The caller must call one of NvRtDiscardObjRef() or * NvRtStoreObjRef() for a NvRtObjRefHandle returned by this * function. Failure to do so will unrecoverably leak the object * reference handle. * * @param Ctx The dispatcher context, filled by the OS driver * @param ObjRef A new handle to an object reference * * \ingroup idl_iface */ NvError NvRtAllocObjRef( const NvDispatchCtx* Ctx, NvRtObjRefHandle* ObjRef); /** * Discard an object reference handle. * * Frees a previously allocated object reference handle without storing * anything in the database. * * @param Ctx The dispatcher context, filled by the OS driver * @param ObjRef An object reference handle * * \ingroup idl_iface */ void NvRtDiscardObjRef( const NvDispatchCtx* Ctx, NvRtObjRefHandle ObjRef); /** * Store an object reference to the database. * * This function adds an object reference to the database. An object * is identified via the the attributes (Ctx.PackageIdx, ObjType, * ObjPtr). The reference is created from Ctx.Client. It is * completely valid to have multiple references to a given object from * the same client, or from multiple clients. * * After calling this function the NvRtObjRefHandle acquired by a call * to NvRtAllocObjRef becomes invalid and may no longer be used for * any other purpose. * * It is the caller's responsibility to make sure that the object type * is within range of the allocated object types for the package. In * practice if the NvRtObjType enumeration is well defined and the * NvRt database correctly initialized with the maximum amount of * objects for the package this should not be an issue. * * @param Ctx The dispatcher context, filled by the OS driver * @param ObjRef An object reference handle * @param ObjType The NvRtObjType of the object to be stored * @param ObjPtr A opaque pointer uniquely identifying the object * that this reference points to. NULL is not allowed. * * \ingroup idl_iface */ void NvRtStoreObjRef( const NvDispatchCtx* Ctx, NvRtObjRefHandle ObjRef, NvU32 ObjType, void* ObjPtr); /** * Find and free an object reference. * * The NvRt API provides no way of enumerating or querying the object * database without simultaneously freeing the object reference as * well. This is intentional - the utility is built for a very * specific purpose and optimized to do that in a fast and robust way. * * This function is used to free a previously stored object * reference. Upon locating an object reference from Ctx.Client to * (Ctx.PackageIdx, ObjType, ObjPtr) it immediately frees the object * reference from the database. * * Passing in NULL as ObjPtr means 'match any', the function will locate and * free the first object reference from Ctx.Client to (Ctx.PackageIdx, * ObjType). This can be used to free all outstanding references from a client, * iterate over all packages and object types that the client may have used, * call NvRtFreeObjRef() with a NULL ObjPtr parameter and free the returned * ObjPtr reference until no more references are returned. * * In any case, if an object reference was found and freed the ObjPtr * of the reference is returned. A NULL return value means that no reference * matching the criteria was found. Note that if the generated IDL code works * correctly this function should never get called with a ObjPtr parameter that * can't be found from the database. * * @param Ctx The dispatcher context, filled by the OS driver * @param ObjType The NvRtObjType of the object to be found * @param ObjPtr A opaque pointer of the object to be found * @return The ObjPtr of the reference free'd, NULL if not found * * \ingroup idl_iface */ void* NvRtFreeObjRef( const NvDispatchCtx* Ctx, NvU32 ObjType, void* ObjPtr); #if defined(__cplusplus) } #endif #endif