diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 560678f19c..ccf5a91d1c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -108,20 +108,20 @@ public: return str; } - // Find and remove the object from the container (deque or vector) + // Find and remove the object from the deque container template - static T* unqueue(std::deque& queue, E* object) + static T unqueue(std::deque& queue, E object) { for (auto found = queue.cbegin(), end = queue.cend(); found != end; found++) { if (*found == object) { queue.erase(found); - return static_cast(object); + return static_cast(object); } } - return nullptr; + return {}; } template diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp index 416f836978..20a1496998 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -13,7 +13,17 @@ LOG_CHANNEL(sys_timer); -void lv2_timer_context::operator()() +struct lv2_timer_thread +{ + shared_mutex mutex; + std::deque> timers; + + void operator()(); + + static constexpr auto thread_name = "Timer Thread"sv; +}; + +u64 lv2_timer::check() { while (thread_ctrl::state() != thread_state::aborting) { @@ -49,15 +59,48 @@ void lv2_timer_context::operator()() // Stop after oneshot state.release(SYS_TIMER_STATE_STOP); - continue; + break; } - // TODO: use single global dedicated thread for busy waiting, no timer threads - lv2_obj::wait_timeout(next - _now); - continue; + return (next - _now); } - thread_ctrl::wait_on(state, _state); + break; + } + + return umax; +} + +void lv2_timer_thread::operator()() +{ + u64 sleep_time = umax; + + while (thread_ctrl::state() != thread_state::aborting) + { + if (sleep_time != umax) + { + // Scale time + sleep_time = std::min(sleep_time, u64{umax} / 100) * 100 / g_cfg.core.clocks_scale; + } + + thread_ctrl::wait_for(sleep_time); + + sleep_time = umax; + + reader_lock lock(mutex); + + for (const auto& timer : timers) + { + if (lv2_obj::check(timer)) + { + const u64 adviced_sleep_time = timer->check(); + + if (sleep_time > adviced_sleep_time) + { + sleep_time = adviced_sleep_time; + } + } + } } } @@ -67,9 +110,15 @@ error_code sys_timer_create(ppu_thread& ppu, vm::ptr timer_id) sys_timer.warning("sys_timer_create(timer_id=*0x%x)", timer_id); - if (const u32 id = idm::make("Timer Thread")) + if (auto ptr = idm::make_ptr()) { - *timer_id = id; + auto& thread = g_fxo->get>(); + { + std::lock_guard lock(thread.mutex); + thread.timers.emplace_back(std::move(ptr)); + } + + *timer_id = idm::last_id(); return CELL_OK; } @@ -82,14 +131,14 @@ error_code sys_timer_destroy(ppu_thread& ppu, u32 timer_id) sys_timer.warning("sys_timer_destroy(timer_id=0x%x)", timer_id); - const auto timer = idm::withdraw(timer_id, [&](lv2_timer& timer) -> CellError + auto timer = idm::withdraw(timer_id, [&](lv2_timer& timer) -> CellError { if (reader_lock lock(timer.mutex); lv2_obj::check(timer.port)) { return CELL_EISCONN; } - timer = thread_state::aborting; + timer.exists--; return {}; }); @@ -103,6 +152,9 @@ error_code sys_timer_destroy(ppu_thread& ppu, u32 timer_id) return timer.ret; } + auto& thread = g_fxo->get>(); + std::lock_guard lock(thread.mutex); + lv2_obj::unqueue(thread.timers, std::move(timer.ptr)); return CELL_OK; } @@ -144,7 +196,7 @@ error_code _sys_timer_start(ppu_thread& ppu, u32 timer_id, u64 base_time, u64 pe const auto timer = idm::check(timer_id, [&](lv2_timer& timer) -> CellError { - std::unique_lock lock(timer.mutex); + std::lock_guard lock(timer.mutex); if (!lv2_obj::check(timer.port)) { @@ -167,9 +219,6 @@ error_code _sys_timer_start(ppu_thread& ppu, u32 timer_id, u64 base_time, u64 pe timer.expire = expire > start_time ? expire : umax; timer.period = period; timer.state = SYS_TIMER_STATE_RUN; - - lock.unlock(); - timer.state.notify_one(); return {}; }); @@ -188,6 +237,8 @@ error_code _sys_timer_start(ppu_thread& ppu, u32 timer_id, u64 base_time, u64 pe return timer.ret; } + g_fxo->get>()([]{}); + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.h b/rpcs3/Emu/Cell/lv2/sys_timer.h index e9f17ae60c..e8a85b5dd3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.h +++ b/rpcs3/Emu/Cell/lv2/sys_timer.h @@ -21,12 +21,10 @@ struct sys_timer_information_t be_t pad; }; -struct lv2_timer_context : lv2_obj +struct lv2_timer : lv2_obj { static const u32 id_base = 0x11000000; - void operator()(); - shared_mutex mutex; atomic_t state{SYS_TIMER_STATE_STOP}; @@ -38,6 +36,13 @@ struct lv2_timer_context : lv2_obj atomic_t expire{0}; // Next expiration time atomic_t period{0}; // Period (oneshot if 0) + u64 check(); + + lv2_timer() noexcept + : lv2_obj{1} + { + } + void get_information(sys_timer_information_t& info) { reader_lock lock(mutex); @@ -57,8 +62,6 @@ struct lv2_timer_context : lv2_obj } }; -using lv2_timer = named_thread; - class ppu_thread; // Syscalls