1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25/* 26 Based on code donated by Perry Kiehtreiber 27 */ 28#ifndef _SECURITY_REFCOUNT_H_ 29#define _SECURITY_REFCOUNT_H_ 30 31#include <security_utilities/threading.h> 32#include <libkern/OSAtomic.h> 33 34namespace Security { 35 36 37// 38// RefCount/RefPointer - a simple reference counting facility. 39// 40// To make an object reference-counted, inherit from RefCount. To track refcounted 41// objects, use RefPointer<TheType>, where TheType must inherit from RefCount. 42// 43// RefCount is thread safe - any number of threads can hold and manipulate references 44// in parallel. It does however NOT protect the contents of your object - just the 45// reference count itself. If you need to share your object contents, you must provide 46// appropriate locking yourself. 47// 48// There is no (thread safe) way to determine whether you are the only thread holding 49// a pointer to a particular RefCount object. Thus there is no (thread safe) 50// way to "demand copy" a RefCount subclass. Trust me; it's been tried. Don't. 51// 52 53#if !defined(DEBUG_REFCOUNTS) 54# define DEBUG_REFCOUNTS 1 55#endif 56 57#if DEBUG_REFCOUNTS 58# define RCDEBUG(_kind, _args...) SECURITY_DEBUG_REFCOUNT_##_kind((void *)this, ##_args) 59#else 60# define RCDEBUG(kind) /* nothing */ 61#endif 62 63 64// 65// Base class for reference counted objects 66// 67class RefCount { 68public: 69 RefCount() : mRefCount(0) { RCDEBUG(CREATE); } 70 71protected: 72 template <class T> friend class RefPointer; 73 74 void ref() const 75 { 76 OSAtomicIncrement32(&mRefCount); 77 RCDEBUG(UP, mRefCount); 78 } 79 80 unsigned int unref() const 81 { 82 RCDEBUG(DOWN, mRefCount - 1); 83 return OSAtomicDecrement32(&mRefCount); 84 } 85 86 // if you call this for anything but debug output, you will go to hell (free handbasket included) 87 unsigned int refCountForDebuggingOnly() const { return mRefCount; } 88 89private: 90 volatile mutable int32_t mRefCount; 91}; 92 93 94// 95// A pointer type supported by reference counts. 96// T must be derived from RefCount. 97// 98template <class T> 99class RefPointer { 100 template <class Sub> friend class RefPointer; // share with other instances 101public: 102 RefPointer() : ptr(0) {} // default to NULL pointer 103 RefPointer(const RefPointer& p) { if (p) p->ref(); ptr = p.ptr; } 104 RefPointer(T *p) { if (p) p->ref(); ptr = p; } 105 106 template <class Sub> 107 RefPointer(const RefPointer<Sub>& p) { if (p) p->ref(); ptr = p.ptr; } 108 109 ~RefPointer() { release(); } 110 111 RefPointer& operator = (const RefPointer& p) { setPointer(p.ptr); return *this; } 112 RefPointer& operator = (T * p) { setPointer(p); return *this; } 113 114 template <class Sub> 115 RefPointer& operator = (const RefPointer<Sub>& p) { setPointer(p.ptr); return *this; } 116 117 // dereference operations 118 T* get () const { _check(); return ptr; } // mimic auto_ptr 119 operator T * () const { _check(); return ptr; } 120 T * operator -> () const { _check(); return ptr; } 121 T & operator * () const { _check(); return *ptr; } 122 123protected: 124 void release_internal() 125 { 126 if (ptr && ptr->unref() == 0) 127 { 128 delete ptr; 129 ptr = NULL; 130 } 131 } 132 133 void release() 134 { 135 StLock<Mutex> mutexLock(mMutex); 136 release_internal(); 137 } 138 139 void setPointer(T *p) 140 { 141 StLock<Mutex> mutexLock(mMutex); 142 if (p) 143 { 144 p->ref(); 145 } 146 147 release_internal(); 148 ptr = p; 149 } 150 151 void _check() const { } 152 153 T *ptr; 154 Mutex mMutex; 155}; 156 157template <class T> 158bool operator <(const RefPointer<T> &r1, const RefPointer<T> &r2) 159{ 160 T *p1 = r1.get(), *p2 = r2.get(); 161 return p1 && p2 ? *p1 < *p2 : p1 < p2; 162} 163 164template <class T> 165bool operator ==(const RefPointer<T> &r1, const RefPointer<T> &r2) 166{ 167 T *p1 = r1.get(), *p2 = r2.get(); 168 return p1 && p2 ? *p1 == *p2 : p1 == p2; 169} 170 171template <class T> 172bool operator !=(const RefPointer<T> &r1, const RefPointer<T> &r2) 173{ 174 T *p1 = r1.get(), *p2 = r2.get(); 175 return p1 && p2 ? *p1 != *p2 : p1 != p2; 176} 177 178} // end namespace Security 179 180#endif // !_SECURITY_REFCOUNT_H_ 181