/*
 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 * 
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */
#ifndef _LIBKERN_OSMETACLASS_H
#define _LIBKERN_OSMETACLASS_H

#include <sys/types.h>

#include <libkern/OSReturn.h>
#include <kern/debug.h>

class OSMetaClass;
class OSObject;
class OSString;
class OSSymbol;
class OSDictionary;
class OSSerialize;
#ifdef XNU_KERNEL_PRIVATE
class OSOrderedSet;
#endif


/*!
 * @header
 *
 * @abstract
 * This header declares the OSMetaClassBase and OSMetaClass classes,
 * which together form the basis of the Libkern and I/O Kit C++ class hierarchy
 * and run-time type information facility.
 */
 
 
/*! @parseOnly */
#define APPLE_KEXT_COMPATIBILITY

#ifdef XNU_KERNEL_PRIVATE

/*! @parseOnly */
#define APPLE_KEXT_VTABLE_PADDING   1

#else /* XNU_KERNEL_PRIVATE */
#include <TargetConditionals.h>

/*! @parseOnly */
#define APPLE_KEXT_VTABLE_PADDING   1

#endif /* XNU_KERNEL_PRIVATE */

#define APPLE_KEXT_ALIGN_CONTAINERS     (0 == APPLE_KEXT_VTABLE_PADDING)

#if defined(__LP64__)
/*! @parseOnly */
#define APPLE_KEXT_LEGACY_ABI  0
#else
#define APPLE_KEXT_LEGACY_ABI  1
#endif

#if defined(__LP64__)
/*! @parseOnly */
#define APPLE_KEXT_COMPATIBILITY_VIRTUAL
#else
// private method made virtual only for binary compatibility
#define APPLE_KEXT_COMPATIBILITY_VIRTUAL  virtual
#endif

/*! @parseOnly */
#define APPLE_KEXT_DEPRECATED  __attribute__((deprecated))


#if __cplusplus >= 201103L
#define APPLE_KEXT_OVERRIDE  				override
#if defined(__LP64__)
#define APPLE_KEXT_COMPATIBILITY_OVERRIDE
#else
#define APPLE_KEXT_COMPATIBILITY_OVERRIDE	APPLE_KEXT_OVERRIDE
#endif
#else
#define APPLE_KEXT_OVERRIDE
#define APPLE_KEXT_COMPATIBILITY_OVERRIDE
#endif


/*!
 * @class OSMetaClassBase
 *
 * @abstract
 * OSMetaClassBase is the abstract bootstrap class
 * for the Libkern and I/O Kit run-time type information system.
 *
 * @discussion
 * OSMetaClassBase is the abstract C++ root class
 * underlying the entire Libkern and I/O Kit class hierarchy.
 * It defines the run-time type information system,
 * including dynamic class allocation and safe type-casting,
 * as well as the abstract interface for reference counting
 * and a few other utility functions.
 * OSMetaClassBase is the immediate superclass of
 * @link //apple_ref/doc/class/OSObject OSObject@/link and
 * @link //apple_ref/doc/class/OSMetaClass OSMetaClass@/link;
 * no other class should derive from OSMetaClassBase.
 *
 * For more information, see
 * <i>@link //apple_ref/doc/uid/TP40002799
 * I/O Kit Device Driver Design Guidelines@/link</i>.
 *
 * <b>Use by Kernel Extensions</b>
 *
 * Kernel Extensions should never interact directly with OSMetaClassBase,
 * but they will find useful several macros that tie in
 * to the run-time type information system, specifically:
 * <ul>
 * <li><code>@link OSTypeAlloc OSTypeAlloc@/link</code> - allocation of new instances</li>
 * <li><code>@link OSDynamicCast OSDynamicCast@/link</code> - safe type casting</li>
 * <li><code>@link OSCheckTypeInst OSCheckTypeInst@/link</code> -
 *     checking for inheritance/derivation</li>
 * <li><code>@link OSMemberFunctionCast OSMemberFunctionCast@/link</code> -
 *     casting C++ member functions to C function pointers
 *     for registration as callbacks</li>
 * </ul>
 *
 * See @link //apple_ref/doc/class/OSMetaClass OSMetaClass@/link
 * for more run-time type information interfaces.
 *
 * <b>Use Restrictions</b>
 *
 * OSMetaClassBase should not be subclassed by kernel extensions,
 * nor should kernel extensions call its run-time type functions directly.
 *
 * The run-time type functions and macros are <b>not safe</b>
 *  to call in a primary interrupt context.
 *
 * <b>Concurrency Protection</b>
 *
 * The run-time type macros and functions of OSMetaClassBase are thread-safe.
 */
class OSMetaClassBase
{
public:


   /*!
    * @define OSTypeAlloc
    * @hidecontents
    *
    * @abstract
    * Allocates an instance of the named object class.
    *
    * @param type    The name of the desired class to be created,
    *                as a raw token, <i>not</i> a string or macro.
    *
    * @result
    * A pointer to the new, uninitialized object on success;
    * <code>NULL</code> on failure.
    *
    * @discussion
    * See also
    * <code>@link
    * //apple_ref/cpp/clm/OSMetaClass/allocClassWithName/staticOSObject*\/(constchar*)
    * OSMetaClass::allocClassWithName(const char *)@/link</code>
    * and
    * <code>@link
    * //apple_ref/cpp/instm/OSMetaClass/alloc/virtualOSObject*\/()
    * OSMetaClass::alloc@/link</code>.
    *
    * The OSTypeAlloc macro is used to avoid binary compatibility difficulties
    * presented by the C++ <code>new</code> operator.
    */
#define OSTypeAlloc(type)   ((type *) ((type::metaClass)->alloc()))


   /*!
    * @define OSTypeID
    * @hidecontents
    *
    * @abstract
    * Returns the type ID (metaclass) of a class based on its name.
    *
    * @param type    The name of the desired class, as a raw token,
    *                <i>not</i> a string or macro.
    *
    * @result
    * The unique type ID (metaclass) for the class.
    *
    * @discussion
    * It is typically more useful to determine whether a class is derived
    * from another; see
    * <code>@link //apple_ref/cpp/macro/OSDynamicCast OSDynamicCast@/link</code>
    * and
    * <code>@link //apple_ref/cpp/macro/OSCheckTypeInst OSCheckTypeInst@/link</code>.
    */
#define OSTypeID(type)   (type::metaClass)


   /*!
    * @define OSTypeIDInst
    * @hidecontents
    *
    * @abstract
    * Returns the type ID (metaclass) for the class of an object instance.
    *
    * @param typeinst An instance of an OSObject subclass.
    *
    * @result
    * The type ID of that object's class; that is, its metaclass.
    *
    * @discussion
    * It is typically more useful to determine whether an object is derived
    * from a particular class; see
    * <code>@link //apple_ref/cpp/macro/OSDynamicCast OSDynamicCast@/link</code>
    * and
    * <code>@link //apple_ref/cpp/macro/OSCheckTypeInst OSCheckTypeInst@/link</code>.
    */
#define OSTypeIDInst(typeinst)   ((typeinst)->getMetaClass())


