summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-26 22:26:53 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:35:17 -0400
commitd4ebb510a05d29befde6556e632413e5b35b9ab5 (patch)
tree309755a4ef21b48f12cca6c40798dccd191cf860 /src/core/hle/kernel/svc.cpp
parentSVC: Cleanup old methods. (diff)
downloadyuzu-d4ebb510a05d29befde6556e632413e5b35b9ab5.tar.gz
yuzu-d4ebb510a05d29befde6556e632413e5b35b9ab5.tar.xz
yuzu-d4ebb510a05d29befde6556e632413e5b35b9ab5.zip
SVC: Correct WaitSynchronization, WaitProcessWideKey, SignalProcessWideKey.
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp75
1 files changed, 48 insertions, 27 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 8634d3feb..a5193063b 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1541,33 +1541,50 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
1541 return ERR_INVALID_ADDRESS; 1541 return ERR_INVALID_ADDRESS;
1542 } 1542 }
1543 1543
1544 UNIMPLEMENTED();
1545
1546 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); 1544 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
1547 1545 auto& kernel = system.Kernel();
1546 Handle event_handle;
1547 Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
1548 auto* const current_process = system.Kernel().CurrentProcess(); 1548 auto* const current_process = system.Kernel().CurrentProcess();
1549 const auto& handle_table = current_process->GetHandleTable(); 1549 {
1550 std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1550 SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds);
1551 ASSERT(thread); 1551 const auto& handle_table = current_process->GetHandleTable();
1552 std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1553 ASSERT(thread);
1554
1555 current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
1556
1557 const auto release_result = current_process->GetMutex().Release(mutex_addr);
1558 if (release_result.IsError()) {
1559 lock.CancelSleep();
1560 return release_result;
1561 }
1552 1562
1553 const auto release_result = current_process->GetMutex().Release(mutex_addr); 1563 if (nano_seconds == 0) {
1554 if (release_result.IsError()) { 1564 lock.CancelSleep();
1555 return release_result; 1565 return RESULT_TIMEOUT;
1566 }
1567
1568 current_thread->SetCondVarWaitAddress(condition_variable_addr);
1569 current_thread->SetMutexWaitAddress(mutex_addr);
1570 current_thread->SetWaitHandle(thread_handle);
1571 current_thread->SetStatus(ThreadStatus::WaitCondVar);
1572 current_process->InsertConditionVariableThread(SharedFrom(current_thread));
1556 } 1573 }
1557 1574
1558 Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); 1575 if (event_handle != InvalidHandle) {
1559 current_thread->SetCondVarWaitAddress(condition_variable_addr); 1576 auto& time_manager = kernel.TimeManager();
1560 current_thread->SetMutexWaitAddress(mutex_addr); 1577 time_manager.UnscheduleTimeEvent(event_handle);
1561 current_thread->SetWaitHandle(thread_handle); 1578 }
1562 current_thread->SetStatus(ThreadStatus::WaitCondVar);
1563 current_thread->InvalidateWakeupCallback();
1564 current_process->InsertConditionVariableThread(SharedFrom(current_thread));
1565 1579
1566 current_thread->WakeAfterDelay(nano_seconds); 1580 {
1581 SchedulerLock lock(kernel);
1567 1582
1583 current_process->RemoveConditionVariableThread(SharedFrom(current_thread));
1584 }
1568 // Note: Deliberately don't attempt to inherit the lock owner's priority. 1585 // Note: Deliberately don't attempt to inherit the lock owner's priority.
1569 1586
1570 return RESULT_SUCCESS; 1587 return current_thread->GetSignalingResult();
1571} 1588}
1572 1589
1573/// Signal process wide key 1590/// Signal process wide key
@@ -1577,10 +1594,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
1577 1594
1578 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); 1595 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
1579 1596
1580 UNIMPLEMENTED();
1581
1582 // Retrieve a list of all threads that are waiting for this condition variable. 1597 // Retrieve a list of all threads that are waiting for this condition variable.
1583 auto* const current_process = system.Kernel().CurrentProcess(); 1598 auto& kernel = system.Kernel();
1599 SchedulerLock lock(kernel);
1600 auto* const current_process = kernel.CurrentProcess();
1584 std::vector<std::shared_ptr<Thread>> waiting_threads = 1601 std::vector<std::shared_ptr<Thread>> waiting_threads =
1585 current_process->GetConditionVariableThreads(condition_variable_addr); 1602 current_process->GetConditionVariableThreads(condition_variable_addr);
1586 1603
@@ -1589,10 +1606,18 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
1589 std::size_t last = waiting_threads.size(); 1606 std::size_t last = waiting_threads.size();
1590 if (target > 0) 1607 if (target > 0)
1591 last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); 1608 last = std::min(waiting_threads.size(), static_cast<std::size_t>(target));
1592 1609 auto& time_manager = kernel.TimeManager();
1593 for (std::size_t index = 0; index < last; ++index) { 1610 for (std::size_t index = 0; index < last; ++index) {
1594 auto& thread = waiting_threads[index]; 1611 auto& thread = waiting_threads[index];
1595 1612
1613 if (thread->GetStatus() != ThreadStatus::WaitCondVar) {
1614 last++;
1615 last = std::min(waiting_threads.size(), last);
1616 continue;
1617 }
1618
1619 time_manager.CancelTimeEvent(thread.get());
1620
1596 ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); 1621 ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
1597 1622
1598 // liberate Cond Var Thread. 1623 // liberate Cond Var Thread.
@@ -1630,17 +1655,13 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
1630 } 1655 }
1631 1656
1632 thread->SetLockOwner(nullptr); 1657 thread->SetLockOwner(nullptr);
1633 thread->SetMutexWaitAddress(0); 1658 thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
1634 thread->SetWaitHandle(0);
1635 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
1636 } else { 1659 } else {
1637 // The mutex is already owned by some other thread, make this thread wait on it. 1660 // The mutex is already owned by some other thread, make this thread wait on it.
1638 const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); 1661 const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
1639 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1662 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1640 auto owner = handle_table.Get<Thread>(owner_handle); 1663 auto owner = handle_table.Get<Thread>(owner_handle);
1641 ASSERT(owner); 1664 ASSERT(owner);
1642 ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
1643 thread->InvalidateWakeupCallback();
1644 thread->SetStatus(ThreadStatus::WaitMutex); 1665 thread->SetStatus(ThreadStatus::WaitMutex);
1645 1666
1646 owner->AddMutexWaiter(thread); 1667 owner->AddMutexWaiter(thread);