/* Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #pragma once #if defined(LEAN_MULTI_THREAD) #if !defined(LEAN_USE_BOOST) // MULTI THREADING SUPPORT BASED ON THE STANDARD LIBRARY #include #include #include #include #include #define LEAN_THREAD_LOCAL thread_local namespace lean { inline void set_thread_stack_size(size_t ) {} using std::thread; using std::mutex; using std::recursive_mutex; using std::atomic; using std::atomic_bool; using std::atomic_ushort; using std::atomic_uint; using std::atomic_uchar; using std::condition_variable; using std::lock_guard; using std::unique_lock; using std::atomic_load; using std::atomic_fetch_add_explicit; using std::atomic_fetch_sub_explicit; using std::memory_order_relaxed; using std::memory_order_release; using std::memory_order_acquire; using std::memory_order_seq_cst; using std::atomic_thread_fence; namespace chrono = std::chrono; namespace this_thread = std::this_thread; } #else // MULTI THREADING SUPPORT BASED ON THE BOOST LIBRARY #include #include #define LEAN_THREAD_LOCAL thread_local namespace lean { void set_thread_stack_size(size_t ); boost::thread::attributes const & get_thread_attributes(); using boost::thread; using boost::mutex; using boost::recursive_mutex; using boost::atomic; using boost::memory_order_relaxed; using boost::memory_order_acquire; using boost::memory_order_release; using boost::memory_order_seq_cst; using boost::condition_variable; using boost::unique_lock; using boost::lock_guard; using boost::atomic_thread_fence; namespace chrono = boost::chrono; namespace this_thread = boost::this_thread; typedef atomic atomic_bool; typedef atomic atomic_ushort; typedef atomic atomic_uchar; typedef atomic atomic_uint; template T atomic_load(atomic const * a) { return a->load(); } template T atomic_fetch_add_explicit(atomic * a, T v, boost::memory_order mo) { return a->fetch_add(v, mo); } template T atomic_fetch_sub_explicit(atomic * a, T v, boost::memory_order mo) { return a->fetch_sub(v, mo); } } #endif #else // NO MULTI THREADING SUPPORT #include #include #define LEAN_THREAD_LOCAL namespace lean { inline void set_thread_stack_size(size_t ) {} namespace chrono { typedef unsigned milliseconds; } constexpr int memory_order_relaxed = 0; constexpr int memory_order_release = 0; constexpr int memory_order_acquire = 0; constexpr int memory_order_seq_cst = 0; inline void atomic_thread_fence(int ) {} template class atomic { T m_value; public: atomic(T const & v = T()):m_value(v) {} atomic(T && v):m_value(std::forward(v)) {} atomic(atomic const & v):m_value(v.m_value) {} atomic(atomic && v):m_value(std::forward(v.m_value)) {} atomic & operator=(T const & v) { m_value = v; return *this; } atomic & operator=(T && v) { m_value = std::forward(v); return *this; } atomic & operator=(atomic const & v) { m_value = v.m_value; return *this; } atomic & operator=(atomic && v) { m_value = std::forward(v.m_value); return *this; } operator T() const { return m_value; } void store(T const & v) { m_value = v; } T load() const { return m_value; } atomic & operator|=(T const & v) { m_value |= v; return *this; } atomic & operator+=(T const & v) { m_value += v; return *this; } atomic & operator-=(T const & v) { m_value -= v; return *this; } atomic & operator++() { ++m_value; return *this; } atomic operator++(int ) { atomic tmp(*this); ++m_value; return tmp; } atomic & operator--() { --m_value; return *this; } atomic operator--(int ) { atomic tmp(*this); --m_value; return tmp; } friend T atomic_load(atomic const * a) { return a->m_value; } friend T atomic_fetch_add_explicit(atomic * a, T const & v, int ) { T r(a->m_value); a->m_value += v; return r; } friend T atomic_fetch_sub_explicit(atomic * a, T const & v, int ) { T r(a->m_value); a->m_value -= v; return r; } }; typedef atomic atomic_ushort; typedef atomic atomic_uchar; typedef atomic atomic_bool; typedef atomic atomic_uint; class thread { public: thread() {} template thread(Function && fun, Args &&... args) { fun(std::forward(args)...); } typedef unsigned id; bool joinable() const { return true; } void join() {} }; class this_thread { public: static void sleep_for(chrono::milliseconds const &) {} static thread::id get_id() { return 0; } static void yield() {} }; class mutex { public: void lock() {} void unlock() {} }; class recursive_mutex { public: void lock() {} void unlock() {} }; class condition_variable { public: template void wait(Lock const &) {} template void wait_for(Lock const &, chrono::milliseconds const &) {} void notify_all() {} void notify_one() {} }; template class lock_guard { public: lock_guard(T const &) {} ~lock_guard() {} }; template class unique_lock { public: unique_lock(T const &) {} ~unique_lock() {} }; } #endif #ifdef MSVC #define LEAN_THREAD_PTR(T, V) static __declspec(thread) T * V = nullptr #define LEAN_THREAD_VALUE(T, V, VAL) static __declspec(thread) T V = VAL #else #define LEAN_THREAD_PTR(T, V) static __thread T * V = nullptr #define LEAN_THREAD_VALUE(T, V, VAL) static __thread T V = VAL #endif #define MK_THREAD_LOCAL_GET(T, GETTER_NAME, DEF_VALUE) \ LEAN_THREAD_PTR(T, GETTER_NAME ## _tlocal); \ static void finalize_ ## GETTER_NAME() { \ if (GETTER_NAME ## _tlocal) { \ delete GETTER_NAME ## _tlocal; \ GETTER_NAME ## _tlocal = nullptr; \ } \ } \ static T & GETTER_NAME() { \ if (!GETTER_NAME ## _tlocal) { \ GETTER_NAME ## _tlocal = new T(DEF_VALUE); \ register_thread_finalizer(finalize_ ## GETTER_NAME); \ } \ return *(GETTER_NAME ## _tlocal); \ } #define MK_THREAD_LOCAL_GET_DEF(T, GETTER_NAME) \ LEAN_THREAD_PTR(T, GETTER_NAME ## _tlocal); \ static void finalize_ ## GETTER_NAME() { \ if (GETTER_NAME ## _tlocal) { \ delete GETTER_NAME ## _tlocal; \ GETTER_NAME ## _tlocal = nullptr; \ } \ } \ static T & GETTER_NAME() { \ if (!GETTER_NAME ## _tlocal) { \ GETTER_NAME ## _tlocal = new T(); \ register_thread_finalizer(finalize_ ## GETTER_NAME); \ } \ return *(GETTER_NAME ## _tlocal); \ } namespace lean { void initialize_thread(); void finalize_thread(); typedef void (*thread_finalizer)(); void register_post_thread_finalizer(thread_finalizer fn); void register_thread_finalizer(thread_finalizer fn); void run_post_thread_finalizers(); void run_thread_finalizers(); }