   /*!
    * @define OSDynamicCast
    * @hidecontents
    *
    * @abstract
    * Safe type-casting for Libkern C++ objects.
    *
    * @param type    The name of the desired class type, as a raw token,
    *                <i>not</i> a string or macro.
    *                It is assumed you intend to cast to a pointer
    *                to an object of this type.
    *                Type qualifiers, such as <code>const</code>,
    *                are not recognized and will cause
    *                a (usually obscure) compile error.
    * @param inst    A pointer to the object instance to be cast.
    *                May be <code>NULL</code>.
    *
    * @result
    * <code>inst</code> if it is non-<code>NULL</code>
    * and derived from <code>type</code>;
    * otherwise <code>NULL</code>.
    *
    * @discussion
    * <code>OSDynamicCast</code> is a rough equivalent
    * to the standard C++ RTTI <code>dynamic_cast&lt;T&gt;</code> operator.
    * Your code should use this instead of raw C type-casting,
    * and check the resulting value.
    * If the result is non-<code>NULL</code>,
    * the object is safe to use as the type-cast class;
    * if the result is <code>NULL</code>,
    * the object does not derive from the type-cast class
    * and your code should take appropriate steps to handle the error.
    */
#define OSDynamicCast(type, inst)   \
    ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))


   /*!
    * @define OSCheckTypeInst
    * @hidecontents
    *
    * @abstract
    * Checks whether two objects are type-compatible.
    *
    * @param typeinst The reference object.
    * @param inst     The object to check for type compatibility.
    *
    * @result
    * <code>true</code> if both <code>inst</code> and
    * <code>typeinst</code> are non-<code>NULL</code>
    * and <code>inst</code> is derived from the class of <code>typeinst</code>;
    * otherwise <code>false</code>.
    */
#define OSCheckTypeInst(typeinst, inst) \
    OSMetaClassBase::checkTypeInst(inst, typeinst)

#define OSSafeRelease(inst) \
  do { int OSSafeRelease __attribute__ ((deprecated("Use OSSafeReleaseNULL"))); (OSSafeRelease); \
	if (inst) (inst)->release(); } while (0)

/*! @function OSSafeReleaseNULL
 *  @abstract Release an object if not <code>NULL</code>, then set it to <code>NULL</code>.
 *  @param    inst  Instance of an OSObject, may be <code>NULL</code>.
 */
#define OSSafeReleaseNULL(inst)   do { if (inst) (inst)->release(); (inst) = NULL; } while (0)

typedef void (*_ptf_t)(void);

#if APPLE_KEXT_LEGACY_ABI

// Arcane evil code interprets a C++ pointer to function as specified in the
// -fapple-kext ABI, i.e. the gcc-2.95 generated code.  IT DOES NOT ALLOW
// the conversion of functions that are from MULTIPLY inherited classes.

static inline _ptf_t
_ptmf2ptf(const OSMetaClassBase *self, void (OSMetaClassBase::*func)(void))
{
    union {
        void (OSMetaClassBase::*fIn)(void);
        struct {     // Pointer to member function 2.95
            unsigned short fToff;
            short  fVInd;
            union {
                _ptf_t fPFN;
                short  fVOff;
            } u;
        } fptmf2;
    } map;

    map.fIn = func;
    if (map.fptmf2.fToff) {
        panic("Multiple inheritance is not supported");
        return 0;
    } else if (map.fptmf2.fVInd < 0) {
        // Not virtual, i.e. plain member func
        return map.fptmf2.u.fPFN;
    } else {
        union {
            const OSMetaClassBase *fObj;
            _ptf_t **vtablep;
        } u;
        u.fObj = self;

        // Virtual member function so dereference vtable
        return (*u.vtablep)[map.fptmf2.fVInd - 1];
    }
}

#else /* !APPLE_KEXT_LEGACY_ABI */
#if   defined(__i386__) || defined(__x86_64__)

// Slightly less arcane and slightly less evil code to do
// the same for kexts compiled with the standard Itanium C++
// ABI

static inline _ptf_t
_ptmf2ptf(const OSMetaClassBase *self, void (OSMetaClassBase::*func)(void))
{
    union {
        void (OSMetaClassBase::*fIn)(void);
        uintptr_t fVTOffset;
        _ptf_t fPFN;
    } map;

    map.fIn = func;

    if (map.fVTOffset & 1) {
        // virtual
        union {
            const OSMetaClassBase *fObj;
            _ptf_t **vtablep;
        } u;
        u.fObj = self;

        // Virtual member function so dereference vtable
        return *(_ptf_t *)(((uintptr_t)*u.vtablep) + map.fVTOffset - 1);
    } else {
        // Not virtual, i.e. plain member func
        return map.fPFN;
    }
}

#else
#error Unknown architecture.
#endif /* __arm__ */

#endif /* !APPLE_KEXT_LEGACY_ABI */

   /*!
    * @define OSMemberFunctionCast
    * @hidecontents
    *
    * @abstract
    * Converts a C++ member function pointer, relative to an instance,
    * to a C-style pointer to function.
    *
    * @param cptrtype The function type declaration to cast to
    *                 (typically provided as a <code>typedef</code> by  I/O KitKit classes).
    * @param self     The <code>this</code> pointer of the object whose function
    *                 you wish to cache.
    * @param func     The pointer to the member function itself,
    *                 something like <code>&Class::function</code>.
    *
    * @result
    * A pointer to a function of the given type referencing <code>self</code>.  
    *
    * @discussion
    * This function is used to generate pointers to C++ functions for instances,
    * such that they can be registered as callbacks with I/O Kit objects.
    *
    * No warnings are generated.
    *
    * This function will panic if an attempt is made to call it
    * with a multiply-inheriting class.
    */
#define OSMemberFunctionCast(cptrtype, self, func)         \
    (cptrtype) OSMetaClassBase::                           \
        _ptmf2ptf(self, (void (OSMetaClassBase::*)(void)) func)

protected:
    OSMetaClassBase();
    virtual ~OSMetaClassBase();

private:
    // Disable copy constructors of OSMetaClassBase based objects
   /* Not to be included in headerdoc.
    *
    * @function operator =
    *
    * @abstract
    * Disable implicit copy constructor by making private
    *
    * @param src Reference to source object that isn't allowed to be copied.
    */
    void operator =(OSMetaClassBase &src);

   /* Not to be included in headerdoc.
    *
    * @function OSMetaClassBase
    *
    * @abstract
    * Disable implicit copy constructor by making private
    *
    * @param src Reference to source object that isn't allowed to be copied.
    */
    OSMetaClassBase(OSMetaClassBase &src);

public:

