mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +00:00
lv2_timer: manage timers by separate thread (#10445)
Substitutes missing abort op for lv2_obj manager.
This commit is contained in:
parent
c3415bcff2
commit
24e4a43ec4
@ -108,20 +108,20 @@ public:
|
|||||||
return str;
|
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>
|
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++)
|
for (auto found = queue.cbegin(), end = queue.cend(); found != end; found++)
|
||||||
{
|
{
|
||||||
if (*found == object)
|
if (*found == object)
|
||||||
{
|
{
|
||||||
queue.erase(found);
|
queue.erase(found);
|
||||||
return static_cast<T*>(object);
|
return static_cast<T>(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename T>
|
template <typename E, typename T>
|
||||||
|
@ -13,7 +13,17 @@
|
|||||||
|
|
||||||
LOG_CHANNEL(sys_timer);
|
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)
|
while (thread_ctrl::state() != thread_state::aborting)
|
||||||
{
|
{
|
||||||
@ -49,15 +59,48 @@ void lv2_timer_context::operator()()
|
|||||||
|
|
||||||
// Stop after oneshot
|
// Stop after oneshot
|
||||||
state.release(SYS_TIMER_STATE_STOP);
|
state.release(SYS_TIMER_STATE_STOP);
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use single global dedicated thread for busy waiting, no timer threads
|
return (next - _now);
|
||||||
lv2_obj::wait_timeout(next - _now);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
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;
|
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);
|
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))
|
if (reader_lock lock(timer.mutex); lv2_obj::check(timer.port))
|
||||||
{
|
{
|
||||||
return CELL_EISCONN;
|
return CELL_EISCONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = thread_state::aborting;
|
timer.exists--;
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -103,6 +152,9 @@ error_code sys_timer_destroy(ppu_thread& ppu, u32 timer_id)
|
|||||||
return timer.ret;
|
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;
|
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
|
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))
|
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.expire = expire > start_time ? expire : umax;
|
||||||
timer.period = period;
|
timer.period = period;
|
||||||
timer.state = SYS_TIMER_STATE_RUN;
|
timer.state = SYS_TIMER_STATE_RUN;
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
timer.state.notify_one();
|
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -188,6 +237,8 @@ error_code _sys_timer_start(ppu_thread& ppu, u32 timer_id, u64 base_time, u64 pe
|
|||||||
return timer.ret;
|
return timer.ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_fxo->get<named_thread<lv2_timer_thread>>()([]{});
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,12 +21,10 @@ struct sys_timer_information_t
|
|||||||
be_t<u32> pad;
|
be_t<u32> pad;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lv2_timer_context : lv2_obj
|
struct lv2_timer : lv2_obj
|
||||||
{
|
{
|
||||||
static const u32 id_base = 0x11000000;
|
static const u32 id_base = 0x11000000;
|
||||||
|
|
||||||
void operator()();
|
|
||||||
|
|
||||||
shared_mutex mutex;
|
shared_mutex mutex;
|
||||||
atomic_t<u32> state{SYS_TIMER_STATE_STOP};
|
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> expire{0}; // Next expiration time
|
||||||
atomic_t<u64> period{0}; // Period (oneshot if 0)
|
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)
|
void get_information(sys_timer_information_t& info)
|
||||||
{
|
{
|
||||||
reader_lock lock(mutex);
|
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;
|
class ppu_thread;
|
||||||
|
|
||||||
// Syscalls
|
// Syscalls
|
||||||
|
Loading…
x
Reference in New Issue
Block a user