1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42:36 +01:00

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"
namespace vm
{
class waiter_lock_t;
}
enum CPUThreadType
{
CPU_THREAD_PPU,
@ -53,6 +58,8 @@ public:
using thread_t::is_current;
using thread_t::get_thread_ctrl;
friend vm::waiter_lock_t;
protected:
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;
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);
@ -242,25 +242,18 @@ namespace vm
addr = 0;
mask = ~0;
// signal thread (must not be signaled yet)
if (!thread->signal())
{
throw EXCEPTION("Thread already signaled");
}
// signal thread
thread->cv.notify_one();
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()
{
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())
{
return;
@ -270,15 +263,6 @@ namespace vm
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()

View File

@ -4,7 +4,7 @@
const class thread_ctrl_t* get_current_thread_ctrl();
class CPUThread;
class thread_t;
namespace vm
{
@ -38,13 +38,13 @@ namespace vm
{
u32 addr = 0;
u32 mask = ~0;
CPUThread* thread = nullptr;
thread_t* thread = nullptr;
std::function<bool()> pred;
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->mask = ~(size - 1);
@ -62,6 +62,9 @@ namespace vm
bool try_notify();
};
// for internal use
waiter_t* _add_waiter(thread_t& thread, u32 addr, u32 size);
class waiter_lock_t
{
waiter_t* m_waiter;
@ -70,7 +73,11 @@ namespace vm
public:
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
{
@ -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
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)
if (pred(args...)) return;
@ -396,15 +403,14 @@ namespace vm
}
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_ptr.h"
#include "vm_var.h"
class CPUThread;
namespace vm
{
class stack
@ -439,4 +445,7 @@ namespace vm
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);
}