// xx-review: the original comment for this makes it sound to me like we don't
// xx-review: catch over-releasing an object...?

   /*!
    * @function release
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/release/virtualvoid/(int)
    * release(int freeWhen)@/link</code>.
    *
    * @discussion
    * See
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/release/virtualvoid/(int)
    * release(int freeWhen)@/link</code>.
    */
    virtual void release(int freeWhen) const = 0;


   /*!
    * @function getRetainCount
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/getRetainCount/virtualint/()
    * getRetainCount()@/link</code>.
    *
    * @discussion
    * See
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/getRetainCount/virtualint/()
    * OSObject::getRetainCount()@/link</code>.
    */
    virtual int getRetainCount() const = 0;


   /*!
    * @function retain
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/retain/virtualvoid/()
    * retain()@/link</code>.
    *
    * @discussion
    * See
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/retain/virtualvoid/()
    * OSObject::retain()@/link</code>.
    */
    virtual void retain() const = 0;


   /*!
    * @function release
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
    * release@/link</code>.
    *
    * @discussion
    * See
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
    * OSObject::release@/link</code>.
    */
    virtual void release() const = 0;


   /*!
    * @function serialize
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/serialize/virtualbool/(OSSerialize*)
    * serialize@/link</code>.
    *
    * @discussion
    * See 
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/serialize/virtualbool/(OSSerialize*)
    * OSObject::serialize@/link</code>.
    */
    virtual bool serialize(OSSerialize * serializer) const = 0;


   /*!
    * @function getMetaClass
    *
    * @abstract
    * Returns the OSMetaClass representing
    * an OSMetaClassBase subclass.
    *
    * @discussion
    * OSObject overrides this abstract member function
    * to return the OSMetaClass object that represents
    * each class for run-time typing.
    */
    virtual const OSMetaClass * getMetaClass() const = 0;


   /*!
    * @function isEqualTo
    *
    * @abstract
    * Checks whether another object is equal to the receiver.
    *
    * @param anObject The object to copmare to the receiver.
    *
    * @result
    * <code>true</code> if the objects are equal, <code>false</code> otherwise.
    *
    * @discussion
    * OSMetaClassBase implements this as a direct pointer comparison,
    * since it has no other information to judge equality by.
    * Subclasses generally override this function
    * to do a more meaningful comparison.
    * For example, OSString implements it to return
    * <code>true</code> if <code>anObject</code>
    * is derived from OSString and represents the same C string.
    */
    virtual bool isEqualTo(const OSMetaClassBase * anObject) const;


   /*!
    * @function metaCast
    *
    * @abstract
    * Casts this object is to the class managed by the given OSMetaClass.
    *
    * @param toMeta A pointer to a constant OSMetaClass
    *               for the desired target type.
    *
    * @result
    * <code>this</code> if the object is derived
    * from the class managed by <code>toMeta</code>,
    * otherwise <code>NULL</code>.
    *
    * @discussion
    * It is far more convenient to use
    * <code>@link OSDynamicCast OSDynamicCast@/link</code>.
    */
    OSMetaClassBase * metaCast(const OSMetaClass * toMeta) const;


   /*!
    * @function metaCast
    *
    * @abstract
    * Casts this object is to the class managed by the named OSMetaClass.
    *
    * @param toMeta An OSSymbol naming the desired target type.
    *
    * @result
    * <code>this</code> if the object is derived
    * from the class named by <code>toMeta</code>,
    * otherwise <code>NULL</code>.
    *
    * @discussion
    * It is far more convenient to use
    * <code>@link OSDynamicCast OSDynamicCast@/link</code>.
    */
    OSMetaClassBase * metaCast(const OSSymbol * toMeta) const;


   /*!
    * @function metaCast
    *
    * @abstract
    * Casts this object is to the class managed by the named OSMetaClass.
    *
    * @param toMeta An OSString naming the desired target type.
    * @result
    * <code>this</code> if the object is derived
    * from the class named by <code>toMeta</code>,
    * otherwise <code>NULL</code>.
    *
    * @discussion
    * It is far more convenient to use
    * <code>@link OSDynamicCast OSDynamicCast@/link</code>.
    */
    OSMetaClassBase * metaCast(const OSString * toMeta) const;


   /*!
    * @function metaCast
    *
    * @abstract
    * Casts this object is to the class managed by the named OSMetaClass.
    *
    * @param toMeta A C string naming the desired target type.
    * @result
    * <code>this</code> if the object is derived
    * from the class named by <code>toMeta</code>,
    * otherwise <code>NULL</code>.
    *
    * @discussion
    * It is far more convenient to use
    * <code>@link OSDynamicCast OSDynamicCast@/link</code>.
    */
    OSMetaClassBase * metaCast(const char * toMeta) const;

    // Helper inlines for run-time type preprocessor macros
   /*!
    * @function safeMetaCast
    *
    * @abstract
    * Casts an object is to the class managed by the given OSMetaClass.
    *
    * @param anObject A pointer to the object to be cast.
    * @param toMeta   A pointer to a constant OSMetaClass
    *                 for the desired target type.
    *
    * @result
    * <code>anObject</code> if the object is derived
    * from the class managed by <code>toMeta</code>,
    * otherwise <code>NULL</code>.
    *
    * @discussion
    * It is far more convenient to use
    * <code>@link OSDynamicCast OSDynamicCast@/link</code>.
    */
    static OSMetaClassBase * safeMetaCast(
        const OSMetaClassBase * anObject,
        const OSMetaClass     * toMeta);

   /*!
    * @function checkTypeInst
    *
    * @abstract
    * Checks whether an object instance is of the same class
    * as another object instance (or a subclass of that class).
    *
    * @param inst       A pointer to the object to check.
    * @param typeinst   A pointer to an object of the class being checked.
    *
    * @result
    * <code>true</code> if the object is derived
    * from the class of <code>typeinst</code>
    * or a subclass of that class,
    * otherwise <code>false</code>.
    *
    * @discussion
    * It is far more convenient to use
    * <code>@link OSCheckTypeInst OSCheckTypeInst@/link</code>.
    */
    static bool checkTypeInst(
        const OSMetaClassBase * inst,
        const OSMetaClassBase * typeinst);

    static void initialize(void);

public:

   /*!
    * @function taggedRetain
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/taggedRetain/virtualvoid/(constvoid*)
    * taggedRetain(const void *)@/link</code>.
    *
    * @discussion
    * See
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/taggedRetain/virtualvoid/(constvoid*)
    * OSObject::taggedRetain(const void *)@/link</code>.
    */
    // WAS: virtual void _RESERVEDOSMetaClassBase0();
    virtual void taggedRetain(const void * tag = 0) const = 0;


   /*!
    * @function taggedRelease
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/taggedRelease/virtualvoid/(constvoid*)
    * taggedRelease(const void *)@/link</code>.
    *
    * @discussion
    * See
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/taggedRelease/virtualvoid/(constvoid*)
    * OSObject::taggedRelease(const void *)@/link</code>.
    */
    // WAS:  virtual void _RESERVEDOSMetaClassBase1();
    virtual void taggedRelease(const void * tag = 0) const = 0;

protected:
   /*!
    * @function taggedRelease
    *
    * @abstract
    * Abstract declaration of
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/taggedRelease/virtualvoid/(constvoid*,constint)
    * taggedRelease(const void *, const int freeWhen)@/link</code>.
    *
    * @discussion
    * See
    * <code>@link
    * //apple_ref/cpp/instm/OSObject/taggedRelease/virtualvoid/(constvoid*,constint)
    * OSObject::taggedRelease(const void *, const int freeWhen)@/link</code>.
    */
    // WAS:  virtual void _RESERVEDOSMetaClassBase2();
    virtual void taggedRelease(
        const void * tag,
        const int    freeWhen) const = 0;

private:
#if APPLE_KEXT_VTABLE_PADDING
    // Virtual Padding
    virtual void _RESERVEDOSMetaClassBase3();
    virtual void _RESERVEDOSMetaClassBase4();
    virtual void _RESERVEDOSMetaClassBase5();
    virtual void _RESERVEDOSMetaClassBase6();
    virtual void _RESERVEDOSMetaClassBase7();
#endif
} APPLE_KEXT_COMPATIBILITY;


#ifdef XNU_KERNEL_PRIVATE
typedef bool (*OSMetaClassInstanceApplierFunction)(const OSObject * instance,
						   void * context);
#endif /* XNU_KERNEL_PRIVATE */

