/*
 * Copyright (c) 2000-2019 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@
 */
/*
 *  Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
 *  HISTORY
 *   1998-10-30  Godfrey van der Linden(gvdl)
 *   Created
 */
#ifndef _LIBKERN_OSOBJECT_H
#define _LIBKERN_OSOBJECT_H

#include <libkern/c++/OSMetaClass.h>
#include <libkern/c++/OSPtr.h>
#include <IOKit/IORPC.h>
#include <DriverKit/OSObject.h>

#if defined(__clang__)
#pragma clang diagnostic ignored "-Woverloaded-virtual"
#endif

class OSSymbol;
class OSString;
class OSObject;

typedef OSObject* OSObjectPtr;


/*!
 * @header
 *
 * @abstract
 * This header declares the OSObject class,
 * which is the concrete root of the Libkern C++ class hierarchy.
 */


/*!
 * @class OSObject
 *
 * @abstract
 * OSObject is the concrete root class
 * of the Libkern and I/O Kit C++ class hierarchy.
 *
 * @discussion
 * OSObject defines the minimal functionality
 * required of Libkern and I/O Kit C++ classes:
 * tie-in to the run-time type information facility,
 * the dynamic allocation/initialization paradigm,
 * and reference counting.
 * While kernel extensions are free to use their own C++ classes internally,
 * any interaction they have with Libkern or the I/O Kit will require
 * classes ultimately derived from OSObject.
 *
 * <b>Run-Time Type Information</b>
 *
 * OSObject is derived from the abstract root class
 * @link //apple_ref/doc/class/OSMetaClassBase OSMetaClassBase@/link,
 * which declares (and defines many of) the primitives
 * on which the run-time type information facility is based.
 * A parallel inheritance hierarchy of metaclass objects
 * provides run-time introspection, including access to class names,
 * inheritance, and safe type-casting.
 * See @link //apple_ref/doc/class/OSMetaClass OSMetaClass@/link
 * for more information.
 *
 * <b>Dynamic Allocation/Initialization</b>
 *
 * The kernel-resident C++ runtime does not support exceptions,
 * so Libkern classes cannot use standard C++ object
 * constructors and destructors,
 * which use exceptions to report errors.
 * To support error-handling during instance creation, then,
 * OSObject separates object allocation from initialization.
 * You can create a new OSObject-derived instance
 * with the <code>new</code> operator,
 * but this does nothing more than allocate memory
 * and initialize the reference count to 1.
 * Following this, you must call a designated initialization function
 * and check its <code>bool</code> return value.
 * If the initialization fails,
 * you must immediately call
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
 * release@/link</code>
 * on the instance and handle the failure in whatever way is appropriate.
 * Many Libkern and I/O Kit classes define static instance-creation functions
 * (beginning with the word "with")
 * to make construction a one-step process for clients.
 *
 * <b>Reference Counting</b>
 *
 * OSObject provides reference counting services using the
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/retain/virtualvoid/()
 * retain@/link</code>,
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
 * release()@/link</code>,
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/(int)
 * release(int freeWhen)@/link</code>
 * and
 *<code> @link
 * //apple_ref/cpp/instm/OSObject/free/virtualvoid/()
 * free@/link</code>
 * functions.
 * The public interface to the reference counting is
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/retain/virtualvoid/()
 * retain@/link</code>,
 * and
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
 * release@/link</code>;
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/(int)
 * release(int freeWhen)@/link</code>
 * is provided
 * for objects that have internal retain cycles.
 *
 * In general, a subclass is expected to only override
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/free/virtualvoid/()
 * free@/link</code>.
 * It may also choose to override
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/(int)
 * release(int freeWhen)@/link</code>
 * if the object has a circular retain count, as noted above.
 *
 * <b>Use Restrictions</b>
 *
 * With very few exceptions in the I/O Kit, all Libkern-based C++
 * classes, functions, and macros are <b>unsafe</b>
 * to use in a primary interrupt context.
 * Consult the I/O Kit documentation related to primary interrupts
 * for more information.
 *
 * <b>Concurrency Protection</b>
 *
 * The basic features of OSObject are thread-safe.
 * Most Libkern subclasses are not, and require locking or other protection
 * if instances are shared between threads.
 * I/O Kit driver objects are either designed for use within thread-safe contexts
 * or designed to inherently be thread-safe.
 * Always check the individual class documentation to see what
 * steps are necessary for concurrent use of instances.
 */
