/*
 *  ZThreads, a platform-independant, multithreading and 
 *  synchroniation library
 *
 *  Copyright (C) 2001, 2002 Eric Crahen, See LGPL.TXT for details
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  SUNY @ Buffalo, hereby disclaims all copyright interest in the
 *  ZThreads library written by Eric Crahen
 */

#include "POSIX_ThreadLocalImpl.h"
#include "POSIX_ThreadImpl.h"
#include "ValueHolder.h"

#include <assert.h>

using namespace ZThread;


ThreadLocalImpl::ThreadLocalImpl() throw() {
    
  int err = pthread_key_create(&_key, 0);
  _valid = (err == 0);
  assert(_valid);

  if(_valid)
    pthread_setspecific(_key, 0);

}

// Help debug bad uses of the ThreadLocal classes
#ifndef NDEBUG

bool ThreadLocalImpl::cleanedUp = false;

void ThreadLocalImpl::cleanup() {
  cleanedUp = true;
  ZTDEBUG("Cleanedup ThreadLocals\n");
}


#endif

ThreadLocalImpl::~ThreadLocalImpl() throw() {
  
  if(_valid) {

    int err = pthread_key_delete(_key);

    _valid = (err == 0);
    assert(_valid);
    
  }

#if !defined(NDEBUG)

  if(!cleanedUp) {

    ZTDEBUG("You are using a ThreadLocal object that is not static.\n");
    ZTDEBUG("You should make sure that all ThreadLocals are static.\n");
    
    assert(0);

  }

#endif

}

/**
 *
 */
void* ThreadLocalImpl::get() const 
  throw(Synchronization_Exception) {

  if(!_valid)
    throw Synchronization_Exception("Could not create ThreadLocal");

  return pthread_getspecific(_key);

}

/**
 *
 */
void* ThreadLocalImpl::set(void* value) const 
  throw(Synchronization_Exception) {

  void* oldValue = get();
  pthread_setspecific(_key, value);

  return oldValue;

}

ValueHolder* ThreadLocalImpl::getValueHolder(const AbstractThreadLocal* tls) const
  throw(Synchronization_Exception) {


  // Try to just fetch the value first. 
  void* value = pthread_getspecific(_key);
  if(value == 0) {

    assert(tls != 0);
    
    ThreadImpl* impl = ThreadImpl::current();

    void* initialValue = tls->initialValue();
    bool propogateValue = tls->propogateValue();

    // Create a ValueHolder associated with the current thread on first use
    // and map it to the native TLS.
    value = impl->createValueHolder(tls, initialValue, propogateValue);
    pthread_setspecific(_key, value);

  }

  ValueHolder* holder = static_cast<ValueHolder*>(value);
  return holder;
  
}



