kern: implement SvcWaitSynchronization

This commit is contained in:
Michael Scire 2020-07-09 17:21:47 -07:00
parent 16c9c53a4a
commit f52232f0f2
10 changed files with 211 additions and 59 deletions

View file

@ -20,7 +20,87 @@ namespace ams::kern {
Result KSynchronization::Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout) {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_UNIMPLEMENTED();
/* Allocate space on stack for thread iterators. */
KSynchronizationObject::iterator *thread_iters = static_cast<KSynchronizationObject::iterator *>(__builtin_alloca(sizeof(KSynchronizationObject::iterator) * num_objects));
/* Prepare for wait. */
KThread *thread = GetCurrentThreadPointer();
s32 sync_index = -1;
KHardwareTimer *timer;
{
/* Setup the scheduling lock and sleep. */
KScopedSchedulerLockAndSleep slp(std::addressof(timer), thread, timeout);
/* Check if any of the objects are already signaled. */
for (auto i = 0; i < num_objects; ++i) {
AMS_ASSERT(objects[i] != nullptr);
if (objects[i]->IsSignaled()) {
*out_index = i;
slp.CancelSleep();
return ResultSuccess();
}
}
/* Check if the timeout is zero. */
if (timeout == 0) {
slp.CancelSleep();
return svc::ResultTimedOut();
}
/* Check if the thread should terminate. */
if (thread->IsTerminationRequested()) {
slp.CancelSleep();
return svc::ResultTerminationRequested();
}
/* Check if waiting was canceled. */
if (thread->IsWaitCancelled()) {
slp.CancelSleep();
thread->ClearWaitCancelled();
return svc::ResultCancelled();
}
/* Add the waiters. */
for (auto i = 0; i < num_objects; ++i) {
thread_iters[i] = objects[i]->RegisterWaitingThread(thread);
}
/* Mark the thread as waiting. */
thread->SetCancellable();
thread->SetSyncedObject(nullptr, svc::ResultTimedOut());
thread->SetState(KThread::ThreadState_Waiting);
}
/* The lock/sleep is done, so we should be able to get our result. */
/* Thread is no longer cancellable. */
thread->ClearCancellable();
/* Cancel the timer as needed. */
if (timer != nullptr) {
timer->CancelTask(thread);
}
/* Get the wait result. */
Result wait_result;
{
KScopedSchedulerLock lk;
KSynchronizationObject *synced_obj;
wait_result = thread->GetWaitResult(std::addressof(synced_obj));
for (auto i = 0; i < num_objects; ++i) {
objects[i]->UnregisterWaitingThread(thread_iters[i]);
if (objects[i] == synced_obj) {
sync_index = i;
}
}
}
/* Set output. */
*out_index = sync_index;
return wait_result;
}
void KSynchronization::OnAvailable(KSynchronizationObject *object) {