class OSObject : public OSMetaClassBase
{
	OSDeclareAbstractStructorsWithDispatchAndNoOperators(OSObject);

#if IOKITSTATS
	friend class IOStatistics;
#endif

private:
/* Not to be included in headerdoc.
 *
 * @var retainCount Number of references held on this instance.
 */
	mutable int retainCount;

protected:

// xx-review: seems not to be used, should we deprecate?

/*!
 * @function release
 *
 * @abstract
 * Releases a reference to an object,
 * freeing it immediately if the reference count
 * drops below the specified threshold.
 *
 * @param freeWhen If decrementing the reference count makes it
 *                 < <code>freeWhen</code>, the object is immediately freed.
 *
 * @discussion
 * If the receiver has fewer than <code>freeWhen</code> references
 * after its reference count is decremented,
 * it is immediately freed.
 *
 * This version of <code>release</code>
 * can be used to break certain retain cycles in object graphs.
 * In general, however, it should be avoided.
 */
	virtual void release(int freeWhen) const APPLE_KEXT_OVERRIDE;

/*!
 * @function taggedRelease
 *
 * @abstract
 * Releases a tagged reference to an object,
 * freeing it immediately if the reference count
 * drops below the specified threshold.
 *
 * @param tag      Used for tracking collection references.
 * @param freeWhen If decrementing the reference count makes it
 *                 < <code>freeWhen</code>, the object is immediately freed.
 *
 * @discussion
 * Kernel extensions should not use this function.
 * It is for use by OSCollection and subclasses to track
 * inclusion in collections.
 *
 * If the receiver has fewer than <code>freeWhen</code> references
 * after its reference count is decremented,
 * it is immediately freed.
 *
 * This version of <code>release</code>
 * can be used to break certain retain cycles in object graphs.
 * In general, however, it should be avoided.
 */
	virtual void taggedRelease(const void * tag, const int freeWhen) const APPLE_KEXT_OVERRIDE;


/*!
 * @function init
 *
 * @abstract
 * Initializes a newly-allocated object.
 *
 * @result
 * <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Classes derived from OSObject must override the primary init method
 * of their parent.
 * In general most implementations call
 * <code><i>super</i>::init()</code>
 * before doing local initialisation.
 * If the superclass call fails then return <code>false</code> immediately.
 * If the subclass encounters a failure then it should return <code>false</code>.
 */
	virtual bool init();


/*!
 * @function free
 *
 * @abstract
 * Deallocates/releases resources held by the object.
 *
 * @discussion
 * Classes derived from OSObject should override this function
 * to deallocate or release all dynamic resources held by the instance,
 * then call the superclass's implementation.
 *
 * <b>Caution:</b>
 * <ol>
 * <li>You can not assume that you have completed initialization
 *     before <code>free</code> is called,
 *     so be very careful in your implementation.</li>
 * <li>OSObject's implementation performs the C++ <code>delete</code>
 *     of the instance, so be sure that you call the superclass
 *     implementation <i>last</i> in your implementation.</li>
 * <li><code>free</code> must not fail;
 *     all resources must be deallocated or released on completion.</li>
 * </ol>
 */
	virtual void free();


/*!
 * @function operator delete
 *
 * @abstract
 * Frees the memory of the object itself.
 *
 * @param mem   A pointer to the object's memory.
 * @param size  The size of the object's block of memory.
 *
 * @discussion
 * Never use <code>delete</code> on objects derived from OSObject;
 * use
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
 * release@/link</code>
 * instead.
 */
#ifdef XNU_KERNEL_PRIVATE
	static void operator delete(void * mem, size_t size)
	__XNU_INTERNAL(OSObject_operator_delete);
#else
	static void operator delete(void * mem, size_t size);
#endif


// XXX: eventually we can flip this switch
//#ifdef LIBKERN_SMART_POINTERS
#if 0
private:
#else
public:
#endif

/*!
 * @function operator new
 *
 * @abstract
 * Allocates memory for an instance of the class.
 *
 * @param size The number of bytes to allocate
 *
 * @result
 * A pointer to block of memory if available, <code>NULL</code> otherwise.
 */
#ifdef XNU_KERNEL_PRIVATE
	static void * operator new(size_t size)
	__XNU_INTERNAL(OSObject_operator_new);
#else
	static void * operator new(size_t size);
#endif

public:

/*!
 * @function getRetainCount
 *
 * @abstract
 * Returns the reference count of the object.
 *
 * @result
 * The reference count of the object.
 */
	virtual int getRetainCount() const APPLE_KEXT_OVERRIDE;


/*!
 * @function retain
 *
 * @abstract
 * Retains a reference to the object.
 *
 * @discussion
 * This function increments the reference count of the receiver by 1.
 * If you need to maintain a reference to an object
 * outside the context in which you received it,
 * you should always retain it immediately.
 */
	virtual void retain() const APPLE_KEXT_OVERRIDE;


/*!
 * @function release
 *
 * @abstract
 * Releases a reference to the object,
 * freeing it immediately if the reference count drops to zero.
 *
 * @discussion
 * This function decrements the reference count of the receiver by 1.
 * If the reference count drops to zero,
 * the object is immediately freed using
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/free/virtualvoid/()
 * free@/link</code>.
 */
	virtual void release() const APPLE_KEXT_OVERRIDE;


/*!
 * @function taggedRetain
 *
 * @abstract
 * Retains a reference to the object with an optional
 * tag used for reference-tracking.
 *
 * @param tag      Used for tracking collection references.
 *
 * @discussion
 * Kernel extensions should not use this function.
 * It is for use by OSCollection and subclasses to track
 * inclusion in collections.
 *
 * If you need to maintain a reference to an object
 * outside the context in which you received it,
 * you should always retain it immediately.
 */
	virtual void taggedRetain(const void * tag = NULL) const APPLE_KEXT_OVERRIDE;


/*!
 * @function taggedRelease
 *
 * @abstract
 * Releases a tagged reference to an object,
 * freeing it immediately if the reference count
 * drops to zero.
 *
 * @param tag      Used for tracking collection references.
 *
 * @discussion
 * Kernel extensions should not use this function.
 * It is for use by OSCollection and subclasses to track
 * inclusion in collections.
 */
	virtual void taggedRelease(const void * tag = NULL) const APPLE_KEXT_OVERRIDE;
// xx-review: used to say, "Remove a reference on this object with this tag, if an attempt is made to remove a reference that isn't associated with this tag the kernel will panic immediately", but I don't see that in the implementation


/*!
 * @function serialize
 *
 * @abstract
 * Overridden by subclasses to archive the receiver into the provided
 * @link //apple_ref/doc/class/OSSerialize OSSerialize@/link object.
 *
 * @param serializer The OSSerialize object.
 *
 * @result
 * <code>true</code> if serialization succeeds, <code>false</code> if not.
 *
 * @discussion
 * OSObject's implementation writes a string indicating that
 * the class of the object receiving the function call
 * is not serializable.
 * Subclasses that can meaningfully encode themselves
 * in I/O Kit-style property list XML can override this function to do so.
 * See
 * @link //apple_ref/doc/class/OSSerialize OSSerialize@/link
 * for more information.
 */
	virtual bool serialize(OSSerialize * serializer) const APPLE_KEXT_OVERRIDE;

#ifdef XNU_KERNEL_PRIVATE
#if IOTRACKING
	void trackingAccumSize(size_t size);
#endif

