Ensure that threads are ready before their preemption timer can be

armed.

It was discovered during testing of 'Hatsune Miku Project DIVA: Mega Mix'
that if a thread was starting while preemption was being enabled a NULL
pointer dereference could occur in the timer_settime call as
timer_create may not have been called yet.
This commit is contained in:
Billy Laws 2021-05-30 18:15:04 +01:00
parent a7dc69223b
commit af5ee96b9a

View File

@ -231,16 +231,25 @@ namespace skyline::kernel::type {
}
void KThread::ArmPreemptionTimer(std::chrono::nanoseconds timeToFire) {
struct itimerspec spec{.it_value = {
.tv_nsec = std::min(timeToFire.count(), static_cast<long long>(constant::NsInSecond)),
.tv_sec = std::max(std::chrono::duration_cast<std::chrono::seconds>(timeToFire).count() - 1, 0LL),
}};
timer_settime(preemptionTimer, 0, &spec, nullptr);
isPreempted = true;
std::unique_lock lock(statusMutex);
statusCondition.wait(lock, [this]() { return ready || killed; });
if (!killed && running) {
struct itimerspec spec{.it_value = {
.tv_nsec = std::min(timeToFire.count(), static_cast<long long>(constant::NsInSecond)),
.tv_sec = std::max(std::chrono::duration_cast<std::chrono::seconds>(timeToFire).count() - 1, 0LL),
}};
timer_settime(preemptionTimer, 0, &spec, nullptr);
isPreempted = true;
}
}
void KThread::DisarmPreemptionTimer() {
if (isPreempted) {
if (!isPreempted)
return;
std::unique_lock lock(statusMutex);
statusCondition.wait(lock, [this]() { return ready || killed; });
if (!killed && running) {
struct itimerspec spec{};
timer_settime(preemptionTimer, 0, &spec, nullptr);
isPreempted = false;