/* * * @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.cpp Contains: Implementation of OSRef class. */ #include "OSRef.h" #include UInt32 OSRefTableUtils::HashString(StrPtrLen* inString) { Assert(inString != NULL); Assert(inString->Ptr != NULL); Assert(inString->Len > 0); if (inString == NULL || inString->Len == 0 || inString->Ptr == NULL) return 0; //make sure to convert to unsigned here, as there may be binary //data in this string UInt8* theData = (UInt8*)inString->Ptr; //divide by 4 and take the characters at quarter points in the string, //use those as the basis for the hash value UInt32 quarterLen = inString->Len >> 2; return (inString->Len * (theData[0] + theData[quarterLen] + theData[quarterLen * 2] + theData[quarterLen * 3] + theData[inString->Len - 1])); } OS_Error OSRefTable::Register(OSRef* inRef) { Assert(inRef != NULL); if (inRef == NULL) return EPERM; #if DEBUG Assert(!inRef->fInATable); #endif Assert(inRef->fRefCount == 0); Assert(inRef->fString.Ptr != NULL); Assert(inRef->fString.Len != 0); OSMutexLocker locker(&fMutex); if (inRef->fString.Ptr == NULL || inRef->fString.Len == 0) { //printf("OSRefTable::Register inRef is invalid \n"); return EPERM; } // Check for a duplicate. In this function, if there is a duplicate, // return an error, don't resolve the duplicate OSRefKey key(&inRef->fString); OSRef* duplicateRef = fTable.Map(&key); if (duplicateRef != NULL) return EPERM; // There is no duplicate, so add this ref into the table #if DEBUG inRef->fInATable = true; #endif fTable.Add(inRef); return OS_NoErr; } OSRef* OSRefTable::RegisterOrResolve(OSRef* inRef) { Assert(inRef != NULL); #if DEBUG Assert(!inRef->fInATable); #endif Assert(inRef->fRefCount == 0); OSMutexLocker locker(&fMutex); // Check for a duplicate. If there is one, resolve it and return it to the caller OSRef* duplicateRef = this->Resolve(&inRef->fString); if (duplicateRef != NULL) return duplicateRef; // There is no duplicate, so add this ref into the table #if DEBUG inRef->fInATable = true; #endif fTable.Add(inRef); return NULL; } void OSRefTable::UnRegister(OSRef* ref, UInt32 refCount) { Assert(ref != NULL); OSMutexLocker locker(&fMutex); //make sure that no one else is using the object while (ref->fRefCount > refCount) ref->fCond.Wait(&fMutex); #if DEBUG OSRefKey key(&ref->fString); if (ref->fInATable) Assert(fTable.Map(&key) != NULL); ref->fInATable = false; #endif //ok, we now definitely have no one else using this object, so //remove it from the table fTable.Remove(ref); } Bool16 OSRefTable::TryUnRegister(OSRef* ref, UInt32 refCount) { OSMutexLocker locker(&fMutex); if (ref->fRefCount > refCount) return false; // At this point, this is guarenteed not to block, because // we've already checked that the refCount is low. this->UnRegister(ref, refCount); return true; } OSRef* OSRefTable::Resolve(StrPtrLen* inUniqueID) { Assert(inUniqueID != NULL); OSRefKey key(inUniqueID); //this must be done atomically wrt the table OSMutexLocker locker(&fMutex); OSRef* ref = fTable.Map(&key); if (ref != NULL) { ref->fRefCount++; Assert(ref->fRefCount > 0); } return ref; } void OSRefTable::Release(OSRef* ref) { Assert(ref != NULL); OSMutexLocker locker(&fMutex); ref->fRefCount--; // fRefCount is a UInt32 and QTSS should never run into // a ref greater than 16 * 64K, so this assert just checks to // be sure that we have not decremented the ref less than zero. Assert( ref->fRefCount < 1048576L ); //make sure to wakeup anyone who may be waiting for this resource to be released ref->fCond.Signal(); } void OSRefTable::Swap(OSRef* newRef) { Assert(newRef != NULL); OSMutexLocker locker(&fMutex); OSRefKey key(&newRef->fString); OSRef* oldRef = fTable.Map(&key); if (oldRef != NULL) { fTable.Remove(oldRef); fTable.Add(newRef); #if DEBUG newRef->fInATable = true; oldRef->fInATable = false; oldRef->fSwapCalled = true; #endif } else Assert(0); }