forked from enlightenment/efl
357 lines
7.3 KiB
C++
357 lines
7.3 KiB
C++
#ifndef EINA_THREAD_HH_
|
|
#define EINA_THREAD_HH_
|
|
|
|
#include <Eina.h>
|
|
#include <eina_error.hh>
|
|
|
|
#include <memory>
|
|
#include <iterator>
|
|
#include <cstdlib>
|
|
#include <cassert>
|
|
#include <iosfwd>
|
|
#include <functional>
|
|
#include <chrono>
|
|
#include <mutex>
|
|
|
|
#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<eina::mutex> 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<eina::mutex> l(_mutex);
|
|
Eina_Bool r = eina_condition_broadcast(&_cond);
|
|
if(!r)
|
|
throw eina::system_error(eina::get_error_code());
|
|
}
|
|
template <typename Lock>
|
|
void wait(Lock& lock)
|
|
{
|
|
eina::unique_lock<eina::mutex> l(_mutex);
|
|
lock.unlock();
|
|
::eina_condition_wait(&_cond);
|
|
lock.lock();
|
|
}
|
|
template <typename Lock, typename Predicate>
|
|
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<Eina_Thread>()(lhs._raw, rhs._raw);
|
|
}
|
|
private:
|
|
Eina_Thread _raw;
|
|
|
|
template <typename charT, typename Traits>
|
|
friend std::basic_ostream<charT, Traits>&
|
|
operator<<(std::basic_ostream<charT, Traits>& 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<void()> function;
|
|
};
|
|
|
|
inline void* create_thread(void* data, Eina_Thread)
|
|
{
|
|
arguments* args = static_cast<arguments*>(data);
|
|
|
|
eina_lock_take(&args->mutex);
|
|
|
|
std::function<void()> 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 <typename F, class ... Args>
|
|
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 <typename Clock, typename Duration>
|
|
void sleep_until(std::chrono::time_point<Clock, Duration>const& abs_time);
|
|
|
|
template <typename Rep, typename Period>
|
|
void sleep_for(std::chrono::duration<Rep, Period>const& rel_time);
|
|
}
|
|
|
|
} }
|
|
|
|
namespace std {
|
|
|
|
template <typename T> struct hash;
|
|
template <>
|
|
struct hash< ::efl::eina::thread_id> : hash<unsigned long>
|
|
{};
|
|
|
|
}
|
|
|
|
#endif
|