Exceptions passed to wait_op caller

This commit is contained in:
Nekotekina 2015-07-16 03:19:00 +03:00
parent a7668ff57f
commit 1519a2b468

View file

@ -212,23 +212,45 @@ namespace vm
{ {
std::lock_guard<std::mutex> lock(thread->mutex); std::lock_guard<std::mutex> lock(thread->mutex);
// check predicate try
if (pred && pred())
{ {
// clear predicate and signal if succeeded // test predicate
pred = nullptr; if (!pred || !pred())
if (thread->Signal())
{ {
return true; return false;
}
else
{
throw EXCEPTION("Thread already signaled");
} }
} }
catch (...)
{
// catch exception thrown by predicate
auto exception = std::current_exception();
return false; // set new predicate that will throw this exception from the original thread
pred = [exception]() -> bool
{
// rethrow exception
std::rethrow_exception(exception);
// dummy return value
return true;
};
// signal unconditionally (may be already signaled)
thread->Signal();
return true;
}
// clear predicate if succeeded
pred = nullptr;
// signal if succeeded or an exception thrown
if (!thread->Signal())
{
throw EXCEPTION("Thread already signaled");
}
return true;
} }
waiter_lock_t::waiter_lock_t(CPUThread& thread, u32 addr, u32 size) waiter_lock_t::waiter_lock_t(CPUThread& thread, u32 addr, u32 size)
@ -254,6 +276,9 @@ namespace vm
// if another thread called pred(), it must be removed // if another thread called pred(), it must be removed
if (m_waiter->pred) if (m_waiter->pred)
{ {
// pred() should rethrow exception caught by another thread
m_waiter->pred();
throw EXCEPTION("Unexpected"); throw EXCEPTION("Unexpected");
} }
} }
@ -279,7 +304,7 @@ namespace vm
{ {
waiter_t& waiter = g_waiter_list[i]; waiter_t& waiter = g_waiter_list[i];
if (((waiter.addr ^ addr) & (mask & waiter.mask)) == 0 && waiter.thread) if (((waiter.addr ^ addr) & (mask & waiter.mask)) == 0 && waiter.thread && waiter.pred)
{ {
waiter.try_notify(); waiter.try_notify();
} }