/*!
 * @class OSMetaClass
 *
 * @abstract
 * OSMetaClass manages run-time type information
 * for Libkern and I/O Kit C++ classes.
 *
 * @discussion OSMetaClass manages run-time type information
 * for Libkern and I/O Kit C++ classes.
 * An instance of OSMetaClass exists for (nearly) every such C++ class,
 * keeping track of inheritance relationships, class lookup by name,
 * instance counts, and more.
 * OSMetaClass operates almost entirely behind the scenes,
 * and kernel extensions should rarely, if ever,
 * have to interact directly with OSMetaClass.
 *
 * <b>Use by Kernel Extensions</b>
 *
 * While kernel extensions rarey interact directly with OSMetaClass at run time,
 * they must register their classes with the metaclass system
 * using the macros declared here.
 * The class declaration should use one of these two macros
 * before its first member function declaration:
 * <ul>
 * <li><code>@link OSDeclareDefaultStructors OSDeclareDefaultStructors@/link</code> -
 *     for classes with no abstract member function declarations</li>
 * <li><code>@link OSDeclareAbstractStructors OSDeclareAbstractStructors@/link</code> -
 *     for classes with at least one abstract member function declaration</li>
 * <li><code>@link OSDeclareFinalStructors OSDeclareFinalStructors@/link</code> -
 *     for classes that should not be subclassable by another kext</li>
 * </ul>
 *
 * The class implementation should then use one of these macros:
 * <ul>
 * <li><code>@link OSDefineMetaClassAndStructors
 *           OSDefineMetaClassAndStructors@/link</code> -
 *     for classes with no abstract member function declarations</li>
 * <li><code>@link OSDefineMetaClassAndAbstractStructors
 *           OSDefineMetaClassAndAbstractStructors@/link</code> -
 *     for classes with at least one abstract member function declaration</li>
 * <li><code>@link OSDefineMetaClassAndFinalStructors
 *           OSDefineMetaClassAndFinalStructors@/link</code> -
 *     for classes that should not be subclassable by another kext</li>
 * </ul>
 *
 * Classes in kernel extensions that are intended for use as libraries
 * may need to reserve vtable slots to preserve binary compatibility
 * as new functions are added. They may do so with these macros:
 * <ul>
 * <li><code>@link OSMetaClassDeclareReservedUnused
 *           OSMetaClassDeclareReservedUnused@/link</code> -
 *     reserves a vtable slot</li>
 * <li><code>@link OSMetaClassDefineReservedUnused
 *           OSMetaClassDefineReservedUnused@/link</code> -
 *     defines the reserved vtable slot as an unimplemented function</li>
 * <li><code>@link OSMetaClassDeclareReservedUsed
 *           OSMetaClassDeclareReservedUsed@/link</code> -
 *     documents that a formerly reserved slot is now used</li>
 * <li><code>@link OSMetaClassDefineReservedUsed
 *           OSMetaClassDefineReservedUsed@/link</code> -
 *    documents that a formerly reserved slot is now used</li>
 * </ul>
 *
 * <b>Use Restrictions</b>
 *
 * OSMetaClass should not be explicitly subclassed by kernel extensions
 * (the declare/define macros do that),
 * nor should kernel extensions call its run-time type functions directly.
 *
 * OSMetaClass functions should be considered
 * <b>unsafe</b> to call in a primary interrupt context.
 *
 * <b>Concurrency Protection</b>
 *
 * Kernel extensions should in general not interact
 * with OSMetaClass objects directly,
 * instead using the run-time type macros.
 * Much of OSMetaClass's interface is intended for use
 * by the run-time type information system,
 * which handles concurrency and locking internally.
 */
class OSMetaClass : private OSMetaClassBase
{
    friend class OSKext;
#if IOKITSTATS
	friend class IOStatistics;
#endif

private:
    // Can never be allocated must be created at compile time
    static void * operator new(size_t size);

   /* Reserved for future use.  (Internal use only) */
    struct ExpansionData *reserved;

   /* superClass Handle to the superclass's meta class. */
    const OSMetaClass *superClassLink;

   /* className OSSymbol of the class' name. */
    const OSSymbol *className;

   /* classSize How big is a single instance of this class. */
    unsigned int classSize;

   /* instanceCount Roughly number of instances of the object,
    * +1 for each direct subclass with a nonzero refcount.
    * Used primarily as a code-in-use flag.
    */
    mutable unsigned int instanceCount;

   /* Not to be included in headerdoc.
    *
    * @function OSMetaClass
    *
    * @abstract
    * The default private constructor.
    */
    OSMetaClass();

    // Called by postModLoad
   /* Not to be included in headerdoc.
    *
    * @function logError
    *
    * @abstract
    * Logs an error string for an <code>OSReturn</code> value
    * using <code>printf</code>.
    *
    * @param result  The <code>OSReturn</code> value for which to log a message.
    *
    * @discussion
    * This function is used to log errors loading kernel extensions.
    * Kernel extensions themselves should not call it.
    */
    static void logError(OSReturn result);

public:

   /*!
    * @function getMetaClassWithName
    *
    * @abstract
    * Look up a metaclass in the run-time type information system.
    *
    * @param name The name of the desired class's metaclass. 
    *
    * @result
    * A pointer to the metaclass object if found, <code>NULL</code> otherwise.
    */
    static const OSMetaClass * getMetaClassWithName(const OSSymbol * name);

protected:
   /*!
    * @function retain
    *
    * @abstract
    * Implements the abstract <code>retain</code> function to do nothing.
    *
    * @discussion
    * Since an OSMetaClass instance must remain in existence
    * for as long as its kernel extension is loaded,
    * OSMetaClass does not use reference-counting.
    */
    virtual void retain() const;


   /*!
    * @function release
    *
    * @abstract
    * Implements the abstract <code>release</code> function to do nothing.
    *
    * @discussion
    * Since an OSMetaClass instance must remain in existence
    * for as long as its kernel extension is loaded,
    * OSMetaClass does not use reference-counting.
    */
    virtual void release() const;


   /*!
    * @function release
    *
    * @abstract
    * Implements the abstract <code>release(int freeWhen)</code>
    * function to do nothing.
    *
    * @param freeWhen  Unused.
    *
    * @discussion
    * Since an OSMetaClass instance must remain in existence
    * for as long as its kernel extension is loaded,
    * OSMetaClass does not use reference-counting.
    */
    virtual void release(int freeWhen) const;


   /*!
    * @function taggedRetain
    *
    * @abstract
    * Implements the abstract <code>taggedRetain(const void *)</code>
    * function to do nothing.
    *
    * @param tag  Unused.
    *
    * @discussion
    * Since an OSMetaClass instance must remain in existence
    * for as long as its kernel extension is loaded,
    * OSMetaClass does not use reference-counting.
    */
    virtual void taggedRetain(const void * tag = 0) const;


   /*!
    * @function taggedRelease
    *
    * @abstract
    * Implements the abstract <code>taggedRelease(const void *)</code>
    * function to do nothing.
    *
    * @param tag  Unused.
    *
    * @discussion
    * Since an OSMetaClass instance must remain in existence
    * for as long as its kernel extension is loaded,
    * OSMetaClass does not use reference-counting.
    */
    virtual void taggedRelease(const void * tag = 0) const;


   /*!
    * @function taggedRelease
    *
    * @abstract
    * Implements the abstract <code>taggedRelease(const void *, cont int)</code>
    * function to do nothing.
    *
    * @param tag       Unused.
    * @param freeWhen  Unused.
    *
    * @discussion
    * Since an OSMetaClass instance must remain in existence
    * for as long as its kernel extension is loaded,
    * OSMetaClass does not use reference-counting.
    */
    virtual void taggedRelease(
        const void * tag,
        const int    freeWhen) const;


