/*
 *  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 "WIN32_ThreadLocalImpl.h"
#include "WIN32_ThreadImpl.h"

#include <assert.h>

using namespace ZThread;


ThreadLocalImpl::ThreadLocalImpl() throw() {
    
  _key = ::TlsAlloc();
  _valid = (_key != 0xFFFFFFFF);

  assert(_valid);
  ::TlsSetValue(_key, 0x00);

}


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

#if defined(NDEBUG)
  ::TlsFree(_key);
#else
  assert(::TlsFree(_key) != FALSE);
#endif
    
  }

}


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

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

  return ::TlsGetValue(_key);

}


void* ThreadLocalImpl::set(void* newValue) const 
  throw(Synchronization_Exception) {
  
  void* oldValue = get();

  ::TlsSetValue(_key, newValue);
  
  return oldValue;

}


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

  // Try to just fetch the value first. 
  void* value = ::TlsGetValue(_key);

  if(value == 0x00) {

    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);
    ::TlsSetValue(_key, value);

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



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

bool ThreadLocalImpl::cleanedUp = false;

void ThreadLocalImpl::cleanup() {
  cleanedUp = true;
}


#endif

