#ifndef EINA_THREAD_HH_ #define EINA_THREAD_HH_ #include #include #include #include #include #include #include #include #include #include #define EFL_EINA_BOOST_MOVABLE_BUT_NOT_COPYABLE(x) #define EFL_EINA_BOOST_RV_REF(x) x const& namespace efl { namespace eina { struct mutex { typedef Eina_Lock* native_handle_type; mutex() { ::eina_lock_new(&_mutex); } ~mutex() { ::eina_lock_free(&_mutex); } void lock() { ::Eina_Lock_Result r = ::eina_lock_take(&_mutex); switch(r) { case EINA_LOCK_SUCCEED: return; case EINA_LOCK_DEADLOCK: throw system_error(error_code(int(eina::errc::resource_deadlock_would_occur) , get_generic_category())); default: throw system_error(get_error_code()); } } bool try_lock() { ::Eina_Lock_Result r = ::eina_lock_take_try(&_mutex); switch(r) { case EINA_LOCK_SUCCEED: return true; case EINA_LOCK_FAIL: return false; case EINA_LOCK_DEADLOCK: throw system_error(error_code(int(eina::errc::resource_deadlock_would_occur) , get_generic_category())); default: throw system_error(get_error_code()); } } void unlock() { ::Eina_Lock_Result r = ::eina_lock_release(&_mutex); switch(r) { case EINA_LOCK_SUCCEED: return; case EINA_LOCK_DEADLOCK: throw system_error(error_code(int(eina::errc::resource_deadlock_would_occur) , get_generic_category())); default: throw system_error(get_error_code()); } } void debug() { ::eina_lock_debug(&_mutex); } native_handle_type native_handle() { return &_mutex; } private: mutex(mutex const&) = delete; mutex& operator=(mutex const&) = delete; Eina_Lock _mutex; }; using std::lock_guard; using std::unique_lock; struct condition_variable { typedef Eina_Condition* native_handle_type; condition_variable() { ::eina_condition_new(&_cond, _mutex.native_handle()); } ~condition_variable() { ::eina_condition_free(&_cond); } void notify_one() { eina::unique_lock l(_mutex); Eina_Bool r = eina_condition_signal(&_cond); if(!r) throw eina::system_error(eina::get_error_code()); } void notify_all() { eina::unique_lock l(_mutex); Eina_Bool r = eina_condition_broadcast(&_cond); if(!r) throw eina::system_error(eina::get_error_code()); } template void wait(Lock& lock) { eina::unique_lock l(_mutex); lock.unlock(); ::eina_condition_wait(&_cond); lock.lock(); } template void wait(Lock& lock, Predicate p) { while(!p()) wait(lock); } native_handle_type native_handle() { return &_cond; } private: condition_variable(condition_variable const&); condition_variable& operator=(condition_variable const&); mutex _mutex; Eina_Condition _cond; }; struct thread_id { thread_id() noexcept : _raw(0u) { } thread_id(Eina_Thread raw) : _raw(raw) {} friend inline bool operator==(thread_id lhs, thread_id rhs) { return lhs._raw == rhs._raw; } friend inline bool operator!=(thread_id lhs, thread_id rhs) { return lhs._raw != rhs._raw; } friend inline bool operator<(thread_id lhs, thread_id rhs) { return std::less()(lhs._raw, rhs._raw); } private: Eina_Thread _raw; template friend std::basic_ostream& operator<<(std::basic_ostream& out, thread_id id) { return out << id._raw; } }; inline bool operator<=(thread_id lhs, thread_id rhs) { return (lhs == rhs) || lhs < rhs; } inline bool operator>(thread_id lhs, thread_id rhs) { return !(lhs <= rhs); } inline bool operator>=(thread_id lhs, thread_id rhs) { return !(lhs < rhs); } namespace _detail { struct arguments { Eina_Lock mutex; Eina_Condition condition; bool started; std::function function; }; inline void* create_thread(void* data, Eina_Thread) { arguments* args = static_cast(data); eina_lock_take(&args->mutex); std::function f = std::move(args->function); args->started = true; eina_condition_signal(&args->condition); eina_lock_release(&args->mutex); f(); return 0; } } struct thread { typedef thread_id id; typedef Eina_Thread native_handle_type; thread() noexcept : _joinable(false), _raw(0u) { } template explicit thread(F&& f, Args&&... args) { _detail::arguments arguments; arguments.started = false; arguments.function = std::bind(f, args...); _joinable = true; Eina_Bool r = ::eina_lock_new(&arguments.mutex); if(!r) throw eina::system_error(eina::get_error_code()); r = ::eina_condition_new(&arguments.condition, &arguments.mutex); if(!r) throw eina::system_error(eina::get_error_code()); if(!eina_thread_create (&_raw, ::EINA_THREAD_NORMAL , -1, &eina::_detail::create_thread, &arguments)) { eina_condition_free(&arguments.condition); eina_lock_free(&arguments.mutex); throw eina::system_error(eina::get_error_code()); } Eina_Lock_Result lr = ::eina_lock_take(&arguments.mutex); if(lr != EINA_LOCK_SUCCEED) throw eina::system_error(eina::get_error_code()); while(!arguments.started) { r = eina_condition_wait(&arguments.condition); if(!r) throw eina::system_error(eina::get_error_code()); } lr = eina_lock_release(&arguments.mutex); if(lr != EINA_LOCK_SUCCEED) throw eina::system_error(eina::get_error_code()); eina_condition_free(&arguments.condition); eina_lock_free(&arguments.mutex); } thread(thread&& other) : _joinable(other._joinable), _raw(other._raw) { } thread& operator=(thread&& other) { _raw = other._raw; _joinable = other._joinable; return *this; } ~thread() { assert(!joinable()); } void swap(thread& other) noexcept { std::swap(_raw, other._raw); } bool joinable() const noexcept { return _joinable; } void join() { assert(joinable()); ::eina_thread_join(_raw); _joinable = false; } void detach() { assert(joinable()); _joinable = false; } id get_id() const noexcept { return id(_raw); } native_handle_type native_handle() const { return _raw; } static unsigned hardware_concurrency() noexcept { return ::eina_cpu_count(); } private: bool _joinable; Eina_Thread _raw; }; inline void swap(thread& lhs, thread& rhs) { lhs.swap(rhs); } namespace this_thread { inline thread::id get_id() { return thread::id(eina_thread_self()); } inline void yield() {} template void sleep_until(std::chrono::time_pointconst& abs_time); template void sleep_for(std::chrono::durationconst& rel_time); } } } namespace std { template struct hash; template <> struct hash< ::efl::eina::thread_id> : hash {}; } #endif