/*
 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
 * 
 * The contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License. Please obtain
 * a copy of the License at http://www.apple.com/publicsource and read it before
 * using this file.
 * 
 * This 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.
 */


//
// handleobject - give an object a process-global unique handle
//
#include <Security/handleobject.h>


//
// Static members of HandleObject
//
ModuleNexus<HandleObject::State> HandleObject::state;


//
// Bring the State constructor out of line
//
HandleObject::State::State()
{ }


//
// HandleObject destructor (virtual)
//
HandleObject::~HandleObject()
{
	State &st = state();
	StLock<Mutex> _(st);
	st.erase(this);
}


//
// Assign a HandleObject's (new) Handle.
//
void HandleObject::State::make(HandleObject *obj)
{
    StLock<Mutex> _(*this);
	for (;;) {
		Handle handle = reinterpret_cast<uint32>(obj) ^ (++sequence << 19);
		if (handleMap[handle] == NULL) {
			debug("handleobj", "create 0x%lx for %p", handle, obj);
			obj->setHandle(handle);
			handleMap[handle] = obj;
			return;
		}
	}
}


//
// Clean up a HandleObject that dies.
// Note that an object MAY clear its handle before (in which case we do nothing).
// In particular, killHandle will do this.
//
void HandleObject::State::erase(HandleObject *obj)
{
    if (obj->validHandle())
        handleMap.erase(obj->handle());
}

void HandleObject::State::erase(HandleMap::iterator &it)
{
    if (it->second->validHandle())
        handleMap.erase(it);
}


//
// Observing proper map locking, locate a handle in the global handle map
// and return a pointer to its object. Throw CssmError(error) if it cannot
// be found, or it is corrupt.
//
HandleObject *HandleObject::State::find(CSSM_HANDLE h, CSSM_RETURN error)
{
	StLock<Mutex> _(*this);
	HandleMap::const_iterator it = handleMap.find(h);
	if (it == handleMap.end())
		CssmError::throwMe(error);
	HandleObject *obj = it->second;
	if (obj == NULL || obj->handle() != h)
		CssmError::throwMe(error);
	return obj;
}


//
// Look up the handle given in the global handle map.
// If not found, or if the object is corrupt, throw an exception.
// Otherwise, hold the State lock and return an iterator to the map entry.
// Caller must release the State lock in a timely manner.
//
HandleObject::HandleMap::iterator HandleObject::State::locate(CSSM_HANDLE h, CSSM_RETURN error)
{
	StLock<Mutex> locker(*this);
	HandleMap::iterator it = handleMap.find(h);
	if (it == handleMap.end())
		CssmError::throwMe(error);
	HandleObject *obj = it->second;
	if (obj == NULL || obj->handle() != h)
		CssmError::throwMe(error);
	locker.release();
	return it;
}


//
// The default locking virtual methods do nothing and succeed.
//
void HandleObject::lock() { }

bool HandleObject::tryLock() { return true; }
