mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
Thread.cpp refinement
Hide thread mutex Safe notify() method Other refactoring
This commit is contained in:
+248
-189
File diff suppressed because it is too large
Load Diff
+92
-205
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user