2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-22 17:52:18 +00:00
Files
thread/src/tss.cpp
Michael Glassford 5f27fb2607 Add newline to end of file.
[SVN r24976]
2004-09-08 15:58:40 +00:00

207 lines
5.0 KiB
C++

// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/detail/config.hpp>
#include <boost/thread/tss.hpp>
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
#include <boost/thread/once.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/exceptions.hpp>
#include <vector>
#include <string>
#include <stdexcept>
#include <cassert>
#if defined(BOOST_HAS_WINTHREADS)
# include <windows.h>
# include <boost/thread/detail/tss_hooks.hpp>
#endif
namespace {
typedef std::vector<void*> tss_slots;
struct tss_data_t
{
boost::mutex mutex;
std::vector<boost::function1<void, void*>*> cleanup_handlers;
#if defined(BOOST_HAS_WINTHREADS)
DWORD native_key;
#elif defined(BOOST_HAS_PTHREADS)
pthread_key_t native_key;
#elif defined(BOOST_HAS_MPTASKS)
TaskStorageIndex native_key;
#endif
};
tss_data_t* tss_data = 0;
boost::once_flag tss_data_once = BOOST_ONCE_INIT;
extern "C" void cleanup_slots(void* p)
{
tss_slots* slots = static_cast<tss_slots*>(p);
for (tss_slots::size_type i = 0; i < slots->size(); ++i)
{
boost::mutex::scoped_lock lock(tss_data->mutex);
(*tss_data->cleanup_handlers[i])((*slots)[i]);
(*slots)[i] = 0;
}
}
void init_tss_data()
{
std::auto_ptr<tss_data_t> temp(new tss_data_t);
#if defined(BOOST_HAS_WINTHREADS)
//Force the cleanup implementation library to be linked in
tss_cleanup_implemented();
//Allocate tls slot
temp->native_key = TlsAlloc();
if (temp->native_key == 0xFFFFFFFF)
return;
#elif defined(BOOST_HAS_PTHREADS)
int res = pthread_key_create(&temp->native_key, &cleanup_slots);
if (res != 0)
return;
#elif defined(BOOST_HAS_MPTASKS)
OSStatus status = MPAllocateTaskStorageIndex(&temp->native_key);
if (status != noErr)
return;
#endif
// Intentional memory "leak"
// This is the only way to ensure the mutex in the global data
// structure is available when cleanup handlers are run, since the
// execution order of cleanup handlers is unspecified on any platform
// with regards to C++ destructor ordering rules.
tss_data = temp.release();
}
#if defined(BOOST_HAS_WINTHREADS)
tss_slots* get_slots(bool alloc);
void __cdecl tss_thread_exit()
{
tss_slots* slots = get_slots(false);
if (slots)
cleanup_slots(slots);
}
#endif
tss_slots* get_slots(bool alloc)
{
tss_slots* slots = 0;
#if defined(BOOST_HAS_WINTHREADS)
slots = static_cast<tss_slots*>(
TlsGetValue(tss_data->native_key));
#elif defined(BOOST_HAS_PTHREADS)
slots = static_cast<tss_slots*>(
pthread_getspecific(tss_data->native_key));
#elif defined(BOOST_HAS_MPTASKS)
slots = static_cast<tss_slots*>(
MPGetTaskStorageValue(tss_data->native_key));
#endif
if (slots == 0 && alloc)
{
std::auto_ptr<tss_slots> temp(new tss_slots);
#if defined(BOOST_HAS_WINTHREADS)
if (at_thread_exit(&tss_thread_exit) == -1)
return 0;
if (!TlsSetValue(tss_data->native_key, temp.get()))
return 0;
#elif defined(BOOST_HAS_PTHREADS)
if (pthread_setspecific(tss_data->native_key, temp.get()) != 0)
return 0;
#elif defined(BOOST_HAS_MPTASKS)
if (MPSetTaskStorageValue(tss_data->native_key, temp.get()) != noErr)
return 0;
#endif
slots = temp.release();
}
return slots;
}
} // namespace
namespace boost {
namespace detail {
void tss::init(boost::function1<void, void*>* pcleanup)
{
boost::call_once(&init_tss_data, tss_data_once);
if (tss_data == 0)
throw thread_resource_error();
boost::mutex::scoped_lock lock(tss_data->mutex);
try
{
tss_data->cleanup_handlers.push_back(pcleanup);
m_slot = tss_data->cleanup_handlers.size() - 1;
}
catch (...)
{
throw thread_resource_error();
}
}
void* tss::get() const
{
tss_slots* slots = get_slots(false);
if (!slots)
return 0;
if (m_slot >= slots->size())
return 0;
return (*slots)[m_slot];
}
void tss::set(void* value)
{
tss_slots* slots = get_slots(true);
if (!slots)
throw boost::thread_resource_error();
if (m_slot >= slots->size())
{
try
{
slots->resize(m_slot + 1);
}
catch (...)
{
throw boost::thread_resource_error();
}
}
(*slots)[m_slot] = value;
}
void tss::cleanup(void* value)
{
boost::mutex::scoped_lock lock(tss_data->mutex);
(*tss_data->cleanup_handlers[m_slot])(value);
}
} // namespace detail
} // namespace boost
#endif //BOOST_THREAD_NO_TSS_CLEANUP