vm::wait_op improved

Now it accepts thread_t and its descendants (but may require adding
friend vm::waiter_lock_t class)
This commit is contained in:
Nekotekina 2015-07-27 04:18:18 +03:00
parent ff1f6d3d4f
commit 71a378a3fb
3 changed files with 30 additions and 30 deletions

View file

@ -2,6 +2,11 @@
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
namespace vm
{
class waiter_lock_t;
}
enum CPUThreadType enum CPUThreadType
{ {
CPU_THREAD_PPU, CPU_THREAD_PPU,
@ -53,6 +58,8 @@ public:
using thread_t::is_current; using thread_t::is_current;
using thread_t::get_thread_ctrl; using thread_t::get_thread_ctrl;
friend vm::waiter_lock_t;
protected: protected:
CPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name); CPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name);

View file

@ -152,7 +152,7 @@ namespace vm
std::mutex g_waiter_list_mutex; std::mutex g_waiter_list_mutex;
waiter_t* _add_waiter(CPUThread& thread, u32 addr, u32 size) waiter_t* _add_waiter(thread_t& thread, u32 addr, u32 size)
{ {
std::lock_guard<std::mutex> lock(g_waiter_list_mutex); std::lock_guard<std::mutex> lock(g_waiter_list_mutex);
@ -242,25 +242,18 @@ namespace vm
addr = 0; addr = 0;
mask = ~0; mask = ~0;
// signal thread (must not be signaled yet) // signal thread
if (!thread->signal()) thread->cv.notify_one();
{
throw EXCEPTION("Thread already signaled");
}
return true; return true;
} }
waiter_lock_t::waiter_lock_t(CPUThread& thread, u32 addr, u32 size)
: m_waiter(_add_waiter(thread, addr, size))
, m_lock(thread.mutex, std::adopt_lock) // must be locked in _add_waiter
{
}
void waiter_lock_t::wait() void waiter_lock_t::wait()
{ {
while (!m_waiter->thread->unsignal()) // if another thread successfully called pred(), it must be set to null
while (m_waiter->pred)
{ {
// if pred() called by another thread threw an exception, it'll be rethrown
if (m_waiter->pred()) if (m_waiter->pred())
{ {
return; return;
@ -270,15 +263,6 @@ namespace vm
m_waiter->thread->cv.wait(m_lock); m_waiter->thread->cv.wait(m_lock);
} }
// if another thread successfully called pred(), it must be set to null
if (m_waiter->pred)
{
// if pred() called by another thread threw an exception, rethrow it
m_waiter->pred();
throw EXCEPTION("Unexpected");
}
} }
waiter_lock_t::~waiter_lock_t() waiter_lock_t::~waiter_lock_t()

View file

@ -4,7 +4,7 @@
const class thread_ctrl_t* get_current_thread_ctrl(); const class thread_ctrl_t* get_current_thread_ctrl();
class CPUThread; class thread_t;
namespace vm namespace vm
{ {
@ -38,13 +38,13 @@ namespace vm
{ {
u32 addr = 0; u32 addr = 0;
u32 mask = ~0; u32 mask = ~0;
CPUThread* thread = nullptr; thread_t* thread = nullptr;
std::function<bool()> pred; std::function<bool()> pred;
waiter_t() = default; waiter_t() = default;
waiter_t* reset(u32 addr, u32 size, CPUThread& thread) waiter_t* reset(u32 addr, u32 size, thread_t& thread)
{ {
this->addr = addr; this->addr = addr;
this->mask = ~(size - 1); this->mask = ~(size - 1);
@ -62,6 +62,9 @@ namespace vm
bool try_notify(); bool try_notify();
}; };
// for internal use
waiter_t* _add_waiter(thread_t& thread, u32 addr, u32 size);
class waiter_lock_t class waiter_lock_t
{ {
waiter_t* m_waiter; waiter_t* m_waiter;
@ -70,7 +73,11 @@ namespace vm
public: public:
waiter_lock_t() = delete; waiter_lock_t() = delete;
waiter_lock_t(CPUThread& thread, u32 addr, u32 size); template<typename T> inline waiter_lock_t(T& thread, u32 addr, u32 size)
: m_waiter(_add_waiter(static_cast<thread_t&>(thread), addr, size))
, m_lock(thread.mutex, std::adopt_lock) // must be locked in _add_waiter
{
}
waiter_t* operator ->() const waiter_t* operator ->() const
{ {
@ -83,7 +90,7 @@ namespace vm
}; };
// wait until pred() returns true, addr must be aligned to size which must be a power of 2, pred() may be called by any thread // wait until pred() returns true, addr must be aligned to size which must be a power of 2, pred() may be called by any thread
template<typename F, typename... Args> auto wait_op(CPUThread& thread, u32 addr, u32 size, F pred, Args&&... args) -> decltype(static_cast<void>(pred(args...))) template<typename T, typename F, typename... Args> auto wait_op(T& thread, u32 addr, u32 size, F pred, Args&&... args) -> decltype(static_cast<void>(pred(args...)))
{ {
// return immediately if condition passed (optimistic case) // return immediately if condition passed (optimistic case)
if (pred(args...)) return; if (pred(args...)) return;
@ -396,15 +403,14 @@ namespace vm
} }
void close(); void close();
u32 stack_push(CPUThread& CPU, u32 size, u32 align, u32& old_pos);
void stack_pop(CPUThread& CPU, u32 addr, u32 old_pos);
} }
#include "vm_ref.h" #include "vm_ref.h"
#include "vm_ptr.h" #include "vm_ptr.h"
#include "vm_var.h" #include "vm_var.h"
class CPUThread;
namespace vm namespace vm
{ {
class stack class stack
@ -439,4 +445,7 @@ namespace vm
return m_begin + m_position; return m_begin + m_position;
} }
}; };
u32 stack_push(CPUThread& cpu, u32 size, u32 align, u32& old_pos);
void stack_pop(CPUThread& cpu, u32 addr, u32 old_pos);
} }