   /*!
    * @function getRetainCount
    *
    * @abstract
    * Implements the abstract <code>getRetainCount</code>
    * function to return 0.
    *
    * @result
    * Always returns 0.
    *
    * @discussion
    * Since an OSMetaClass instance must remain in existence
    * for as long as its kernel extension is loaded,
    * OSMetaClass does not use reference-counting.
    */
    virtual int getRetainCount() const;


   /* Not to be included in headerdoc.
    *
    * @function getMetaClass
    *
    * @abstract
    * Returns the meta-metaclass.
    *
    * @result
    * The metaclass of the OSMetaClass object.
    */
    virtual const OSMetaClass * getMetaClass() const;


   /*!
    * @function OSMetaClass
    *
    * @abstract
    * Constructor for OSMetaClass objects.
    *
    * @param className  A C string naming the C++ class
    *                   that this OSMetaClass represents.
    * @param superclass The OSMetaClass object representing the superclass
    *                   of this metaclass's class.
    * @param classSize  The allocation size of the represented C++ class.
    *
    * @discussion
    * This constructor is protected and cannot be used
    * to instantiate OSMetaClass directly, as OSMetaClass is an abstract class.
    * This function is called during kext loading
    * to queue C++ classes for registration.
    * See <code>@link preModLoad preModLoad@/link</code> and
    * <code>@link postModLoad postModLoad@/link</code>.
    */
    OSMetaClass(const char * className,
        const OSMetaClass  * superclass,
        unsigned int         classSize);


   /*!
    * @function ~OSMetaClass
    *
    * @abstract
    * Destructor for OSMetaClass objects.
    *
    * @discussion
    * This function is called when the kernel extension that implements
    * the metaclass's class is unloaded.
    * The destructor removes all references to the class
    * from the run-time type information system.
    */
    virtual ~OSMetaClass();

    // Needs to be overriden as NULL as all OSMetaClass objects are allocated
    // statically at compile time, don't accidently try to free them.
    void operator delete(void *, size_t) { }

public:
    static const OSMetaClass * const metaClass;

   /*!
    * @function preModLoad
    *
    * @abstract
    * Prepares the run-time type system
    * for the creation of new metaclasses
    * during loading of a kernel extension (module).
    *
    * @param kextID  The bundle ID of the kext being loaded.
    *
    * @result
    * An opaque handle to the load context
    * for the kernel extension on success;
    * <code>NULL</code> on failure.
    *
    * @discussion
    * <i>Not for use by kernel extensions.</i>
    *
    * Prepares the run-time type information system to record and register
    * metaclasses created by static constructors until a subsequent call to
    * <code>@link postModLoad postModLoad@/link</code>.
    * <code>preModLoad</code> takes a lock to ensure processing of a single
    * load operation at a time; the lock is released by
    * <code>@link postModLoad postModLoad@/link</code>.
    * Any OSMetaClass constructed between these two function calls
    * will be associated with <code>kextID</code>.
    */
    static void * preModLoad(const char * kextID);


   /*!
    * @function checkModLoad
    *
    * @abstract
    * Checks whether the current kext load operation can proceed.
    *
    * @param loadHandle The opaque handle returned
    *                   by <code>@link preModLoad preModLoad@/link</code>.
    * @result
    * <code>true</code> if no errors are outstanding
    * and the system is ready to process more metaclasses.
    *
    * @discussion
    * <i>Not for use by kernel extensions.</i>
    */
    static bool checkModLoad(void * loadHandle);


   /*!
    * @function postModLoad
    *
    * @abstract
    * Registers the metaclasses created during loading of a kernel extension.
    *
    * @param loadHandle The opaque handle returned
    *                   by <code>@link preModLoad preModLoad@/link</code>.
    * @result
    * The error code of the first error encountered,
    * or
    * <code>@link
    * //apple_ref/cpp/macro/kOSReturnSuccess
    * kOSReturnSuccess@/link</code>
    * if no error occurred.
    *
    * @discussion
    * <i>Not for use by kernel extensions.</i>
    *
    * Called after all static constructors in a kernel extension
    * have created metaclasses,
    * this function checks for duplicate class names,
    * then registers the new metaclasses under the kext ID
    * that @link preModLoad preModLoad@/link was called with,
    * so that they can be dynamically allocated
    * and have their instance counts tracked.
    * <code>postModLoad</code> releases the lock taken by
    * <code>@link preModLoad preModLoad@/link</code>.
    */
    static OSReturn postModLoad(void * loadHandle);

   /*!
    * @function modHasInstance
    *
    * @abstract
    * Returns whether any classes defined by the named
    * kernel extension (or their subclasses) have existing instances.
    *
    * @param kextID   The bundle ID of the kernel extension to check.
    *
    * @result
    * <code>true</code> if the kext is found and
    * if any class defined by that kext
    * has a nonzero instance count,
    * <code>false</code> otherwise.
    *
    * @discussion
    * This function is called before a kernel extension's static destructors
    * are invoked, prior to unloading the extension.
    * If any classes stil have instances or subclasses with instances,
    * those classes are logged
    * (using <code>@link reportModInstances reportModInstances@/link</code>) and
    * the kernel extension is not be unloaded.
    */
    static bool modHasInstance(const char * kextID);


   /*!
    * @function reportModInstances
    *
    * @abstract
    * Logs the instance counts for classes
    * defined by a kernel extension.
    *
    * @param kextID   The bundle ID of the kernel extension to report on.
    *
    * @discussion
    * This function prints the names and instance counts
    * of any class defined by <code>kextID</code>
    * that has a nonzero instance count.
    * It's called by <code>@link modHasInstance modHasInstance@/link</code>
    * to help diagnose problems unloading kernel extensions.
    */
    static void reportModInstances(const char * kextID);


   /*!
    * @function considerUnloads
    *
    * @abstract
    * Schedule automatic unloading of unused kernel extensions.
    *
    * @discussion
    * This function schedules a check for kernel extensions
    * that can be automatically unloaded,
    * canceling any currently scheduled check.
    * At that time, any such kexts with no Libkern C++ instances
    * and no external references are unloaded.
    *
    * The I/O Kit calls this function when matching goes idle.
    *
    * Kernel extensions that define subclasses of
    * @link //apple_ref/doc/class/IOService IOService@/link
    * are eligible for automatic unloading.
    *
    * (On releases of Mac OS X prior to Snow Leopard (10.6),
    * any kernel extension defining any Libkern C++ class
    * was eligible for automatic unloading,
    * but that unload did not call the module stop routine.
    * Non-I/O Kit kernel extensions that define Libkern C++ subclasses
    * should be sure to have OSBundleLibraries declarations that ensure
    * they will not load on releases prior to Snow Leopard.)
    */
    static void considerUnloads();


   /*!
    * @function allocClassWithName
    *
    * @abstract
    * Allocates an instance of a named OSObject-derived class.
    *
    * @param name The name of the desired class. 
    *
    * @result
    * A pointer to the newly-allocated, uninitialized object on success;
    * <code>NULL</code> on failure.
    *
    * @discussion
    * Kernel extensions should not need to use this function
    * directly, instead using static instance-creation functions
    * defined by classes.
    *
    * This function consults the run-time type information system
    * to find the metaclass for the named class.
    * If it exists, it calls the metaclass's <code>@link alloc alloc@/link</code>
    * function and returns the result.
    */
    static OSObject * allocClassWithName(const OSSymbol * name);


