lv2_timer: manage timers by separate thread (#10445)

Substitutes missing abort op for lv2_obj manager.
This commit is contained in:
Eladash 2021-06-15 15:04:51 +03:00 committed by GitHub
parent c3415bcff2
commit 24e4a43ec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 23 deletions

View File

@ -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 <typename T, typename E>
static T* unqueue(std::deque<T*>& queue, E* object)
static T unqueue(std::deque<T>& queue, E object)
{
for (auto found = queue.cbegin(), end = queue.cend(); found != end; found++)
{
if (*found == object)
{
queue.erase(found);
return static_cast<T*>(object);
return static_cast<T>(object);
}
}
return nullptr;
return {};
}
template <typename E, typename T>

View File

@ -13,7 +13,17 @@
LOG_CHANNEL(sys_timer);
void lv2_timer_context::operator()()
struct lv2_timer_thread
{
shared_mutex mutex;
std::deque<std::shared_ptr<lv2_timer>> 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<u32> timer_id)
sys_timer.warning("sys_timer_create(timer_id=*0x%x)", timer_id);
if (const u32 id = idm::make<lv2_obj, lv2_timer>("Timer Thread"))
if (auto ptr = idm::make_ptr<lv2_obj, lv2_timer>())
{
*timer_id = id;
auto& thread = g_fxo->get<named_thread<lv2_timer_thread>>();
{
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<lv2_obj, lv2_timer>(timer_id, [&](lv2_timer& timer) -> CellError
auto timer = idm::withdraw<lv2_obj, lv2_timer>(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<named_thread<lv2_timer_thread>>();
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<lv2_obj, lv2_timer>(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<named_thread<lv2_timer_thread>>()([]{});
return CELL_OK;
}

View File

@ -21,12 +21,10 @@ struct sys_timer_information_t
be_t<u32> 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<u32> state{SYS_TIMER_STATE_STOP};
@ -38,6 +36,13 @@ struct lv2_timer_context : lv2_obj
atomic_t<u64> expire{0}; // Next expiration time
atomic_t<u64> 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<lv2_timer_context>;
class ppu_thread;
// Syscalls