	bool taggedTryRetain(const void *tag) const;

	bool iterateObjects(void * refcon, bool (*callback)(void * refcon, OSObject * object));
#ifdef __BLOCKS__
	bool iterateObjects(bool (^block)(OSObject * object));
#endif /* __BLOCKS__ */

#endif /* XNU_KERNEL_PRIVATE */

// Unused Padding
	OSMetaClassDeclareReservedUnused(OSObject, 0);
	OSMetaClassDeclareReservedUnused(OSObject, 1);
	OSMetaClassDeclareReservedUnused(OSObject, 2);
	OSMetaClassDeclareReservedUnused(OSObject, 3);
	OSMetaClassDeclareReservedUnused(OSObject, 4);
	OSMetaClassDeclareReservedUnused(OSObject, 5);
	OSMetaClassDeclareReservedUnused(OSObject, 6);
	OSMetaClassDeclareReservedUnused(OSObject, 7);
	OSMetaClassDeclareReservedUnused(OSObject, 8);
	OSMetaClassDeclareReservedUnused(OSObject, 9);
	OSMetaClassDeclareReservedUnused(OSObject, 10);
	OSMetaClassDeclareReservedUnused(OSObject, 11);
	OSMetaClassDeclareReservedUnused(OSObject, 12);
	OSMetaClassDeclareReservedUnused(OSObject, 13);
	OSMetaClassDeclareReservedUnused(OSObject, 14);
	OSMetaClassDeclareReservedUnused(OSObject, 15);
};

#endif /* !_LIBKERN_OSOBJECT_H */
