/* 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 #include #include #include #ifndef LEAN_STACK_BUFFER_SPACE #define LEAN_STACK_BUFFER_SPACE 128*1024 // 128 Kb #endif namespace lean { namespace chrono = std::chrono; }; #if defined(LEAN_MULTI_THREAD) #include #include #include #include #define LEAN_THREAD_LOCAL thread_local namespace lean { 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 this_thread = std::this_thread; inline unsigned hardware_concurrency() { return std::thread::hardware_concurrency(); } /** Simple thread class that allows us to set the thread stack size. We implement it using pthreads on OSX/Linux and WinThreads on Windows. */ class lthread { static size_t m_thread_stack_size; struct imp; std::unique_ptr m_imp; public: lthread(std::function const & p); ~lthread(); void join(); static void set_thread_stack_size(size_t sz); static size_t get_thread_stack_size(); }; } #else // NO MULTI THREADING SUPPORT #include #include #define LEAN_THREAD_LOCAL namespace lean { 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; } T exchange(T desired) { T old = m_value; m_value = desired; return old; } bool compare_exchange_strong(T & expected, T desired) { if (m_value == expected) { m_value = desired; return true; } else { expected = m_value; return false; } } }; 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 lthread { public: lthread(std::function const & p) { p(); } ~lthread(); void join() {} static void set_thread_stack_size(size_t) {} static size_t get_thread_stack_size() { return 0; } }; 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() {} void lock() {} void unlock() {} }; inline unsigned hardware_concurrency() { return 1; } } #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(void * p) { \ delete reinterpret_cast(p); \ 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, GETTER_NAME ## _tlocal); \ } \ 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(void * p) { \ delete reinterpret_cast(p); \ GETTER_NAME ## _tlocal = nullptr; \ } \ static T & GETTER_NAME() { \ if (!GETTER_NAME ## _tlocal) { \ GETTER_NAME ## _tlocal = new T(); \ register_thread_finalizer(finalize_ ## GETTER_NAME, GETTER_NAME ## _tlocal); \ } \ return *(GETTER_NAME ## _tlocal); \ } namespace lean { void initialize_thread(); void finalize_thread(); typedef void (*thread_finalizer)(void *); // NOLINT void register_post_thread_finalizer(thread_finalizer fn, void * p); void register_thread_finalizer(thread_finalizer fn, void * p); void run_thread_finalizers(); void run_post_thread_finalizers(); void delete_thread_finalizer_manager(); bool in_thread_finalization(); }