Implement independent CPU preemptions

This commit is contained in:
Eladash 2022-09-06 18:59:23 +03:00 committed by kd-11
parent b9e20dc5c9
commit ec7b18dab5
12 changed files with 358 additions and 4 deletions

View file

@ -55,6 +55,8 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
case cpu_flag::memory: return "mem";
case cpu_flag::pending: return "pend";
case cpu_flag::pending_recheck: return "pend-re";
case cpu_flag::yield: return "y";
case cpu_flag::preempt: return "PREEMPT";
case cpu_flag::dbg_global_pause: return "G-PAUSE";
case cpu_flag::dbg_pause: return "PAUSE";
case cpu_flag::dbg_step: return "STEP";
@ -575,6 +577,7 @@ void cpu_thread::operator()()
if (!(state0 & cpu_flag::stop))
{
cpu_task();
state += cpu_flag::wait;
if (state & cpu_flag::ret && state.test_and_reset(cpu_flag::ret))
{
@ -731,7 +734,7 @@ bool cpu_thread::check_state() noexcept
if (!is_stopped(flags) && flags.none_of(cpu_flag::ret))
{
// Check pause flags which hold thread inside check_state (ignore suspend/debug flags on cpu_flag::temp)
if (flags & (cpu_flag::pause + cpu_flag::memory) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend)))
if (flags & (cpu_flag::pause + cpu_flag::memory + cpu_flag::yield + cpu_flag::preempt) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend)))
{
if (!(flags & cpu_flag::wait))
{
@ -739,6 +742,12 @@ bool cpu_thread::check_state() noexcept
store = true;
}
if (flags & (cpu_flag::yield + cpu_flag::preempt))
{
flags -= (cpu_flag::yield + cpu_flag::preempt);
store = true;
}
escape = false;
state1 = flags;
return store;
@ -768,6 +777,30 @@ bool cpu_thread::check_state() noexcept
return store;
}).first;
if (state0 & cpu_flag::preempt)
{
if (cpu_flag::wait - state0)
{
// Yield itself
state.wait(state1, atomic_wait_timeout{20'000});
}
if (const u128 bits = s_cpu_bits)
{
reader_lock lock(s_cpu_lock);
cpu_counter::for_all_cpu(bits & s_cpu_bits, [](cpu_thread* cpu)
{
if (cpu->state.none_of(cpu_flag::wait + cpu_flag::yield))
{
cpu->state += cpu_flag::yield;
}
return true;
});
}
}
if (escape)
{
if (s_tls_thread_slot == umax && !retval)
@ -856,6 +889,14 @@ bool cpu_thread::check_state() noexcept
break;
}
}
continue;
}
if (state0 & cpu_flag::yield && cpu_flag::wait - state0)
{
// Short sleep when yield flag is present alone (makes no sense when other methods which can stop thread execution have been done)
state.wait(state1, atomic_wait_timeout{20'000});
}
}
}