diff options
| author | 2019-10-28 10:53:27 +1100 | |
|---|---|---|
| committer | 2019-10-28 10:53:27 +1100 | |
| commit | 4c5731c34f0915457a31c60c9f70a2f169ea575d (patch) | |
| tree | 7f03a7f892370b59e56ae06c6c74514f1cc44998 /src/core/hle/kernel/svc.cpp | |
| parent | Merge pull request #3034 from ReinUsesLisp/w4244-maxwell3d (diff) | |
| parent | Kernel Thread: Cleanup THREADPROCESSORID_DONT_UPDATE. (diff) | |
| download | yuzu-4c5731c34f0915457a31c60c9f70a2f169ea575d.tar.gz yuzu-4c5731c34f0915457a31c60c9f70a2f169ea575d.tar.xz yuzu-4c5731c34f0915457a31c60c9f70a2f169ea575d.zip | |
Merge pull request #2971 from FernandoS27/new-scheduler-v2
Kernel: Implement a New Thread Scheduler V2
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 99 |
1 files changed, 52 insertions, 47 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1fd1a732a..f64236be1 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -516,7 +516,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr | |||
| 516 | thread->WakeAfterDelay(nano_seconds); | 516 | thread->WakeAfterDelay(nano_seconds); |
| 517 | thread->SetWakeupCallback(DefaultThreadWakeupCallback); | 517 | thread->SetWakeupCallback(DefaultThreadWakeupCallback); |
| 518 | 518 | ||
| 519 | system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 519 | system.PrepareReschedule(thread->GetProcessorID()); |
| 520 | 520 | ||
| 521 | return RESULT_TIMEOUT; | 521 | return RESULT_TIMEOUT; |
| 522 | } | 522 | } |
| @@ -534,6 +534,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand | |||
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | thread->CancelWait(); | 536 | thread->CancelWait(); |
| 537 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 537 | return RESULT_SUCCESS; | 538 | return RESULT_SUCCESS; |
| 538 | } | 539 | } |
| 539 | 540 | ||
| @@ -1066,6 +1067,8 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act | |||
| 1066 | } | 1067 | } |
| 1067 | 1068 | ||
| 1068 | thread->SetActivity(static_cast<ThreadActivity>(activity)); | 1069 | thread->SetActivity(static_cast<ThreadActivity>(activity)); |
| 1070 | |||
| 1071 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 1069 | return RESULT_SUCCESS; | 1072 | return RESULT_SUCCESS; |
| 1070 | } | 1073 | } |
| 1071 | 1074 | ||
| @@ -1147,7 +1150,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri | |||
| 1147 | 1150 | ||
| 1148 | thread->SetPriority(priority); | 1151 | thread->SetPriority(priority); |
| 1149 | 1152 | ||
| 1150 | system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 1153 | system.PrepareReschedule(thread->GetProcessorID()); |
| 1151 | return RESULT_SUCCESS; | 1154 | return RESULT_SUCCESS; |
| 1152 | } | 1155 | } |
| 1153 | 1156 | ||
| @@ -1503,7 +1506,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1503 | thread->SetName( | 1506 | thread->SetName( |
| 1504 | fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); | 1507 | fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); |
| 1505 | 1508 | ||
| 1506 | system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 1509 | system.PrepareReschedule(thread->GetProcessorID()); |
| 1507 | 1510 | ||
| 1508 | return RESULT_SUCCESS; | 1511 | return RESULT_SUCCESS; |
| 1509 | } | 1512 | } |
| @@ -1525,7 +1528,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { | |||
| 1525 | thread->ResumeFromWait(); | 1528 | thread->ResumeFromWait(); |
| 1526 | 1529 | ||
| 1527 | if (thread->GetStatus() == ThreadStatus::Ready) { | 1530 | if (thread->GetStatus() == ThreadStatus::Ready) { |
| 1528 | system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 1531 | system.PrepareReschedule(thread->GetProcessorID()); |
| 1529 | } | 1532 | } |
| 1530 | 1533 | ||
| 1531 | return RESULT_SUCCESS; | 1534 | return RESULT_SUCCESS; |
| @@ -1537,7 +1540,7 @@ static void ExitThread(Core::System& system) { | |||
| 1537 | 1540 | ||
| 1538 | auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); | 1541 | auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); |
| 1539 | current_thread->Stop(); | 1542 | current_thread->Stop(); |
| 1540 | system.CurrentScheduler().RemoveThread(current_thread); | 1543 | system.GlobalScheduler().RemoveThread(current_thread); |
| 1541 | system.PrepareReschedule(); | 1544 | system.PrepareReschedule(); |
| 1542 | } | 1545 | } |
| 1543 | 1546 | ||
| @@ -1553,17 +1556,18 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { | |||
| 1553 | 1556 | ||
| 1554 | auto& scheduler = system.CurrentScheduler(); | 1557 | auto& scheduler = system.CurrentScheduler(); |
| 1555 | auto* const current_thread = scheduler.GetCurrentThread(); | 1558 | auto* const current_thread = scheduler.GetCurrentThread(); |
| 1559 | bool is_redundant = false; | ||
| 1556 | 1560 | ||
| 1557 | if (nanoseconds <= 0) { | 1561 | if (nanoseconds <= 0) { |
| 1558 | switch (static_cast<SleepType>(nanoseconds)) { | 1562 | switch (static_cast<SleepType>(nanoseconds)) { |
| 1559 | case SleepType::YieldWithoutLoadBalancing: | 1563 | case SleepType::YieldWithoutLoadBalancing: |
| 1560 | scheduler.YieldWithoutLoadBalancing(current_thread); | 1564 | is_redundant = current_thread->YieldSimple(); |
| 1561 | break; | 1565 | break; |
| 1562 | case SleepType::YieldWithLoadBalancing: | 1566 | case SleepType::YieldWithLoadBalancing: |
| 1563 | scheduler.YieldWithLoadBalancing(current_thread); | 1567 | is_redundant = current_thread->YieldAndBalanceLoad(); |
| 1564 | break; | 1568 | break; |
| 1565 | case SleepType::YieldAndWaitForLoadBalancing: | 1569 | case SleepType::YieldAndWaitForLoadBalancing: |
| 1566 | scheduler.YieldAndWaitForLoadBalancing(current_thread); | 1570 | is_redundant = current_thread->YieldAndWaitForLoadBalancing(); |
| 1567 | break; | 1571 | break; |
| 1568 | default: | 1572 | default: |
| 1569 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | 1573 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); |
| @@ -1572,10 +1576,13 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { | |||
| 1572 | current_thread->Sleep(nanoseconds); | 1576 | current_thread->Sleep(nanoseconds); |
| 1573 | } | 1577 | } |
| 1574 | 1578 | ||
| 1575 | // Reschedule all CPU cores | 1579 | if (is_redundant) { |
| 1576 | for (std::size_t i = 0; i < Core::NUM_CPU_CORES; ++i) { | 1580 | // If it's redundant, the core is pretty much idle. Some games keep idling |
| 1577 | system.CpuCore(i).PrepareReschedule(); | 1581 | // a core while it's doing nothing, we advance timing to avoid costly continuous |
| 1582 | // calls. | ||
| 1583 | system.CoreTiming().AddTicks(2000); | ||
| 1578 | } | 1584 | } |
| 1585 | system.PrepareReschedule(current_thread->GetProcessorID()); | ||
| 1579 | } | 1586 | } |
| 1580 | 1587 | ||
| 1581 | /// Wait process wide key atomic | 1588 | /// Wait process wide key atomic |
| @@ -1601,6 +1608,8 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1601 | return ERR_INVALID_ADDRESS; | 1608 | return ERR_INVALID_ADDRESS; |
| 1602 | } | 1609 | } |
| 1603 | 1610 | ||
| 1611 | ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); | ||
| 1612 | |||
| 1604 | auto* const current_process = system.Kernel().CurrentProcess(); | 1613 | auto* const current_process = system.Kernel().CurrentProcess(); |
| 1605 | const auto& handle_table = current_process->GetHandleTable(); | 1614 | const auto& handle_table = current_process->GetHandleTable(); |
| 1606 | SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1615 | SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| @@ -1622,7 +1631,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1622 | 1631 | ||
| 1623 | // Note: Deliberately don't attempt to inherit the lock owner's priority. | 1632 | // Note: Deliberately don't attempt to inherit the lock owner's priority. |
| 1624 | 1633 | ||
| 1625 | system.CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); | 1634 | system.PrepareReschedule(current_thread->GetProcessorID()); |
| 1626 | return RESULT_SUCCESS; | 1635 | return RESULT_SUCCESS; |
| 1627 | } | 1636 | } |
| 1628 | 1637 | ||
| @@ -1632,24 +1641,19 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var | |||
| 1632 | LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", | 1641 | LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", |
| 1633 | condition_variable_addr, target); | 1642 | condition_variable_addr, target); |
| 1634 | 1643 | ||
| 1635 | const auto RetrieveWaitingThreads = [&system](std::size_t core_index, | 1644 | ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); |
| 1636 | std::vector<SharedPtr<Thread>>& waiting_threads, | ||
| 1637 | VAddr condvar_addr) { | ||
| 1638 | const auto& scheduler = system.Scheduler(core_index); | ||
| 1639 | const auto& thread_list = scheduler.GetThreadList(); | ||
| 1640 | |||
| 1641 | for (const auto& thread : thread_list) { | ||
| 1642 | if (thread->GetCondVarWaitAddress() == condvar_addr) | ||
| 1643 | waiting_threads.push_back(thread); | ||
| 1644 | } | ||
| 1645 | }; | ||
| 1646 | 1645 | ||
| 1647 | // Retrieve a list of all threads that are waiting for this condition variable. | 1646 | // Retrieve a list of all threads that are waiting for this condition variable. |
| 1648 | std::vector<SharedPtr<Thread>> waiting_threads; | 1647 | std::vector<SharedPtr<Thread>> waiting_threads; |
| 1649 | RetrieveWaitingThreads(0, waiting_threads, condition_variable_addr); | 1648 | const auto& scheduler = system.GlobalScheduler(); |
| 1650 | RetrieveWaitingThreads(1, waiting_threads, condition_variable_addr); | 1649 | const auto& thread_list = scheduler.GetThreadList(); |
| 1651 | RetrieveWaitingThreads(2, waiting_threads, condition_variable_addr); | 1650 | |
| 1652 | RetrieveWaitingThreads(3, waiting_threads, condition_variable_addr); | 1651 | for (const auto& thread : thread_list) { |
| 1652 | if (thread->GetCondVarWaitAddress() == condition_variable_addr) { | ||
| 1653 | waiting_threads.push_back(thread); | ||
| 1654 | } | ||
| 1655 | } | ||
| 1656 | |||
| 1653 | // Sort them by priority, such that the highest priority ones come first. | 1657 | // Sort them by priority, such that the highest priority ones come first. |
| 1654 | std::sort(waiting_threads.begin(), waiting_threads.end(), | 1658 | std::sort(waiting_threads.begin(), waiting_threads.end(), |
| 1655 | [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { | 1659 | [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { |
| @@ -1679,18 +1683,20 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var | |||
| 1679 | 1683 | ||
| 1680 | // Atomically read the value of the mutex. | 1684 | // Atomically read the value of the mutex. |
| 1681 | u32 mutex_val = 0; | 1685 | u32 mutex_val = 0; |
| 1686 | u32 update_val = 0; | ||
| 1687 | const VAddr mutex_address = thread->GetMutexWaitAddress(); | ||
| 1682 | do { | 1688 | do { |
| 1683 | monitor.SetExclusive(current_core, thread->GetMutexWaitAddress()); | 1689 | monitor.SetExclusive(current_core, mutex_address); |
| 1684 | 1690 | ||
| 1685 | // If the mutex is not yet acquired, acquire it. | 1691 | // If the mutex is not yet acquired, acquire it. |
| 1686 | mutex_val = Memory::Read32(thread->GetMutexWaitAddress()); | 1692 | mutex_val = Memory::Read32(mutex_address); |
| 1687 | 1693 | ||
| 1688 | if (mutex_val != 0) { | 1694 | if (mutex_val != 0) { |
| 1689 | monitor.ClearExclusive(); | 1695 | update_val = mutex_val | Mutex::MutexHasWaitersFlag; |
| 1690 | break; | 1696 | } else { |
| 1697 | update_val = thread->GetWaitHandle(); | ||
| 1691 | } | 1698 | } |
| 1692 | } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(), | 1699 | } while (!monitor.ExclusiveWrite32(current_core, mutex_address, update_val)); |
| 1693 | thread->GetWaitHandle())); | ||
| 1694 | if (mutex_val == 0) { | 1700 | if (mutex_val == 0) { |
| 1695 | // We were able to acquire the mutex, resume this thread. | 1701 | // We were able to acquire the mutex, resume this thread. |
| 1696 | ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); | 1702 | ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); |
| @@ -1704,20 +1710,9 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var | |||
| 1704 | thread->SetLockOwner(nullptr); | 1710 | thread->SetLockOwner(nullptr); |
| 1705 | thread->SetMutexWaitAddress(0); | 1711 | thread->SetMutexWaitAddress(0); |
| 1706 | thread->SetWaitHandle(0); | 1712 | thread->SetWaitHandle(0); |
| 1707 | system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 1713 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); |
| 1714 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 1708 | } else { | 1715 | } else { |
| 1709 | // Atomically signal that the mutex now has a waiting thread. | ||
| 1710 | do { | ||
| 1711 | monitor.SetExclusive(current_core, thread->GetMutexWaitAddress()); | ||
| 1712 | |||
| 1713 | // Ensure that the mutex value is still what we expect. | ||
| 1714 | u32 value = Memory::Read32(thread->GetMutexWaitAddress()); | ||
| 1715 | // TODO(Subv): When this happens, the kernel just clears the exclusive state and | ||
| 1716 | // retries the initial read for this thread. | ||
| 1717 | ASSERT_MSG(mutex_val == value, "Unhandled synchronization primitive case"); | ||
| 1718 | } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(), | ||
| 1719 | mutex_val | Mutex::MutexHasWaitersFlag)); | ||
| 1720 | |||
| 1721 | // The mutex is already owned by some other thread, make this thread wait on it. | 1716 | // The mutex is already owned by some other thread, make this thread wait on it. |
| 1722 | const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); | 1717 | const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); |
| 1723 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1718 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| @@ -1728,6 +1723,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var | |||
| 1728 | thread->SetStatus(ThreadStatus::WaitMutex); | 1723 | thread->SetStatus(ThreadStatus::WaitMutex); |
| 1729 | 1724 | ||
| 1730 | owner->AddMutexWaiter(thread); | 1725 | owner->AddMutexWaiter(thread); |
| 1726 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 1731 | } | 1727 | } |
| 1732 | } | 1728 | } |
| 1733 | 1729 | ||
| @@ -1754,7 +1750,12 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, | |||
| 1754 | 1750 | ||
| 1755 | const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type); | 1751 | const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type); |
| 1756 | auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); | 1752 | auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); |
| 1757 | return address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); | 1753 | const ResultCode result = |
| 1754 | address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); | ||
| 1755 | if (result == RESULT_SUCCESS) { | ||
| 1756 | system.PrepareReschedule(); | ||
| 1757 | } | ||
| 1758 | return result; | ||
| 1758 | } | 1759 | } |
| 1759 | 1760 | ||
| 1760 | // Signals to an address (via Address Arbiter) | 1761 | // Signals to an address (via Address Arbiter) |
| @@ -2040,7 +2041,10 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, | |||
| 2040 | return ERR_INVALID_HANDLE; | 2041 | return ERR_INVALID_HANDLE; |
| 2041 | } | 2042 | } |
| 2042 | 2043 | ||
| 2044 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 2043 | thread->ChangeCore(core, affinity_mask); | 2045 | thread->ChangeCore(core, affinity_mask); |
| 2046 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 2047 | |||
| 2044 | return RESULT_SUCCESS; | 2048 | return RESULT_SUCCESS; |
| 2045 | } | 2049 | } |
| 2046 | 2050 | ||
| @@ -2151,6 +2155,7 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) { | |||
| 2151 | } | 2155 | } |
| 2152 | 2156 | ||
| 2153 | writable_event->Signal(); | 2157 | writable_event->Signal(); |
| 2158 | system.PrepareReschedule(); | ||
| 2154 | return RESULT_SUCCESS; | 2159 | return RESULT_SUCCESS; |
| 2155 | } | 2160 | } |
| 2156 | 2161 | ||