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) {

View File

@@ -42,13 +42,13 @@ namespace ams::kern {
MESOSPHERE_TODO("Do useful debug operation here.");
}
KSynchronizationObject::iterator KSynchronizationObject::AddWaiterThread(KThread *thread) {
KSynchronizationObject::iterator KSynchronizationObject::RegisterWaitingThread(KThread *thread) {
MESOSPHERE_ASSERT_THIS();
return this->thread_list.insert(this->thread_list.end(), *thread);
}
KSynchronizationObject::iterator KSynchronizationObject::RemoveWaiterThread(KSynchronizationObject::iterator it) {
KSynchronizationObject::iterator KSynchronizationObject::UnregisterWaitingThread(KSynchronizationObject::iterator it) {
MESOSPHERE_ASSERT_THIS();
return this->thread_list.erase(it);

View File

@@ -27,6 +27,58 @@ namespace ams::kern::svc {
return ResultSuccess();
}
Result WaitSynchronizationImpl(int32_t *out_index, KSynchronizationObject **objs, int32_t num_handles, int64_t timeout_ns) {
/* Convert the timeout from nanoseconds to ticks. */
s64 timeout;
if (timeout_ns > 0) {
u64 ticks = KHardwareTimer::GetTick();
ticks += ams::svc::Tick(TimeSpan::FromNanoSeconds(timeout_ns));
ticks += 2;
timeout = ticks;
} else {
timeout = timeout_ns;
}
return Kernel::GetSynchronization().Wait(out_index, objs, num_handles, timeout);
}
Result WaitSynchronization(int32_t *out_index, KUserPointer<const ams::svc::Handle *> user_handles, int32_t num_handles, int64_t timeout_ns) {
/* Ensure number of handles is valid. */
R_UNLESS(0 <= num_handles && num_handles <= ams::svc::ArgumentHandleCountMax, svc::ResultOutOfRange());
/* Get the synchronization context. */
auto &handle_table = GetCurrentProcess().GetHandleTable();
KSynchronizationObject **objs = GetCurrentThread().GetSynchronizationObjectBuffer();
ams::svc::Handle *handles = GetCurrentThread().GetHandleBuffer();
/* Copy user handles. */
if (num_handles > 0) {
/* Ensure that we can try to get the handles. */
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer());
/* Get the handles. */
R_TRY(user_handles.CopyArrayTo(handles, num_handles));
/* Convert the handles to objects. */
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs, handles, num_handles), svc::ResultInvalidHandle());
}
/* Ensure handles are closed when we're done. */
ON_SCOPE_EXIT {
for (auto i = 0; i < num_handles; ++i) {
objs[i]->Close();
}
};
/* Wait on the objects. */
R_TRY_CATCH(WaitSynchronizationImpl(out_index, objs, num_handles, timeout_ns)) {
R_CONVERT(svc::ResultSessionClosed, ResultSuccess())
} R_END_TRY_CATCH;
return ResultSuccess();
}
}
/* ============================= 64 ABI ============================= */
@@ -39,8 +91,10 @@ namespace ams::kern::svc {
MESOSPHERE_PANIC("Stubbed SvcResetSignal64 was called.");
}
Result WaitSynchronization64(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t numHandles, int64_t timeout_ns) {
MESOSPHERE_PANIC("Stubbed SvcWaitSynchronization64 was called.");
Result WaitSynchronization64(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, int64_t timeout_ns) {
Result result = WaitSynchronization(out_index, handles, num_handles, timeout_ns);
MESOSPHERE_LOG("WaitSynchronization returned %08x\n", result.GetValue());
return result;
}
Result CancelSynchronization64(ams::svc::Handle handle) {
@@ -61,8 +115,8 @@ namespace ams::kern::svc {
MESOSPHERE_PANIC("Stubbed SvcResetSignal64From32 was called.");
}
Result WaitSynchronization64From32(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t numHandles, int64_t timeout_ns) {
MESOSPHERE_PANIC("Stubbed SvcWaitSynchronization64From32 was called.");
Result WaitSynchronization64From32(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, int64_t timeout_ns) {
return WaitSynchronization(out_index, handles, num_handles, timeout_ns);
}
Result CancelSynchronization64From32(ams::svc::Handle handle) {