   /*!
    * function allocClassWithName
    *
    * @abstract
    * Allocates an instance of a named OSObject-derived class.
    *
    * @param name The name of the desired class. 
    *
    * @result
    * A pointer to the newly-allocated, uninitialized object on success;
    * <code>NULL</code> on failure.
    *
    * @discussion
    * Kernel extensions should not need to use this function
    * directly, instead using static instance-creation functions
    * defined by classes.
    *
    * This function consults the run-time type information system
    * to find the metaclass for the named class.
    * If it exists, it calls the metaclass's <code>@link alloc alloc@/link</code>
    * function and returns the result.
    */
    static OSObject * allocClassWithName(const OSString * name);


   /*!
    * function allocClassWithName
    *
    * @abstract
    * Allocates an instance of a named OSObject-derived class.
    *
    * @param name The name of the desired class. 
    *
    * @result
    * A pointer to the newly-allocated, uninitialized object on success;
    * <code>NULL</code> on failure.
    *
    * @discussion
    * Kernel extensions should not need to use this function
    * directly, instead using static instance-creation functions
    * defined by classes.
    *
    * This function consults the run-time type information system
    * to find the metaclass for the named class.
    * If it exists, it calls the metaclass's <code>@link alloc alloc@/link</code>
    * function and returns the result.
    */
    static OSObject * allocClassWithName(const char * name);


   /*!
    * @function checkMetaCastWithName
    *
    * @abstract
    * Search the metaclass inheritance hierarchy by name for an object instance.
    *
    * @param className The name of the desired class or superclass. 
    * @param object    The object whose metaclass begins the search.
    *
    * @result
    * <code>object</code> if it's derived from <code>className</code>;
    * <code>NULL</code> otherwise.
    *   
    * @discussion
    * This function is the basis of the Libkern run-time type-checking system.
    * Kernel extensions should not use it directly,
    * instead using <code>@link OSDynamicCast OSDynamicCast@/link</code> or
    * <code>@link OSCheckTypeInst OSCheckTypeInst@/link</code>.
    */
    static OSMetaClassBase * checkMetaCastWithName(
        const OSSymbol        * className,
        const OSMetaClassBase * object);

   /*!
    * @function checkMetaCastWithName
    *
    * @abstract
    * Search the metaclass inheritance hierarchy by name for an object instance.
    *
    * @param className The name of the desired class or superclass. 
    * @param object    The object whose metaclass begins the search.
    *
    * @result
    * <code>object</code> if it's derived from <code>className</code>;
    * <code>NULL</code> otherwise.
    *   
    * @discussion
    * Kernel extensions should not use this function directly,
    * instead using <code>@link OSDynamicCast OSDynamicCast@/link</code> or
    * <code>@link OSCheckTypeInst OSCheckTypeInst@/link</code>.
    */
    static OSMetaClassBase * checkMetaCastWithName(
        const OSString        * className,
        const OSMetaClassBase * object);

   /*!
    * @function checkMetaCastWithName
    *
    * @abstract
    * Search the metaclass inheritance hierarchy by name for an object instance.
    *
    * @param className The name of the desired class or superclass. 
    * @param object    The object whose metaclass begins the search.
    *
    * @result
    * <code>object</code> if it's derived from <code>className</code>;
    * <code>NULL</code> otherwise.
    *   
    * @discussion
    * Kernel extensions should not use this function directly,
    * instead using <code>@link OSDynamicCast OSDynamicCast@/link</code> or
    * <code>@link OSCheckTypeInst OSCheckTypeInst@/link</code>.
    */
    static OSMetaClassBase * checkMetaCastWithName(
        const char            * className,
        const OSMetaClassBase * object);


   /*!
    * @function instanceConstructed
    *
    * @abstract
    * Counts the instances of the class managed by this metaclass.
    *
    * @discussion
    * <i>Not for use by kernel extensions.</i>
    *
    * Every non-abstract class that inherits from OSObject
    * has a default constructor that calls it's own metaclass's
    * <code>instanceConstructed</code> function.
    * This constructor is defined by the
    * <code>@link
    * OSDefineMetaClassAndStructors
    * OSDefineMetaClassAndStructors@/link</code>
    * macro that all OSObject subclasses must use.
    *
    * If a class's instance count goes from 0 to 1--that is,
    * upon the creation of the first instance of that class--the
    * superclass's instance count is also incremented.
    * This propagates reference counts up the inheritance chain so that
    * superclasses are counted as "in use" when subclasses have instances.
    */
    void instanceConstructed() const;


   /*!
    * @function instanceDestructed
    *
    * @abstract
    * Counts the instances of the class managed by this metaclass.
    *
    * @discussion
    * Every non-abstract class that inherits from OSObject
    * has a default destructor that calls it's own metaclass's
    * <code>instanceDestructed</code> function.
    * This constructor is defined by the
    * @link OSDefineMetaClassAndStructors OSDefineMetaClassAndStructors@/link
    * macro that all OSObject subclasses must use.
    *
    * If a class's instance count goes from 1 to 0--that is,
    * upon the destruction of the last instance of that class--the
    * superclass's instance count is also decremented.
    * This reduces "in use" counts from superclasses when their subclasses
    * no longer have instances.
    */
    void instanceDestructed() const;


   /*!
    * @function checkMetaCast
    *
    * @abstract
    * Check whether a given object is an instance of the receiving
    * metaclass's class or one derived from it.
    *
    * @param object The object to check for inheritance.
    *
    * @result
    * <code>object</code> if it is derived from the receiver's class,
    * <code>NULL</code> if not.
    */
    OSMetaClassBase * checkMetaCast(const OSMetaClassBase * object) const;


   /*!
    * @function getInstanceCount
    *
    * @abstract
    * Returns the number of existing instances of the metaclass's class.
    *
    * @result
    * The number of existing instances of the metaclass's class,
    * plus 1 for each subclass with any instance.
    */
    unsigned int getInstanceCount() const;


   /*!
    * @function getSuperClass
    *
    * @abstract
    * Returns the super-metaclass of the receiver.
    *
    * @result
    * Returns a pointer to the super-metaclass of the receiving
    * OSMetaClass, or <code>NULL</code> for OSObject's metaclass.
    */
    const OSMetaClass * getSuperClass() const;

   /*!
    * @function getKmodName
    *
    * @abstract
    * Returns the bundle identifier of the kernel extension
    * that defines this metaclass.
    *
    * @result
    * The bundle identifier of the kernel extension that defines this metaclass.
    *
    * @discussion
    * "Kmod" is an older term for kernel extension.
    */
    const OSSymbol * getKmodName() const;


   /*!
    * @function getClassName
    *
    * @abstract
    * Returns the name of the C++ class managed by this metaclass.
    *
    * @result
    * Returns the name of the C++ class managed by this metaclass.
    */
    const char * getClassName() const;
    const OSSymbol * getClassNameSymbol() const;


   /*!
    * @function getClassSize
    *
    * @abstract
    * Returns the allocation size of the C++ class managed by this metaclass.
    *
    * @result
    * The allocation size of the C++ class managed by this metaclass.
    */
    unsigned int getClassSize() const;


   /*!
    * @function alloc
    *
    * @abstract
    * Allocates an instance of the C++ class managed by this metaclass.
    *
    * @result
    * A pointer to the newly allocated, uninitialized instance,
    * with a retain count of 1; <code>NULL</code> on allocation failure.
    *
    * @discussion
    * This function is automatically created by the metaclass-registration macros
    * to enable dynamic instance allocation.
    */
    virtual OSObject * alloc() const = 0;

#ifdef XNU_KERNEL_PRIVATE
    void addInstance(const OSObject * instance, bool super = false) const;	
    void removeInstance(const OSObject * instance, bool super = false) const;
    void applyToInstances(OSMetaClassInstanceApplierFunction applier, 
                          void * context) const;
    static void applyToInstancesOfClassName(
    				const OSSymbol * name,
    				OSMetaClassInstanceApplierFunction  applier,
                                void * context);
private:
    static void applyToInstances(OSOrderedSet * set,
			         OSMetaClassInstanceApplierFunction  applier,
                                 void * context);
public:
#endif

