summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
authorGravatar David2019-10-28 10:53:27 +1100
committerGravatar GitHub2019-10-28 10:53:27 +1100
commit4c5731c34f0915457a31c60c9f70a2f169ea575d (patch)
tree7f03a7f892370b59e56ae06c6c74514f1cc44998 /src/core/hle/kernel/svc.cpp
parentMerge pull request #3034 from ReinUsesLisp/w4244-maxwell3d (diff)
parentKernel Thread: Cleanup THREADPROCESSORID_DONT_UPDATE. (diff)
downloadyuzu-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.cpp99
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