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.
This commit is contained in:
Eladash 2020-02-29 16:15:25 +02:00 committed by GitHub
parent 8e5a03f171
commit 50f51be06a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 24 additions and 8 deletions

View File

@ -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<sys_
const auto timer = idm::check<lv2_obj, lv2_timer>(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 {};
});