   /* Not to be included in headerdoc.
    *
    * @define OSDeclareCommonStructors
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className The name of the C++ class, as a raw token,
    *                  <i>not</i> a string or macro.
    */
#define OSDeclareCommonStructors(className)                     \
    private:                                                    \
    static const OSMetaClass * const superClass;                \
    public:                                                     \
    static const OSMetaClass * const metaClass;                 \
        static class MetaClass : public OSMetaClass {           \
        public:                                                 \
            MetaClass();                                        \
            virtual OSObject *alloc() const;                    \
        } gMetaClass;                                           \
        friend class className ::MetaClass;                     \
        virtual const OSMetaClass * getMetaClass() const APPLE_KEXT_OVERRIDE; \
    protected:                                                  \
    className (const OSMetaClass *);                            \
    virtual ~ className ()


   /*!
    * @define OSDeclareDefaultStructors
    * @hidecontents
    *
    * @abstract
    * Declares run-time type information and functions
    * for a concrete Libkern C++ class.
    *
    * @param className The name of the C++ class, as a raw token,
    *                  <i>not</i> a string or macro.
    *
    * @discussion
    * Concrete Libkern C++ classes should "call" this macro
    * immediately after the opening brace in a class declaration.
    * It leaves the current privacy state as <code>protected:</code>.
    */
#define OSDeclareDefaultStructors(className)    \
    OSDeclareCommonStructors(className);        \
    public:                                     \
    className ();                               \
    protected:


   /*!
    * @define OSDeclareAbstractStructors
    * @hidecontents
    *
    * @abstract
    * Declares run-time type information and functions
    * for an abstract Libkern C++ class.
    *
    * @param className The name of the C++ class, as a raw token,
    *                  <i>not</i> a string or macro.
    *
    * @discussion
    * Abstract Libkern C++ classes--those with at least one
    * pure virtual method--should "call" this macro
    * immediately after the opening brace in a class declaration.
    * It leaves the current privacy state as <code>protected:</code>.
    */
#define OSDeclareAbstractStructors(className)                          \
    OSDeclareCommonStructors(className);                               \
    private:                                                           \
    className (); /* Make primary constructor private in abstract */   \
    protected:

   /*!
    * @define OSDeclareFinalStructors
    * @hidecontents
    *
    * @abstract
    * Declares run-time type information and functions
    * for a final (non-subclassable) Libkern C++ class.
    *
    * @param className The name of the C++ class, as a raw token,
    *                  <i>not</i> a string or macro.
    *
    * @discussion
    * Final Libkern C++ classes--those that do not allow subclassing--should
    * "call" this macro immediately after the opening brace in a class declaration.
    * (Final classes in the kernel may actually have subclasses in the kernel,
    * but kexts cannot define any subclasses of a final class.)
    * It leaves the current privacy state as <code>protected:</code>.
    *
    * <b>Note:</b> If the class is exported by a pseudokext (symbol set),
    * the final symbol generated by this macro must be exported
    * for the final-class attribute to be enforced.
    *
    * <b>Warning:</b> Changing a class from "Default" to "Final" will break
    * binary compatibility.
    */
#define OSDeclareFinalStructors(className)                              \
        OSDeclareDefaultStructors(className)                            \
    private:                                                            \
        void __OSFinalClass(void);                                      \
    protected:


