258 lines
8.4 KiB
C++
258 lines
8.4 KiB
C++
/*
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
|
*
|
|
* 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. 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_LICENSE_HEADER_END@
|
|
*
|
|
*/
|
|
/*
|
|
File: OSRef.h
|
|
|
|
Contains: Class supports creating unique string IDs to object pointers. A grouping
|
|
of an object and its string ID may be stored in an OSRefTable, and the
|
|
associated object pointer can be looked up by string ID.
|
|
|
|
Refs can only be removed from the table when no one is using the ref,
|
|
therefore allowing clients to arbitrate access to objects in a preemptive,
|
|
multithreaded environment.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifndef _OSREF_H_
|
|
#define _OSREF_H_
|
|
|
|
|
|
#include "StrPtrLen.h"
|
|
#include "OSHashTable.h"
|
|
#include "OSCond.h"
|
|
|
|
class OSRefKey;
|
|
|
|
class OSRefTableUtils
|
|
{
|
|
private:
|
|
|
|
static UInt32 HashString(StrPtrLen* inString);
|
|
|
|
friend class OSRef;
|
|
friend class OSRefKey;
|
|
};
|
|
|
|
class OSRef
|
|
{
|
|
public:
|
|
|
|
OSRef() : fObjectP(NULL), fRefCount(0), fNextHashEntry(NULL)
|
|
{
|
|
#if DEBUG
|
|
fInATable = false;
|
|
fSwapCalled = false;
|
|
#endif
|
|
}
|
|
OSRef(const StrPtrLen &inString, void* inObjectP)
|
|
: fRefCount(0), fNextHashEntry(NULL)
|
|
{ Set(inString, inObjectP); }
|
|
~OSRef() {}
|
|
|
|
void Set(const StrPtrLen& inString, void* inObjectP)
|
|
{
|
|
#if DEBUG
|
|
fInATable = false;
|
|
fSwapCalled = false;
|
|
#endif
|
|
fString = inString; fObjectP = inObjectP;
|
|
fHashValue = OSRefTableUtils::HashString(&fString);
|
|
}
|
|
|
|
#if DEBUG
|
|
Bool16 IsInTable() { return fInATable; }
|
|
#endif
|
|
void** GetObjectPtr() { return &fObjectP; }
|
|
void* GetObject() { return fObjectP; }
|
|
UInt32 GetRefCount() { return fRefCount; }
|
|
StrPtrLen *GetString() { return &fString; }
|
|
private:
|
|
|
|
//value
|
|
void* fObjectP;
|
|
//key
|
|
StrPtrLen fString;
|
|
|
|
//refcounting
|
|
UInt32 fRefCount;
|
|
#if DEBUG
|
|
Bool16 fInATable;
|
|
Bool16 fSwapCalled;
|
|
#endif
|
|
OSCond fCond;//to block threads waiting for this ref.
|
|
|
|
UInt32 fHashValue;
|
|
OSRef* fNextHashEntry;
|
|
|
|
friend class OSRefKey;
|
|
friend class OSHashTable<OSRef, OSRefKey>;
|
|
friend class OSHashTableIter<OSRef, OSRefKey>;
|
|
friend class OSRefTable;
|
|
|
|
};
|
|
|
|
|
|
class OSRefKey
|
|
{
|
|
public:
|
|
|
|
//CONSTRUCTOR / DESTRUCTOR:
|
|
OSRefKey(StrPtrLen* inStringP)
|
|
: fStringP(inStringP)
|
|
{ fHashValue = OSRefTableUtils::HashString(inStringP); }
|
|
|
|
~OSRefKey() {}
|
|
|
|
|
|
//ACCESSORS:
|
|
StrPtrLen* GetString() { return fStringP; }
|
|
|
|
|
|
private:
|
|
|
|
//PRIVATE ACCESSORS:
|
|
SInt32 GetHashKey() { return fHashValue; }
|
|
|
|
//these functions are only used by the hash table itself. This constructor
|
|
//will break the "Set" functions.
|
|
OSRefKey(OSRef *elem) : fStringP(&elem->fString),
|
|
fHashValue(elem->fHashValue) {}
|
|
|
|
friend int operator ==(const OSRefKey &key1, const OSRefKey &key2)
|
|
{
|
|
if (key1.fStringP->Equal(*key2.fStringP))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//data:
|
|
StrPtrLen *fStringP;
|
|
UInt32 fHashValue;
|
|
|
|
friend class OSHashTable<OSRef, OSRefKey>;
|
|
};
|
|
|
|
typedef OSHashTable<OSRef, OSRefKey> OSRefHashTable;
|
|
typedef OSHashTableIter<OSRef, OSRefKey> OSRefHashTableIter;
|
|
|
|
class OSRefTable
|
|
{
|
|
public:
|
|
|
|
enum
|
|
{
|
|
kDefaultTableSize = 1193 //UInt32
|
|
};
|
|
|
|
//tableSize doesn't indicate the max number of Refs that can be added
|
|
//(it's unlimited), but is rather just how big to make the hash table
|
|
OSRefTable(UInt32 tableSize = kDefaultTableSize) : fTable(tableSize), fMutex() {}
|
|
~OSRefTable() {}
|
|
|
|
//Allows access to the mutex in case you need to lock the table down
|
|
//between operations
|
|
OSMutex* GetMutex() { return &fMutex; }
|
|
OSRefHashTable* GetHashTable() { return &fTable; }
|
|
|
|
//Registers a Ref in the table. Once the Ref is in, clients may resolve
|
|
//the ref by using its string ID. You must setup the Ref before passing it
|
|
//in here, ie., setup the string and object pointers
|
|
//This function will succeed unless the string identifier is not unique,
|
|
//in which case it will return QTSS_DupName
|
|
//This function is atomic wrt this ref table.
|
|
OS_Error Register(OSRef* ref);
|
|
|
|
// RegisterOrResolve
|
|
// If the ID of the input ref is unique, this function is equivalent to
|
|
// Register, and returns NULL.
|
|
// If there is a duplicate ID already in the map, this funcion
|
|
// leave it, resolves it, and returns it.
|
|
OSRef* RegisterOrResolve(OSRef* inRef);
|
|
|
|
//This function may block. You can only remove a Ref from the table
|
|
//when the refCount drops to the level specified. If several threads have
|
|
//the ref currently, the calling thread will wait until the other threads
|
|
//stop using the ref (by calling Release, below)
|
|
//This function is atomic wrt this ref table.
|
|
void UnRegister(OSRef* ref, UInt32 refCount = 0);
|
|
|
|
// Same as UnRegister, but guarenteed not to block. Will return
|
|
// true if ref was sucessfully unregistered, false otherwise
|
|
Bool16 TryUnRegister(OSRef* ref, UInt32 refCount = 0);
|
|
|
|
//Resolve. This function uses the provided key string to identify and grab
|
|
//the Ref keyed by that string. Once the Ref is resolved, it is safe to use
|
|
//(it cannot be removed from the Ref table) until you call Release. Because
|
|
//of that, you MUST call release in a timely manner, and be aware of potential
|
|
//deadlocks because you now own a resource being contended over.
|
|
//This function is atomic wrt this ref table.
|
|
OSRef* Resolve(StrPtrLen* inString);
|
|
|
|
//Release. Release a Ref, and drops its refCount. After calling this, the
|
|
//Ref is no longer safe to use, as it may be removed from the ref table.
|
|
void Release(OSRef* inRef);
|
|
|
|
// Swap. This atomically removes any existing Ref in the table with the new
|
|
// ref's ID, and replaces it with this new Ref. If there is no matching Ref
|
|
// already in the table, this function does nothing.
|
|
//
|
|
// Be aware that this creates a situation where clients may have a Ref resolved
|
|
// that is no longer in the table. The old Ref must STILL be UnRegistered normally.
|
|
// Once Swap completes sucessfully, clients that call resolve on the ID will get
|
|
// the new OSRef object.
|
|
void Swap(OSRef* newRef);
|
|
|
|
UInt32 GetNumRefsInTable() { UInt64 result = fTable.GetNumEntries(); Assert(result < kUInt32_Max); return (UInt32) result; }
|
|
|
|
private:
|
|
|
|
|
|
//all this object needs to do its job is an atomic hashtable
|
|
OSRefHashTable fTable;
|
|
OSMutex fMutex;
|
|
};
|
|
|
|
|
|
class OSRefReleaser
|
|
{
|
|
public:
|
|
|
|
OSRefReleaser(OSRefTable* inTable, OSRef* inRef) : fOSRefTable(inTable), fOSRef(inRef) {}
|
|
~OSRefReleaser() { fOSRefTable->Release(fOSRef); }
|
|
|
|
OSRef* GetRef() { return fOSRef; }
|
|
|
|
private:
|
|
|
|
OSRefTable* fOSRefTable;
|
|
OSRef* fOSRef;
|
|
};
|
|
|
|
|
|
|
|
#endif //_OSREF_H_
|