Thread.cpp refinement

Hide thread mutex
Safe notify() method
Other refactoring
This commit is contained in:
Nekotekina
2017-01-29 19:52:19 +03:00
parent da878c36bd
commit a5a2d43d7c
35 changed files with 532 additions and 591 deletions
+248 -189
View File
File diff suppressed because it is too large Load Diff
+92 -205
View File
@@ -7,6 +7,9 @@
#include <string>
#include <memory>
#include "sema.h"
#include "cond.h"
// Will report exception and call std::abort() if put in catch(...)
[[noreturn]] void catch_all_exceptions();
@@ -17,19 +20,19 @@ class task_stack
{
std::unique_ptr<task_base> next;
virtual ~task_base() = default;
virtual ~task_base();
virtual void exec()
virtual void invoke()
{
if (next)
{
next->exec();
next->invoke();
}
}
};
template<typename F>
struct task_type : task_base
template <typename F>
struct task_type final : task_base
{
std::remove_reference_t<F> func;
@@ -38,10 +41,10 @@ class task_stack
{
}
void exec() override
void invoke() final override
{
func();
task_base::exec();
task_base::invoke();
}
};
@@ -50,7 +53,7 @@ class task_stack
public:
task_stack() = default;
template<typename F>
template <typename F>
task_stack(F&& func)
: m_stack(new task_type<F>(std::forward<F>(func)))
{
@@ -70,11 +73,11 @@ public:
m_stack.reset();
}
void exec() const
void invoke() const
{
if (m_stack)
{
m_stack->exec();
m_stack->invoke();
}
}
};
@@ -82,23 +85,41 @@ public:
// Thread control class
class thread_ctrl final
{
public: // TODO
struct internal;
private:
// Current thread
static thread_local thread_ctrl* g_tls_this_thread;
// Thread handle storage
std::aligned_storage_t<16> m_thread;
// Self pointer
std::shared_ptr<thread_ctrl> m_self;
// Thread join contention counter
atomic_t<u32> m_joining{};
// Thread handle (platform-specific)
atomic_t<std::uintptr_t> m_thread{0};
// Thread mutex
mutable semaphore<> m_mutex;
// Thread condition variable
cond_variable m_cond;
// Thread flags
atomic_t<u32> m_signal{0};
// Thread joining condition variable
cond_variable m_jcv;
// Remotely set or caught exception
std::exception_ptr m_exception;
// Thread initial task or atexit task
task_stack m_task;
// Thread interrupt guard counter
volatile u32 m_guard = 0x80000000;
// Thread internals
atomic_t<internal*> m_data{};
// Thread interrupt condition variable
cond_variable m_icv;
// Interrupt function
atomic_t<void(*)()> m_iptr{nullptr};
// Fixed name
std::string m_name;
@@ -110,19 +131,19 @@ private:
void initialize();
// Called at the thread end
void finalize() noexcept;
void finalize(std::exception_ptr) noexcept;
// Get atexit function
void push_atexit(task_stack);
// Add task (atexit)
static void _push(task_stack);
// Start waiting
void wait_start(u64 timeout);
// Internal waiting function, may throw. Infinite value is -1.
static bool _wait_for(u64 usec);
// Proceed waiting
bool wait_wait(u64 timeout);
// Internal throwing function. Mutex must be locked and will be unlocked.
[[noreturn]] void _throw();
// Check exception
void test();
// Internal notification function
void _notify(cond_variable thread_ctrl::*);
public:
thread_ctrl(std::string&& name);
@@ -137,63 +158,22 @@ public:
return m_name;
}
// Initialize internal data
void initialize_once();
// Get exception
std::exception_ptr get_exception() const;
// Set exception
void set_exception(std::exception_ptr ptr);
// Get thread result (may throw, simultaneous joining allowed)
void join();
// Lock thread mutex
void lock();
// Lock conditionally (double-checked)
template<typename F>
bool lock_if(F&& pred)
{
if (pred())
{
lock();
try
{
if (LIKELY(pred()))
{
return true;
}
else
{
unlock();
return false;
}
}
catch (...)
{
unlock();
throw;
}
}
else
{
return false;
}
}
// Unlock thread mutex (internal data must be initialized)
void unlock();
// Lock, unlock, notify the thread (required if the condition changed locklessly)
void lock_notify();
// Notify the thread (internal data must be initialized)
// Notify the thread
void notify();
// Set exception (internal data must be initialized, thread mutex must be locked)
void set_exception(std::exception_ptr);
// Internal
static void handle_interrupt();
// Interrupt thread with specified handler call (thread mutex must be locked)
// Interrupt thread with specified handler call
void interrupt(void(*handler)());
// Interrupt guard recursive enter
@@ -226,90 +206,45 @@ public:
// Check interrupt if delayed by guard scope
void test_interrupt();
// Current thread sleeps for specified amount of microseconds.
// Wrapper for std::this_thread::sleep, doesn't require valid thread_ctrl.
[[deprecated]] static void sleep(u64 useconds);
// Wait until pred(). Abortable, may throw. Thread must be locked.
// Timeout in microseconds (zero means infinite).
template<typename F>
static inline auto wait_for(u64 useconds, F&& pred)
// Wait once with timeout. Abortable, may throw. May spuriously return false.
static inline bool wait_for(u64 usec)
{
if (useconds)
{
g_tls_this_thread->wait_start(useconds);
}
while (true)
{
g_tls_this_thread->test();
if (auto&& result = pred())
{
return result;
}
else if (!g_tls_this_thread->wait_wait(useconds) && useconds)
{
return result;
}
}
return _wait_for(usec);
}
// Wait once. Abortable, may throw. Thread must be locked.
// Timeout in microseconds (zero means infinite).
static inline bool wait_for(u64 useconds = 0)
{
if (useconds)
{
g_tls_this_thread->wait_start(useconds);
}
g_tls_this_thread->test();
if (!g_tls_this_thread->wait_wait(useconds) && useconds)
{
return false;
}
g_tls_this_thread->test();
return true;
}
// Wait until pred(). Abortable, may throw. Thread must be locked.
template<typename F>
static inline auto wait(F&& pred)
{
while (true)
{
g_tls_this_thread->test();
if (auto&& result = pred())
{
return result;
}
g_tls_this_thread->wait_wait(0);
}
}
// Wait once. Abortable, may throw. Thread must be locked.
// Wait. Abortable, may throw.
static inline void wait()
{
g_tls_this_thread->test();
g_tls_this_thread->wait_wait(0);
g_tls_this_thread->test();
_wait_for(-1);
}
// Wait eternally. Abortable, may throw. Thread must be locked.
// Wait until pred(). Abortable, may throw.
template<typename F, typename RT = std::result_of_t<F()>>
static inline RT wait(F&& pred)
{
while (true)
{
if (RT result = pred())
{
return result;
}
_wait_for(-1);
}
}
// Wait eternally until aborted.
[[noreturn]] static inline void eternalize()
{
while (true)
{
g_tls_this_thread->test();
g_tls_this_thread->wait_wait(0);
_wait_for(-1);
}
}
// Test exception (may throw).
static void test();
// Get current thread (may be nullptr)
static thread_ctrl* get_current()
{
@@ -320,14 +255,14 @@ public:
template<typename F>
static inline void atexit(F&& func)
{
return g_tls_this_thread->push_atexit(std::forward<F>(func));
_push(std::forward<F>(func));
}
// Named thread factory
// Create detached named thread
template<typename N, typename F>
static inline void spawn(N&& name, F&& func)
{
auto&& out = std::make_shared<thread_ctrl>(std::forward<N>(name));
auto out = std::make_shared<thread_ctrl>(std::forward<N>(name));
thread_ctrl::start(out, std::forward<F>(func));
}
@@ -382,7 +317,7 @@ public:
}
// Access thread_ctrl
thread_ctrl* operator->() const
thread_ctrl* get() const
{
return m_thread.get();
}
@@ -392,60 +327,12 @@ public:
return m_thread->join();
}
void lock() const
{
return m_thread->lock();
}
void unlock() const
{
return m_thread->unlock();
}
void lock_notify() const
{
return m_thread->lock_notify();
}
void notify() const
{
return m_thread->notify();
}
};
// Simple thread mutex locker
class thread_lock final
{
thread_ctrl* m_thread;
public:
thread_lock(const thread_lock&) = delete;
// Lock specified thread
thread_lock(thread_ctrl* thread)
: m_thread(thread)
{
m_thread->lock();
}
// Lock specified named_thread
thread_lock(named_thread& thread)
: thread_lock(thread.operator->())
{
}
// Lock current thread
thread_lock()
: thread_lock(thread_ctrl::get_current())
{
}
~thread_lock()
{
m_thread->unlock();
}
};
// Interrupt guard scope
class thread_guard final
{
@@ -455,24 +342,24 @@ public:
thread_guard(const thread_guard&) = delete;
thread_guard(thread_ctrl* thread)
: m_thread(thread)
//: m_thread(thread)
{
m_thread->guard_enter();
//m_thread->guard_enter();
}
thread_guard(named_thread& thread)
: thread_guard(thread.operator->())
//: thread_guard(thread.get())
{
}
thread_guard()
: thread_guard(thread_ctrl::get_current())
//: thread_guard(thread_ctrl::get_current())
{
}
~thread_guard() noexcept(false)
{
m_thread->guard_leave();
//m_thread->guard_leave();
}
};
@@ -498,7 +385,7 @@ public:
}
// Access thread_ctrl
thread_ctrl* operator->() const
thread_ctrl* get() const
{
return m_thread.get();
}
+3 -3
View File
@@ -20,13 +20,13 @@ public:
constexpr cond_variable() = default;
// Intrusive wait algorithm for lockable objects
template <typename T, void (T::*Unlock)() = &T::unlock, void (T::*Lock)() = &T::lock>
template <typename T>
explicit_bool_t wait(T& object, u64 usec_timeout = -1)
{
const u32 _old = m_value.fetch_add(1); // Increment waiter counter
(object.*Unlock)();
object.unlock();
const bool res = imp_wait(_old, usec_timeout);
(object.*Lock)();
object.lock();
return res;
}
+16 -4
View File
@@ -99,27 +99,39 @@ public:
}
};
// Simplified shared (reader) lock implementation, std::shared_lock compatible.
// Simplified shared (reader) lock implementation.
class reader_lock final
{
shared_mutex& m_mutex;
void lock()
{
m_mutex.lock_shared();
}
void unlock()
{
m_mutex.unlock_shared();
}
friend class cond_variable;
public:
reader_lock(const reader_lock&) = delete;
explicit reader_lock(shared_mutex& mutex)
: m_mutex(mutex)
{
m_mutex.lock_shared();
lock();
}
~reader_lock()
{
m_mutex.unlock_shared();
unlock();
}
};
// Simplified exclusive (writer) lock implementation, std::lock_guard compatible.
// Simplified exclusive (writer) lock implementation.
class writer_lock final
{
shared_mutex& m_mutex;
+33
View File
@@ -13,6 +13,8 @@ class semaphore_base
void imp_post(s32 _old);
friend class semaphore_lock;
protected:
explicit constexpr semaphore_base(s32 value)
: m_value{value}
@@ -108,3 +110,34 @@ public:
return Max;
}
};
class semaphore_lock
{
semaphore_base& m_base;
void lock()
{
m_base.wait();
}
void unlock()
{
m_base.post(INT32_MAX);
}
friend class cond_variable;
public:
explicit semaphore_lock(const semaphore_lock&) = delete;
semaphore_lock(semaphore_base& sema)
: m_base(sema)
{
lock();
}
~semaphore_lock()
{
unlock();
}
};
+2 -20
View File
@@ -43,8 +43,6 @@ void cpu_thread::on_task()
Emu.SendDbgCommand(DID_CREATE_THREAD, this);
std::unique_lock<named_thread> lock(*this);
// Check thread status
while (!test(state & cpu_flag::exit))
{
@@ -53,8 +51,6 @@ void cpu_thread::on_task()
// check stop status
if (!test(state & cpu_flag::stop))
{
if (lock) lock.unlock();
try
{
cpu_task();
@@ -73,12 +69,6 @@ void cpu_thread::on_task()
continue;
}
if (!lock)
{
lock.lock();
continue;
}
thread_ctrl::wait();
}
}
@@ -86,7 +76,7 @@ void cpu_thread::on_task()
void cpu_thread::on_stop()
{
state += cpu_flag::exit;
lock_notify();
notify();
}
cpu_thread::~cpu_thread()
@@ -100,8 +90,6 @@ cpu_thread::cpu_thread(u32 id)
bool cpu_thread::check_state()
{
std::unique_lock<named_thread> lock(*this, std::defer_lock);
while (true)
{
CHECK_EMU_STATUS; // check at least once
@@ -116,12 +104,6 @@ bool cpu_thread::check_state()
break;
}
if (!lock)
{
lock.lock();
continue;
}
thread_ctrl::wait();
}
@@ -144,7 +126,7 @@ bool cpu_thread::check_state()
void cpu_thread::run()
{
state -= cpu_flag::stop;
lock_notify();
notify();
}
void cpu_thread::set_signal()
+2 -2
View File
@@ -799,7 +799,7 @@ s32 cellFsAioRead(vm::ptr<CellFsAio> aio, vm::ptr<s32> id, fs_aio_cb_t func)
{ aio, func },
});
m->thread->lock_notify();
m->thread->notify();
return CELL_OK;
}
@@ -825,7 +825,7 @@ s32 cellFsAioWrite(vm::ptr<CellFsAio> aio, vm::ptr<s32> id, fs_aio_cb_t func)
{ aio, func },
});
m->thread->lock_notify();
m->thread->notify();
return CELL_OK;
}
-4
View File
@@ -773,8 +773,6 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt)
{
bool shouldExit;
std::unique_lock<named_thread> lock(spu, std::defer_lock);
while (true)
{
vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128);
@@ -862,8 +860,6 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt)
if (spuIdling && shouldExit == false && foundReadyWorkload == false)
{
// The system service blocks by making a reservation and waiting on the lock line reservation lost event.
CHECK_EMU_STATUS;
if (!lock) { lock.lock(); continue; }
thread_ctrl::wait_for(1000);
continue;
}
+9 -8
View File
@@ -75,6 +75,7 @@ struct vdec_thread : ppu_thread
u64 next_pts{};
u64 next_dts{};
std::mutex mutex;
std::queue<vdec_frame> out;
std::queue<u64> user_data; // TODO
@@ -325,7 +326,7 @@ struct vdec_thread : ppu_thread
cellVdec.trace("Got picture (pts=0x%llx[0x%llx], dts=0x%llx[0x%llx])", frame.pts, frame->pkt_pts, frame.dts, frame->pkt_dts);
thread_lock{*this}, out.push(std::move(frame));
std::lock_guard<std::mutex>{mutex}, out.push(std::move(frame));
cb_func(*this, id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, cb_arg);
}
@@ -437,7 +438,7 @@ s32 cellVdecClose(u32 handle)
}
vdec->cmd_push({vdec_cmd::close, 0});
vdec->lock_notify();
vdec->notify();
vdec->join();
idm::remove<ppu_thread>(handle);
return CELL_OK;
@@ -455,7 +456,7 @@ s32 cellVdecStartSeq(u32 handle)
}
vdec->cmd_push({vdec_cmd::start_seq, 0});
vdec->lock_notify();
vdec->notify();
return CELL_OK;
}
@@ -471,7 +472,7 @@ s32 cellVdecEndSeq(u32 handle)
}
vdec->cmd_push({vdec_cmd::end_seq, 0});
vdec->lock_notify();
vdec->notify();
return CELL_OK;
}
@@ -497,7 +498,7 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInf
auInfo->codecSpecificData,
});
vdec->lock_notify();
vdec->notify();
return CELL_OK;
}
@@ -514,7 +515,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
vdec_frame frame;
{
thread_lock lock(*vdec);
std::lock_guard<std::mutex> lock(vdec->mutex);
if (vdec->out.empty())
{
@@ -639,7 +640,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
u64 usrd;
u32 frc;
{
thread_lock lock(*vdec);
std::lock_guard<std::mutex> lock(vdec->mutex);
if (vdec->out.empty())
{
@@ -830,7 +831,7 @@ s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
// TODO: check frc value
vdec->cmd_push({vdec_cmd::set_frc, frc});
vdec->lock_notify();
vdec->notify();
return CELL_OK;
}
+1 -1
View File
@@ -50,7 +50,7 @@ s32 sys_ppu_thread_create(vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio,
return eq.name == "_mxr000\0"_u64;
}))
{
thread_ctrl::sleep(50000);
thread_ctrl::wait_for(50000);
}
}
+2 -13
View File
@@ -312,33 +312,22 @@ void ppu_thread::cmd_pop(u32 count)
cmd64 ppu_thread::cmd_wait()
{
std::unique_lock<named_thread> lock(*this, std::defer_lock);
while (true)
{
if (UNLIKELY(test(state)))
{
if (lock) lock.unlock();
if (check_state()) // check_status() requires unlocked mutex
if (check_state())
{
return cmd64{};
}
}
// Lightweight queue doesn't care about mutex state
if (cmd64 result = cmd_queue[cmd_queue.peek()].exchange(cmd64{}))
{
return result;
}
if (!lock)
{
lock.lock();
continue;
}
thread_ctrl::wait(); // Waiting requires locked mutex
thread_ctrl::wait();
}
}
+7 -35
View File
@@ -503,7 +503,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
u32 SPUThread::get_events(bool waiting)
{
// check reservation status and set SPU_EVENT_LR if lost
if (last_raddr != 0 && !vm::reservation_test(operator->()))
if (last_raddr != 0 && !vm::reservation_test(this->get()))
{
ch_event_stat |= SPU_EVENT_LR;
@@ -546,7 +546,7 @@ void SPUThread::set_events(u32 mask)
// Notify if some events were set
if (~old_stat & mask && old_stat & SPU_EVENT_WAITING && ch_event_stat & SPU_EVENT_WAITING)
{
lock_notify();
notify();
}
}
@@ -600,7 +600,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
{
if (!channel.try_pop(out))
{
thread_lock{*this}, thread_ctrl::wait([&] { return test(state & cpu_flag::stop) || channel.try_pop(out); });
thread_ctrl::wait([&] { return test(state & cpu_flag::stop) || channel.try_pop(out); });
return !test(state & cpu_flag::stop);
}
@@ -615,8 +615,6 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
// break;
case SPU_RdInMbox:
{
std::unique_lock<named_thread> lock(*this, std::defer_lock);
while (true)
{
if (const uint old_count = ch_in_mbox.try_pop(out))
@@ -636,12 +634,6 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
return false;
}
if (!lock)
{
lock.lock();
continue;
}
thread_ctrl::wait();
}
}
@@ -691,8 +683,6 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
case SPU_RdEventStat:
{
std::unique_lock<named_thread> lock(*this, std::defer_lock);
// start waiting or return immediately
if (u32 res = get_events(true))
{
@@ -707,8 +697,6 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
}
else
{
lock.lock();
// simple waiting loop otherwise
while (!get_events(true) && !test(state & cpu_flag::stop))
{
@@ -754,8 +742,6 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
{
if (offset >= RAW_SPU_BASE_ADDR)
{
std::unique_lock<named_thread> lock(*this, std::defer_lock);
while (!ch_out_intr_mbox.try_push(value))
{
CHECK_EMU_STATUS;
@@ -765,12 +751,6 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
return false;
}
if (!lock)
{
lock.lock();
continue;
}
thread_ctrl::wait();
}
@@ -961,8 +941,6 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
case SPU_WrOutMbox:
{
std::unique_lock<named_thread> lock(*this, std::defer_lock);
while (!ch_out_mbox.try_push(value))
{
CHECK_EMU_STATUS;
@@ -972,12 +950,6 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
return false;
}
if (!lock)
{
lock.lock();
continue;
}
thread_ctrl::wait();
}
@@ -1237,7 +1209,7 @@ bool SPUThread::stop_and_signal(u32 code)
return false;
}
group->cv.wait_for(lv2_lock, 1ms);
group->cv.wait(lv2_lock, 1000);
}
// change group status
@@ -1278,7 +1250,7 @@ bool SPUThread::stop_and_signal(u32 code)
return false;
}
get_current_thread_cv().wait(lv2_lock);
LV2_UNLOCK, thread_ctrl::wait();
}
// event data must be set by push()
@@ -1303,7 +1275,7 @@ bool SPUThread::stop_and_signal(u32 code)
if (thread && thread.get() != this)
{
thread->state -= cpu_flag::suspend;
thread->lock_notify();
thread->notify();
}
}
@@ -1342,7 +1314,7 @@ bool SPUThread::stop_and_signal(u32 code)
if (thread && thread.get() != this)
{
thread->state += cpu_flag::stop;
thread->lock_notify();
thread->notify();
}
}
+4 -4
View File
@@ -180,7 +180,7 @@ public:
data.value |= value;
});
if (old.wait) spu.lock_notify();
if (old.wait) spu.notify();
}
// push unconditionally (overwriting previous value), may require notification
@@ -193,7 +193,7 @@ public:
data.value = value;
});
if (old.wait) spu.lock_notify();
if (old.wait) spu.notify();
}
// returns true on success
@@ -228,7 +228,7 @@ public:
// value is not cleared and may be read again
});
if (old.wait) spu.lock_notify();
if (old.wait) spu.notify();
return old.value;
}
@@ -295,7 +295,7 @@ public:
return false;
}))
{
spu.lock_notify();
spu.notify();
}
}
+1 -1
View File
@@ -1013,4 +1013,4 @@ extern ppu_function_t ppu_get_syscall(u64 code)
return nullptr;
}
DECLARE(lv2_lock_t::mutex);
DECLARE(lv2_lock_guard::g_sema);
+2 -2
View File
@@ -222,11 +222,11 @@ s32 sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
continue;
}
get_current_thread_cv().wait_for(lv2_lock, std::chrono::microseconds(timeout - passed));
LV2_UNLOCK, thread_ctrl::wait_for(timeout - passed);
}
else
{
get_current_thread_cv().wait(lv2_lock);
LV2_UNLOCK, thread_ctrl::wait();
}
}
+2 -2
View File
@@ -282,11 +282,11 @@ s32 sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
return CELL_ETIMEDOUT;
}
get_current_thread_cv().wait_for(lv2_lock, std::chrono::microseconds(timeout - passed));
LV2_UNLOCK, thread_ctrl::wait_for(timeout - passed);
}
else
{
get_current_thread_cv().wait(lv2_lock);
LV2_UNLOCK, thread_ctrl::wait();
}
}
+2 -2
View File
@@ -162,11 +162,11 @@ s32 sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u
return CELL_ETIMEDOUT;
}
get_current_thread_cv().wait_for(lv2_lock, std::chrono::microseconds(timeout - passed));
LV2_UNLOCK, thread_ctrl::wait_for(timeout - passed);
}
else
{
get_current_thread_cv().wait(lv2_lock);
LV2_UNLOCK, thread_ctrl::wait();
}
}
+4 -4
View File
@@ -28,7 +28,7 @@ void lv2_int_serv_t::exec()
{ ppu_cmd::lle_call, 2 },
});
thread->lock_notify();
thread->notify();
}
void lv2_int_serv_t::join(ppu_thread& ppu, lv2_lock_t lv2_lock)
@@ -41,14 +41,14 @@ void lv2_int_serv_t::join(ppu_thread& ppu, lv2_lock_t lv2_lock)
{ ppu_cmd::opcode, ppu_instructions::SC(0) },
});
thread->lock_notify();
thread->notify();
// Join thread (TODO)
while (!test(thread->state & cpu_flag::exit))
{
CHECK_EMU_STATUS;
get_current_thread_cv().wait_for(lv2_lock, 1ms);
LV2_UNLOCK, thread_ctrl::wait_for(1000);
}
// Cleanup
@@ -155,7 +155,7 @@ void sys_interrupt_thread_eoi(ppu_thread& ppu) // Low-level PPU function example
if (ppu.lr == 0 || ppu.gpr[11] != 88)
{
// Low-level function must disable interrupts before throwing (not related to sys_interrupt_*, it's rather coincidence)
ppu->interrupt_disable();
ppu.get()->interrupt_disable();
throw cpu_flag::ret;
}
}
+2 -2
View File
@@ -202,11 +202,11 @@ s32 _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 t
}
}
get_current_thread_cv().wait_for(lv2_lock, std::chrono::microseconds(timeout - passed));
LV2_UNLOCK, thread_ctrl::wait_for(timeout - passed);
}
else
{
get_current_thread_cv().wait(lv2_lock);
LV2_UNLOCK, thread_ctrl::wait();
}
}
+2 -2
View File
@@ -114,11 +114,11 @@ s32 _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
return CELL_ETIMEDOUT;
}
get_current_thread_cv().wait_for(lv2_lock, std::chrono::microseconds(timeout - passed));
LV2_UNLOCK, thread_ctrl::wait_for(timeout - passed);
}
else
{
get_current_thread_cv().wait(lv2_lock);
LV2_UNLOCK, thread_ctrl::wait();
}
}

Some files were not shown because too many files have changed in this diff Show More