2
0
mirror of https://github.com/boostorg/log.git synced 2026-02-03 09:12:19 +00:00
Files
log/src/thread_specific.cpp

293 lines
7.3 KiB
C++

/*
* Copyright Andrey Semashev 2007 - 2015.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
/*!
* \file thread_specific.cpp
* \author Andrey Semashev
* \date 01.03.2008
*
* \brief This header is the Boost.Log library implementation, see the library documentation
* at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
*/
#include <boost/log/detail/config.hpp>
#include <string>
#include <stdexcept>
#include <boost/log/exceptions.hpp>
#include <boost/log/detail/thread_specific.hpp>
#if !defined(BOOST_LOG_NO_THREADS)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <windows.h>
#include <boost/system/error_code.hpp>
#include <boost/log/detail/header.hpp>
namespace boost {
BOOST_LOG_OPEN_NAMESPACE
namespace aux {
thread_specific_base::thread_specific_base()
{
m_Key = TlsAlloc();
if (BOOST_UNLIKELY(m_Key == TLS_OUT_OF_INDEXES))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (boost::system::errc::not_enough_memory));
}
}
thread_specific_base::~thread_specific_base()
{
TlsFree(m_Key);
}
void* thread_specific_base::get_content() const
{
return TlsGetValue(m_Key);
}
void thread_specific_base::set_content(void* value) const
{
TlsSetValue(m_Key, value);
}
} // namespace aux
BOOST_LOG_CLOSE_NAMESPACE // namespace log
} // namespace boost
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <cstddef>
#include <cstring>
#include <pthread.h>
#include <boost/cstdint.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/log/detail/header.hpp>
namespace boost {
BOOST_LOG_OPEN_NAMESPACE
namespace aux {
BOOST_LOG_ANONYMOUS_NAMESPACE {
//! Some portability magic to detect how to store the TLS key
template< typename KeyT, bool IsStoreableV = sizeof(KeyT) <= sizeof(void*), bool IsIntegralV = boost::is_integral< KeyT >::value >
struct pthread_key_traits
{
typedef KeyT pthread_key_type;
static void allocate(void*& stg)
{
pthread_key_type* pkey = new pthread_key_type();
const int res = pthread_key_create(pkey, NULL);
if (BOOST_UNLIKELY(res != 0))
{
delete pkey;
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
}
stg = pkey;
}
static void deallocate(void* stg)
{
pthread_key_type* pkey = static_cast< pthread_key_type* >(stg);
pthread_key_delete(*pkey);
delete pkey;
}
static void set_value(void* stg, void* value)
{
const int res = pthread_setspecific(*static_cast< pthread_key_type* >(stg), value);
if (BOOST_UNLIKELY(res != 0))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
}
}
static void* get_value(void* stg)
{
return pthread_getspecific(*static_cast< pthread_key_type* >(stg));
}
};
template< typename KeyT >
struct pthread_key_traits< KeyT, true, true >
{
typedef KeyT pthread_key_type;
#if defined(BOOST_HAS_INTPTR_T)
typedef typename mpl::if_c<
boost::is_signed< pthread_key_type >::value,
intptr_t,
uintptr_t
>::type intptr_type;
#else
typedef typename mpl::if_c<
boost::is_signed< pthread_key_type >::value,
std::ptrdiff_t,
std::size_t
>::type intptr_type;
#endif
static void allocate(void*& stg)
{
pthread_key_type key;
const int res = pthread_key_create(&key, NULL);
if (BOOST_UNLIKELY(res != 0))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
}
stg = (void*)(intptr_type)key;
}
static void deallocate(void* stg)
{
pthread_key_delete((pthread_key_type)(intptr_type)stg);
}
static void set_value(void* stg, void* value)
{
const int res = pthread_setspecific((pthread_key_type)(intptr_type)stg, value);
if (BOOST_UNLIKELY(res != 0))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
}
}
static void* get_value(void* stg)
{
return pthread_getspecific((pthread_key_type)(intptr_type)stg);
}
};
template< typename KeyT >
struct pthread_key_traits< KeyT, true, false >
{
typedef KeyT pthread_key_type;
static void allocate(void*& stg)
{
pthread_key_type key;
const int res = pthread_key_create(&key, NULL);
if (BOOST_UNLIKELY(res != 0))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
}
std::memset(&stg, 0, sizeof(stg));
std::memcpy(&stg, &key, sizeof(pthread_key_type));
}
static void deallocate(void* stg)
{
pthread_key_type key;
std::memcpy(&key, &stg, sizeof(pthread_key_type));
pthread_key_delete(key);
}
static void set_value(void* stg, void* value)
{
pthread_key_type key;
std::memcpy(&key, &stg, sizeof(pthread_key_type));
const int res = pthread_setspecific(key, value);
if (BOOST_UNLIKELY(res != 0))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
}
}
static void* get_value(void* stg)
{
pthread_key_type key;
std::memcpy(&key, &stg, sizeof(pthread_key_type));
return pthread_getspecific(key);
}
};
template< typename KeyT >
struct pthread_key_traits< KeyT*, true, false >
{
typedef KeyT* pthread_key_type;
static void allocate(void*& stg)
{
pthread_key_type key = NULL;
const int res = pthread_key_create(&key, NULL);
if (BOOST_UNLIKELY(res != 0))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
}
stg = static_cast< void* >(key);
}
static void deallocate(void* stg)
{
pthread_key_delete(static_cast< pthread_key_type >(stg));
}
static void set_value(void* stg, void* value)
{
const int res = pthread_setspecific(static_cast< pthread_key_type >(stg), value);
if (BOOST_UNLIKELY(res != 0))
{
BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
}
}
static void* get_value(void* stg)
{
return pthread_getspecific(static_cast< pthread_key_type >(stg));
}
};
} // namespace
thread_specific_base::thread_specific_base()
{
typedef pthread_key_traits< pthread_key_t > traits_t;
traits_t::allocate(m_Key);
}
thread_specific_base::~thread_specific_base()
{
typedef pthread_key_traits< pthread_key_t > traits_t;
traits_t::deallocate(m_Key);
}
void* thread_specific_base::get_content() const
{
typedef pthread_key_traits< pthread_key_t > traits_t;
return traits_t::get_value(m_Key);
}
void thread_specific_base::set_content(void* value) const
{
typedef pthread_key_traits< pthread_key_t > traits_t;
traits_t::set_value(m_Key, value);
}
} // namespace aux
BOOST_LOG_CLOSE_NAMESPACE // namespace log
} // namespace boost
#else
#error Boost.Log: unsupported threading API
#endif
#include <boost/log/detail/footer.hpp>
#endif // !defined(BOOST_LOG_NO_THREADS)