   /* Not to be included in headerdoc.
    *
    * @define OSDefineMetaClassWithInit
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    * @param init           A function to call in the constructor
    *                       of the class's OSMetaClass.
    */
#define OSDefineMetaClassWithInit(className, superclassName, init)            \
    /* Class global data */                                                   \
    className ::MetaClass className ::gMetaClass;                             \
    const OSMetaClass * const className ::metaClass =                         \
        & className ::gMetaClass;                                             \
    const OSMetaClass * const className ::superClass =                        \
        & superclassName ::gMetaClass;                                        \
    /* Class member functions */                                              \
    className :: className(const OSMetaClass *meta)                           \
        : superclassName (meta) { }                                           \
    className ::~ className() { }                                             \
    const OSMetaClass * className ::getMetaClass() const                      \
        { return &gMetaClass; }                                               \
    /* The ::MetaClass constructor */                                         \
    className ::MetaClass::MetaClass()                                        \
        : OSMetaClass(#className, className::superClass, sizeof(className))   \
        { init; }


   /* Not to be included in headerdoc.
    *
    * @define OSDefineAbstractStructors
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    */
#define OSDefineAbstractStructors(className, superclassName)        \
    OSObject * className ::MetaClass::alloc() const { return 0; }


   /* Not to be included in headerdoc.
    *
    * @define OSDefineDefaultStructors
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    */
#define OSDefineDefaultStructors(className, superclassName)     \
    OSObject * className ::MetaClass::alloc() const             \
    { return new className; }                                   \
    className :: className () : superclassName (&gMetaClass)    \
    { gMetaClass.instanceConstructed(); }

   /* Not to be included in headerdoc.
    *
    * @define OSDefineDefaultStructors
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    */
#define OSDefineFinalStructors(className, superclassName)               \
    OSDefineDefaultStructors(className, superclassName)                 \
    void className ::__OSFinalClass(void) { }


   /* Not to be included in headerdoc.
    *
    * @define OSDefineMetaClassAndStructorsWithInit
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    * @param init           A function to call in the constructor
    *                       of the class's OSMetaClass.
    */
#define OSDefineMetaClassAndStructorsWithInit(className, superclassName, init) \
    OSDefineMetaClassWithInit(className, superclassName, init)        \
    OSDefineDefaultStructors(className, superclassName)


   /* Not to be included in headerdoc.
    *
    * @define OSDefineMetaClassAndAbstractStructorsWithInit
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    * @param init           A function to call in the constructor
    *                       of the class's OSMetaClass.
    */
#define OSDefineMetaClassAndAbstractStructorsWithInit(className, superclassName, init) \
    OSDefineMetaClassWithInit(className, superclassName, init)        \
    OSDefineAbstractStructors(className, superclassName)


   /* Not to be included in headerdoc.
    *
    * @define OSDefineMetaClassAndFinalStructorsWithInit
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    * @param init           A function to call in the constructor
    *                       of the class's OSMetaClass.
    */
#define OSDefineMetaClassAndFinalStructorsWithInit(className, superclassName, init) \
    OSDefineMetaClassWithInit(className, superclassName, init)                      \
    OSDefineFinalStructors(className, superclassName)


   /* Helpers */

   /* Not to be included in headerdoc.
    *
    * @define OSDefineMetaClass
    * @hidecontents
    *
    * @abstract
    * Helper macro for for the standard metaclass-registration macros.
    * DO NOT USE.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    * @param init           A function to call in the constructor
    *                       of the class's OSMetaClass.
    */
#define OSDefineMetaClass(className, superclassName)            \
    OSDefineMetaClassWithInit(className, superclassName, )


   /*!
    * @define OSDefineMetaClassAndStructors
    * @hidecontents
    *
    * @abstract
    * Defines an OSMetaClass and associated routines
    * for a concrete Libkern C++ class.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    *
    * @discussion
    * Concrete Libkern C++ classes should "call" this macro
    * at the beginning of their implementation files,
    * before any function implementations for the class.
    */
#define OSDefineMetaClassAndStructors(className, superclassName)    \
    OSDefineMetaClassAndStructorsWithInit(className, superclassName, )


   /*!
    * @define OSDefineMetaClassAndAbstractStructors
    * @hidecontents
    *
    * @abstract
    * Defines an OSMetaClass and associated routines
    * for an abstract Libkern C++ class.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    *
    * @discussion
    * Abstract Libkern C++ classes--those with at least one
    * pure virtual method--should "call" this macro
    * at the beginning of their implementation files,
    * before any function implementations for the class.
    */
#define OSDefineMetaClassAndAbstractStructors(className, superclassName) \
    OSDefineMetaClassAndAbstractStructorsWithInit (className, superclassName, )


   /*!
    * @define OSDefineMetaClassAndFinalStructors
    * @hidecontents
    *
    * @abstract
    * Defines an OSMetaClass and associated routines
    * for a final (non-subclassable) Libkern C++ class.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param superclassName The name of the superclass of the C++ class,
    *                       as a raw token,
    *                       <i>not</i> a string or macro.
    *
    * @discussion
    * Final Libkern C++ classes--those that do not allow
    * subclassing--should "call" this macro at the beginning
    * of their implementation files,
    * before any function implementations for the class.
    * (Final classes in the kernel may actually have subclasses in the kernel,
    * but kexts cannot define any subclasses of a final class.)
    *
    * <b>Note:</b> If the class is exported by a pseudokext (symbol set),
    * the final symbol generated by this macro must be exported
    * for the final-class attribute to be enforced.
    *
    * <b>Warning:</b> Changing a class from "Default" to "Final" will break
    * binary compatibility.
    */
#define OSDefineMetaClassAndFinalStructors(className, superclassName)   \
    OSDefineMetaClassAndFinalStructorsWithInit(className, superclassName, )


    // Dynamic vtable patchup support routines and types
    void reservedCalled(int ind) const;


   /*!
    * @define OSMetaClassDeclareReservedUnused
    * @hidecontents
    *
    * @abstract
    * Reserves vtable space for new virtual functions
    * in a Libkern C++ class.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param index          The numeric index of the vtable slot,
    *                       as a raw constant, beginning from 0.
    *
    * @discussion
    * Libkern C++ classes in kernel extensions that can be used as libraries
    * can provide for backward compatibility by declaring a number
    * of reserved vtable slots
    * that can be replaced with new functions as they are added.
    * Each reserved declaration must be accompanied in the implementation
    * by a corresponding reference to
    * <code>@link OSMetaClassDefineReservedUnused
    *       OSMetaClassDefineReservedUnused@/link</code>.
    *
    * When replacing a reserved slot, change the macro from "Unused"
    * to "Used" to document the fact that the slot used to be reserved,
    * and declare the new function immediately after the "Used" macro
    * to preserve vtable ordering.
    * See
    * <code>@link OSMetaClassDeclareReservedUsed
    *       OSMetaClassDeclareReservedUsed@/link</code>.
    */
#if APPLE_KEXT_VTABLE_PADDING
#define OSMetaClassDeclareReservedUnused(className, index)        \
    private:                                                      \
    virtual void _RESERVED ## className ## index ()
#else
#define OSMetaClassDeclareReservedUnused(className, index)
#endif


   /*!
    * @define OSMetaClassDeclareReservedUsed
    * @hidecontents
    *
    * @abstract
    * Documents use of reserved vtable space for new virtual functions
    * in a Libkern C++ class.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param index          The numeric index of the vtable slot,
    *                       as a raw constant, beginning from 0.
    *
    * @discussion
    * This macro evaluates to nothing, and is used to document reserved
    * vtable slots as they are filled.
    * See
    * <code>@link OSMetaClassDeclareReservedUnused
    *       OSMetaClassDeclareReservedUnused@/link</code>.
    */
#define OSMetaClassDeclareReservedUsed(className, index)


   /*!
    * @define OSMetaClassDefineReservedUnused
    * @hidecontents
    *
    * @abstract
    * Defines a reserved vtable slot for a Libkern C++ class.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param index          The numeric index of the vtable slot,
    *                       as a raw constant, beginning from 0.
    *
    * @discussion
    * Libkern C++ classes in kernel extensions that can be used as libraries
    * can provide for backward compatibility by declaring a number
    * of reserved vtable slots
    * that can be replaced with new functions as they are added.
    * Each reserved defintion accompanies
    * a corresponding declaration created with
    * <code>@link OSMetaClassDeclareReservedUnused
    *       OSMetaClassDeclareReservedUnused@/link</code>.
    *
    * This macro is used in the implementation file
    * to provide a placeholder definition for the reserved vtable slot,
    * as a function that calls <code>panic</code> with an error message.
    *
    * When replacing a reserved slot, change the macro from "Unused"
    * to "Used" to document the fact that the slot used to be reserved,
    * and declare the new function immediately after the "Used" macro
    * to preserve vtable ordering.
    * See
    * <code>@link OSMetaClassDefineReservedUsed
    *       OSMetaClassDefineReservedUsed@/link</code>.
    */
#if APPLE_KEXT_VTABLE_PADDING
#define OSMetaClassDefineReservedUnused(className, index)       \
void className ::_RESERVED ## className ## index ()             \
	{ gMetaClass.reservedCalled(index); }
#else
#define OSMetaClassDefineReservedUnused(className, index)
#endif


   /*!
    * @define OSMetaClassDefineReservedUsed
    * @hidecontents
    *
    * @abstract
    * Reserves vtable space for new virtual functions in a Libkern C++ class.
    *
    * @param className      The name of the C++ class, as a raw token,
    *                       <i>not</i> a string or macro.
    * @param index          The numeric index of the vtable slot,
    *                       as a raw constant, beginning from 0.
    *
    * @discussion
    * This macro evaluates to nothing, and is used to document reserved
    * vtable slots as they are filled.
    * See
    * <code>@link OSMetaClassDefineReservedUnused
    *       OSMetaClassDefineReservedUnused@/link</code>.
    */
#define OSMetaClassDefineReservedUsed(className, index)

    // I/O Kit debug internal routines.
    static void printInstanceCounts();
    static void serializeClassDictionary(OSDictionary * dict);
#ifdef XNU_KERNEL_PRIVATE
#if IOTRACKING
public:
    static void * trackedNew(size_t size);
    static void trackedDelete(void * mem, size_t size);
    void trackedInstance(OSObject * instance) const;
    void trackedFree(OSObject * instance) const;
    void trackedAccumSize(OSObject * instance, size_t size) const;
    struct IOTrackingQueue * getTracking() const;
#endif
#endif

private:
    // Obsolete APIs
    static OSDictionary * getClassDictionary();
    virtual bool serialize(OSSerialize * serializer) const;

    // Virtual Padding functions for MetaClass's
    OSMetaClassDeclareReservedUnused(OSMetaClass, 0);
    OSMetaClassDeclareReservedUnused(OSMetaClass, 1);
    OSMetaClassDeclareReservedUnused(OSMetaClass, 2);
    OSMetaClassDeclareReservedUnused(OSMetaClass, 3);
    OSMetaClassDeclareReservedUnused(OSMetaClass, 4);
    OSMetaClassDeclareReservedUnused(OSMetaClass, 5);
    OSMetaClassDeclareReservedUnused(OSMetaClass, 6);
    OSMetaClassDeclareReservedUnused(OSMetaClass, 7);
};

#endif /* !_LIBKERN_OSMETACLASS_H */
