From 50f51be06a4c2105ec7556a8e80d5e7b8506dcaf Mon Sep 17 00:00:00 2001 From: Eladash Date: Sat, 29 Feb 2020 16:15:25 +0200 Subject: [PATCH] Improve sys_timer_get_information (#7638) * Improve sys_timer_get_information * sys_timer_disconnect_event_queue sets STATE_STOP regardless of port connection status. * sys_timer_get_information sets 0 for period and next_expire if the timer is stopped. * Fix two minor races in lv2_timer thread * If the timer thread is about to fire an event of queue x, then another thread disconnects the queue, then restarts the timer and connects the event queue, then the timer thread sends an event - event data combination (source, data1, data2, next) may be inaccurate. * If the timer thread is about to send an event (periodically), then another thread stops the timer and starts it again with sys_timer_start_periodic_absolute, timer.expire in info->timer_state in sys_timer_get_information may be inaccurate. --- rpcs3/Emu/Cell/lv2/sys_timer.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp index abf34c076c..073ce21927 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -21,12 +21,18 @@ void lv2_timer_context::operator()() if (state == SYS_TIMER_STATE_RUN) { const u64 _now = get_guest_system_time(); - const u64 next = expire; + u64 next = expire; if (_now >= next) { std::lock_guard lock(mutex); + if (next = expire; _now < next) + { + // expire was updated in the middle, don't send an event + continue; + } + if (const auto queue = port.lock()) { queue->send(source, data1, data2, next); @@ -34,7 +40,7 @@ void lv2_timer_context::operator()() if (period) { - // Set next expiration time and check again (HACK) + // Set next expiration time and check again expire += period; continue; } @@ -49,7 +55,7 @@ void lv2_timer_context::operator()() continue; } - thread_ctrl::wait_for(10000); + thread_ctrl::wait(); } } @@ -106,11 +112,20 @@ error_code sys_timer_get_information(ppu_thread& ppu, u32 timer_id, vm::ptr(timer_id, [&](lv2_timer& timer) { - std::lock_guard lock(timer.mutex); + std::shared_lock lock(timer.mutex); - info->next_expire = timer.expire; - info->period = timer.period; - info->timer_state = timer.state; + if (timer.state == SYS_TIMER_STATE_RUN) + { + info->timer_state = SYS_TIMER_STATE_RUN; + info->next_expire = timer.expire; + info->period = timer.period; + } + else + { + info->timer_state = SYS_TIMER_STATE_STOP; + info->next_expire = 0; + info->period = 0; + } }); if (!timer) @@ -252,12 +267,13 @@ error_code sys_timer_disconnect_event_queue(ppu_thread& ppu, u32 timer_id) { std::lock_guard lock(timer.mutex); + timer.state = SYS_TIMER_STATE_STOP; + if (timer.port.expired()) { return CELL_ENOTCONN; } - timer.state = SYS_TIMER_STATE_STOP; timer.port.reset(); return {}; });