|
@@ -16,17 +16,37 @@ namespace anki {
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-Thread::Thread(const char* name)
|
|
|
|
|
|
|
+static void* pthreadCallback(void* ud)
|
|
|
{
|
|
{
|
|
|
- // Do some static assertions on the private data
|
|
|
|
|
- static_assert(sizeof(m_impl) >= sizeof(pthread_t),
|
|
|
|
|
- "Incorrect impl size");
|
|
|
|
|
|
|
+ ANKI_ASSERT(ud != nullptr);
|
|
|
|
|
+ Thread* thread = reinterpret_cast<Thread*>(ud);
|
|
|
|
|
|
|
|
- static_assert(ALIGNMENT >= alignof(pthread_t), "Incorrect impl alignment");
|
|
|
|
|
|
|
+ // Set thread name
|
|
|
|
|
+ if(thread->_getName()[0] != '\0')
|
|
|
|
|
+ {
|
|
|
|
|
+ pthread_setname_np(pthread_self(), &thread->_getName()[0]);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-#if ANKI_ASSERTIONS
|
|
|
|
|
- std::memset(&m_impl[0], 0, sizeof(m_impl));
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ // Call the callback
|
|
|
|
|
+ Thread::Info info;
|
|
|
|
|
+ info.m_userData = thread->_getUserData();
|
|
|
|
|
+ info.m_threadName = thread->_getName();
|
|
|
|
|
+
|
|
|
|
|
+ I err = thread->_getCallback()(info);
|
|
|
|
|
+ void* errVoidp = nullptr;
|
|
|
|
|
+ std::memcpy(&errVoidp, &err, sizeof(err));
|
|
|
|
|
+
|
|
|
|
|
+ return nullptr;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Thread::Thread(const char* name)
|
|
|
|
|
+{
|
|
|
|
|
+ m_impl = malloc(sizeof(pthread_t));
|
|
|
|
|
+ if(m_impl == nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw ANKI_EXCEPTION("Out of memory");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// Init the name
|
|
// Init the name
|
|
|
if(name)
|
|
if(name)
|
|
@@ -45,70 +65,52 @@ Thread::Thread(const char* name)
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
Thread::~Thread()
|
|
Thread::~Thread()
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(!initialized() && "Thread probably not joined");
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-void* Thread::pthreadCallback(void* ud)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(ud != nullptr);
|
|
|
|
|
- Thread* thread = reinterpret_cast<Thread*>(ud);
|
|
|
|
|
-
|
|
|
|
|
- // Set thread name
|
|
|
|
|
- if(thread->m_name[0] != '\0')
|
|
|
|
|
- {
|
|
|
|
|
- pthread_setname_np(pthread_self(), &thread->m_name[0]);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Call the callback
|
|
|
|
|
- Info info;
|
|
|
|
|
- info.m_userData = thread->m_userData;
|
|
|
|
|
- info.m_threadName = &thread->m_name[0];
|
|
|
|
|
-
|
|
|
|
|
- I err = thread->m_callback(info);
|
|
|
|
|
- void* errVoidp = nullptr;
|
|
|
|
|
- std::memcpy(&errVoidp, &err, sizeof(err));
|
|
|
|
|
-
|
|
|
|
|
- return nullptr;
|
|
|
|
|
|
|
+ ANKI_ASSERT(!m_started && "Thread probably not joined");
|
|
|
|
|
+ free(m_impl);
|
|
|
|
|
+ m_impl = nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
void Thread::start(void* userData, Callback callback)
|
|
void Thread::start(void* userData, Callback callback)
|
|
|
{
|
|
{
|
|
|
|
|
+ ANKI_ASSERT(!m_started);
|
|
|
ANKI_ASSERT(callback != nullptr);
|
|
ANKI_ASSERT(callback != nullptr);
|
|
|
|
|
|
|
|
- ANKI_ASSERT(!initialized());
|
|
|
|
|
- pthread_t* impl = reinterpret_cast<pthread_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_t* impl = reinterpret_cast<pthread_t*>(m_impl);
|
|
|
|
|
|
|
|
m_callback = callback;
|
|
m_callback = callback;
|
|
|
m_userData = userData;
|
|
m_userData = userData;
|
|
|
|
|
|
|
|
I err = pthread_create(impl, nullptr, pthreadCallback, this);
|
|
I err = pthread_create(impl, nullptr, pthreadCallback, this);
|
|
|
if(err)
|
|
if(err)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw ANKI_EXCEPTION("pthread_create() failed");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
{
|
|
{
|
|
|
#if ANKI_ASSERTIONS
|
|
#if ANKI_ASSERTIONS
|
|
|
- std::memset(&m_impl[0], 0, sizeof(m_impl));
|
|
|
|
|
|
|
+ m_started = true;
|
|
|
#endif
|
|
#endif
|
|
|
- throw ANKI_EXCEPTION("pthread_create() failed");
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
I Thread::join()
|
|
I Thread::join()
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(initialized());
|
|
|
|
|
- pthread_t* impl = reinterpret_cast<pthread_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_started);
|
|
|
|
|
+ pthread_t* impl = reinterpret_cast<pthread_t*>(m_impl);
|
|
|
|
|
|
|
|
void* out;
|
|
void* out;
|
|
|
U err = pthread_join(*impl, &out);
|
|
U err = pthread_join(*impl, &out);
|
|
|
-#if ANKI_ASSERTIONS
|
|
|
|
|
- std::memset(&m_impl[0], 0, sizeof(m_impl));
|
|
|
|
|
-#endif
|
|
|
|
|
if(err)
|
|
if(err)
|
|
|
{
|
|
{
|
|
|
throw ANKI_EXCEPTION("pthread_join() failed");
|
|
throw ANKI_EXCEPTION("pthread_join() failed");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#if ANKI_ASSERTIONS
|
|
|
|
|
+ m_started = false;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
// Set return error code
|
|
// Set return error code
|
|
|
I callbackErr;
|
|
I callbackErr;
|
|
|
std::memcpy(&callbackErr, &out, sizeof(callbackErr));
|
|
std::memcpy(&callbackErr, &out, sizeof(callbackErr));
|
|
@@ -129,18 +131,20 @@ Thread::Id Thread::getCurrentThreadId()
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
Mutex::Mutex()
|
|
Mutex::Mutex()
|
|
|
{
|
|
{
|
|
|
- // Do some static assertions on the private data
|
|
|
|
|
- static_assert(sizeof(m_impl) >= sizeof(pthread_mutex_t),
|
|
|
|
|
- "Incorrect impl size");
|
|
|
|
|
-
|
|
|
|
|
- static_assert(ALIGNMENT >= alignof(pthread_mutex_t),
|
|
|
|
|
- "Incorrect impl alignment");
|
|
|
|
|
|
|
+ pthread_mutex_t* mtx =
|
|
|
|
|
+ reinterpret_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t)));
|
|
|
|
|
+ if(mtx == nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw ANKI_EXCEPTION("Out of memory");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ m_impl = mtx;
|
|
|
|
|
|
|
|
I err = pthread_mutex_init(mtx, nullptr);
|
|
I err = pthread_mutex_init(mtx, nullptr);
|
|
|
if(err)
|
|
if(err)
|
|
|
{
|
|
{
|
|
|
|
|
+ free(m_impl);
|
|
|
|
|
+ m_impl = nullptr;
|
|
|
throw ANKI_EXCEPTION("pthread_mutex_init() failed");
|
|
throw ANKI_EXCEPTION("pthread_mutex_init() failed");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -148,14 +152,17 @@ Mutex::Mutex()
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
Mutex::~Mutex()
|
|
Mutex::~Mutex()
|
|
|
{
|
|
{
|
|
|
- pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(m_impl);
|
|
|
pthread_mutex_destroy(mtx);
|
|
pthread_mutex_destroy(mtx);
|
|
|
|
|
+
|
|
|
|
|
+ free(m_impl);
|
|
|
|
|
+ m_impl = nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
void Mutex::lock()
|
|
void Mutex::lock()
|
|
|
{
|
|
{
|
|
|
- pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(m_impl);
|
|
|
|
|
|
|
|
I err = pthread_mutex_lock(mtx);
|
|
I err = pthread_mutex_lock(mtx);
|
|
|
if(err)
|
|
if(err)
|
|
@@ -167,7 +174,7 @@ void Mutex::lock()
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
Bool Mutex::tryLock()
|
|
Bool Mutex::tryLock()
|
|
|
{
|
|
{
|
|
|
- pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(m_impl);
|
|
|
|
|
|
|
|
I err = pthread_mutex_trylock(mtx);
|
|
I err = pthread_mutex_trylock(mtx);
|
|
|
return err == 0;
|
|
return err == 0;
|
|
@@ -176,7 +183,7 @@ Bool Mutex::tryLock()
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
void Mutex::unlock()
|
|
void Mutex::unlock()
|
|
|
{
|
|
{
|
|
|
- pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(m_impl);
|
|
|
|
|
|
|
|
I err = pthread_mutex_unlock(mtx);
|
|
I err = pthread_mutex_unlock(mtx);
|
|
|
if(err)
|
|
if(err)
|
|
@@ -192,21 +199,20 @@ void Mutex::unlock()
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
ConditionVariable::ConditionVariable()
|
|
ConditionVariable::ConditionVariable()
|
|
|
{
|
|
{
|
|
|
- // Do some static assertions on the private data
|
|
|
|
|
- static_assert(sizeof(m_impl) >= sizeof(pthread_cond_t),
|
|
|
|
|
- "Incorrect impl size");
|
|
|
|
|
-
|
|
|
|
|
- static_assert(ALIGNMENT >= alignof(pthread_cond_t),
|
|
|
|
|
- "Incorrect impl alignment");
|
|
|
|
|
|
|
+ pthread_cond_t* cond =
|
|
|
|
|
+ reinterpret_cast<pthread_cond_t*>(malloc(sizeof(pthread_cond_t)));
|
|
|
|
|
+ if(cond == nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw ANKI_EXCEPTION("Out of memory");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ m_impl = cond;
|
|
|
|
|
|
|
|
I err = pthread_cond_init(cond, nullptr);
|
|
I err = pthread_cond_init(cond, nullptr);
|
|
|
if(err)
|
|
if(err)
|
|
|
{
|
|
{
|
|
|
-#if ANKI_ASSERTIONS
|
|
|
|
|
- std::memset(&m_impl[0], 0, sizeof(m_impl));
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ free(m_impl);
|
|
|
|
|
+ m_impl = nullptr;
|
|
|
throw ANKI_EXCEPTION("pthread_cond_init() failed");
|
|
throw ANKI_EXCEPTION("pthread_cond_init() failed");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -214,31 +220,64 @@ ConditionVariable::ConditionVariable()
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
ConditionVariable::~ConditionVariable()
|
|
ConditionVariable::~ConditionVariable()
|
|
|
{
|
|
{
|
|
|
- pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(m_impl);
|
|
|
pthread_cond_destroy(cond);
|
|
pthread_cond_destroy(cond);
|
|
|
|
|
+
|
|
|
|
|
+ free(m_impl);
|
|
|
|
|
+ m_impl = nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
void ConditionVariable::notifyOne()
|
|
void ConditionVariable::notifyOne()
|
|
|
{
|
|
{
|
|
|
- pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(m_impl);
|
|
|
pthread_cond_signal(cond);
|
|
pthread_cond_signal(cond);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
void ConditionVariable::notifyAll()
|
|
void ConditionVariable::notifyAll()
|
|
|
{
|
|
{
|
|
|
- pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(&m_impl[0]);
|
|
|
|
|
|
|
+ pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(m_impl);
|
|
|
pthread_cond_broadcast(cond);
|
|
pthread_cond_broadcast(cond);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void ConditionVariable::wait(Mutex& amtx)
|
|
|
|
|
|
|
+Bool ConditionVariable::wait(Mutex& amtx, F64 timeoutSeconds)
|
|
|
{
|
|
{
|
|
|
- pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(&m_impl[0]);
|
|
|
|
|
- pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(&amtx.m_impl[0]);
|
|
|
|
|
|
|
+ pthread_cond_t* cond = reinterpret_cast<pthread_cond_t*>(m_impl);
|
|
|
|
|
+ pthread_mutex_t* mtx = reinterpret_cast<pthread_mutex_t*>(amtx.m_impl);
|
|
|
|
|
+
|
|
|
|
|
+ Bool timeout = false;
|
|
|
|
|
+ I err = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if(timeoutSeconds == 0.0)
|
|
|
|
|
+ {
|
|
|
|
|
+ err = pthread_cond_wait(cond, mtx);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ U64 ns = static_cast<U64>(timeoutSeconds * 1e+9);
|
|
|
|
|
+ struct timespec abstime;
|
|
|
|
|
+ abstime.tv_sec = ns / 1000000000;
|
|
|
|
|
+ abstime.tv_nsec = (ns % 1000000000);
|
|
|
|
|
+ err = pthread_cond_timedwait(cond, mtx, &abstime);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(err == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Do nothing
|
|
|
|
|
+ }
|
|
|
|
|
+ else if(err == ETIMEDOUT)
|
|
|
|
|
+ {
|
|
|
|
|
+ timeout = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ throw ANKI_EXCEPTION("pthread_cond_wait() or pthread_cond_timedwait()"
|
|
|
|
|
+ " failed: %d", err);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- pthread_cond_wait(cond, mtx);
|
|
|
|
|
|
|
+ return timeout;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // end namespace anki
|
|
} // end namespace anki
|