| 
									
										
										
										
											2018-06-21 00:49:43 -06:00
										 |  |  | // Copyright 2018 yuzu emulator team
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 08:06:09 -04:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-21 00:49:43 -06:00
										 |  |  | #include "common/assert.h"
 | 
					
						
							|  |  |  | #include "common/common_types.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  | #include "core/arm/exclusive_monitor.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-21 01:40:29 -06:00
										 |  |  | #include "core/core.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | #include "core/hle/kernel/address_arbiter.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-21 01:40:29 -06:00
										 |  |  | #include "core/hle/kernel/errors.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  | #include "core/hle/kernel/handle_table.h"
 | 
					
						
							|  |  |  | #include "core/hle/kernel/kernel.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-31 12:21:34 -04:00
										 |  |  | #include "core/hle/kernel/scheduler.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-21 00:49:43 -06:00
										 |  |  | #include "core/hle/kernel/thread.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  | #include "core/hle/kernel/time_manager.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-31 08:06:09 -04:00
										 |  |  | #include "core/hle/result.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-21 00:49:43 -06:00
										 |  |  | #include "core/memory.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | namespace Kernel { | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | // Wake up num_to_wake (or all) threads in a vector.
 | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  | void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, | 
					
						
							|  |  |  |                                  s32 num_to_wake) { | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
 | 
					
						
							|  |  |  |     // them all.
 | 
					
						
							| 
									
										
										
										
											2018-09-15 15:21:06 +02:00
										 |  |  |     std::size_t last = waiting_threads.size(); | 
					
						
							| 
									
										
										
										
											2019-03-05 12:22:13 -05:00
										 |  |  |     if (num_to_wake > 0) { | 
					
						
							| 
									
										
										
										
											2019-03-13 19:04:40 -04:00
										 |  |  |         last = std::min(last, static_cast<std::size_t>(num_to_wake)); | 
					
						
							| 
									
										
										
										
											2019-03-05 12:22:13 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Signal the waiting threads.
 | 
					
						
							| 
									
										
										
										
											2018-09-15 15:21:06 +02:00
										 |  |  |     for (std::size_t i = 0; i < last; i++) { | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |         waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS); | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  |         RemoveThread(waiting_threads[i]); | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |         waiting_threads[i]->WaitForArbitration(false); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |         waiting_threads[i]->ResumeFromWait(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-05 12:28:10 -05:00
										 |  |  | AddressArbiter::AddressArbiter(Core::System& system) : system{system} {} | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | AddressArbiter::~AddressArbiter() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-07 18:42:44 -05:00
										 |  |  | ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 value, | 
					
						
							|  |  |  |                                            s32 num_to_wake) { | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |     case SignalType::Signal: | 
					
						
							|  |  |  |         return SignalToAddressOnly(address, num_to_wake); | 
					
						
							|  |  |  |     case SignalType::IncrementAndSignalIfEqual: | 
					
						
							|  |  |  |         return IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); | 
					
						
							|  |  |  |     case SignalType::ModifyByWaitingCountAndSignalIfEqual: | 
					
						
							|  |  |  |         return ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, num_to_wake); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return ERR_INVALID_ENUM_VALUE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     SchedulerLock lock(system.Kernel()); | 
					
						
							| 
									
										
										
										
											2019-11-24 20:15:51 -05:00
										 |  |  |     const std::vector<std::shared_ptr<Thread>> waiting_threads = | 
					
						
							|  |  |  |         GetThreadsWaitingOnAddress(address); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     WakeThreads(waiting_threads, num_to_wake); | 
					
						
							|  |  |  |     return RESULT_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, | 
					
						
							|  |  |  |                                                               s32 num_to_wake) { | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     SchedulerLock lock(system.Kernel()); | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |     auto& memory = system.Memory(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     // Ensure that we can write to the address.
 | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |     if (!memory.IsValidVirtualAddress(address)) { | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |         return ERR_INVALID_ADDRESS_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     const std::size_t current_core = system.CurrentCoreIndex(); | 
					
						
							|  |  |  |     auto& monitor = system.Monitor(); | 
					
						
							|  |  |  |     u32 current_value; | 
					
						
							|  |  |  |     do { | 
					
						
							| 
									
										
										
										
											2020-03-15 15:54:40 -04:00
										 |  |  |         current_value = monitor.ExclusiveRead32(current_core, address); | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 15:07:17 -04:00
										 |  |  |         if (current_value != static_cast<u32>(value)) { | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |             return ERR_INVALID_STATE; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         current_value++; | 
					
						
							|  |  |  |     } while (!monitor.ExclusiveWrite32(current_core, address, current_value)); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-07 18:42:44 -05:00
										 |  |  |     return SignalToAddressOnly(address, num_to_wake); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, | 
					
						
							|  |  |  |                                                                          s32 num_to_wake) { | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     SchedulerLock lock(system.Kernel()); | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |     auto& memory = system.Memory(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     // Ensure that we can write to the address.
 | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |     if (!memory.IsValidVirtualAddress(address)) { | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |         return ERR_INVALID_ADDRESS_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Get threads waiting on the address.
 | 
					
						
							| 
									
										
										
										
											2019-11-24 20:15:51 -05:00
										 |  |  |     const std::vector<std::shared_ptr<Thread>> waiting_threads = | 
					
						
							|  |  |  |         GetThreadsWaitingOnAddress(address); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     const std::size_t current_core = system.CurrentCoreIndex(); | 
					
						
							|  |  |  |     auto& monitor = system.Monitor(); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     s32 updated_value; | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     do { | 
					
						
							| 
									
										
										
										
											2020-03-15 15:54:40 -04:00
										 |  |  |         updated_value = monitor.ExclusiveRead32(current_core, address); | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (updated_value != value) { | 
					
						
							|  |  |  |             return ERR_INVALID_STATE; | 
					
						
							| 
									
										
										
										
											2019-10-07 19:09:57 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |         // Determine the modified value depending on the waiting count.
 | 
					
						
							|  |  |  |         if (num_to_wake <= 0) { | 
					
						
							|  |  |  |             if (waiting_threads.empty()) { | 
					
						
							|  |  |  |                 updated_value = value + 1; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 updated_value = value - 1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-10-07 19:09:57 -04:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |             if (waiting_threads.empty()) { | 
					
						
							|  |  |  |                 updated_value = value + 1; | 
					
						
							|  |  |  |             } else if (waiting_threads.size() <= static_cast<u32>(num_to_wake)) { | 
					
						
							|  |  |  |                 updated_value = value - 1; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 updated_value = value; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-10-07 19:09:57 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     } while (!monitor.ExclusiveWrite32(current_core, address, updated_value)); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     WakeThreads(waiting_threads, num_to_wake); | 
					
						
							|  |  |  |     return RESULT_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-07 18:34:22 -05:00
										 |  |  | ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s32 value, | 
					
						
							|  |  |  |                                           s64 timeout_ns) { | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |     case ArbitrationType::WaitIfLessThan: | 
					
						
							|  |  |  |         return WaitForAddressIfLessThan(address, value, timeout_ns, false); | 
					
						
							|  |  |  |     case ArbitrationType::DecrementAndWaitIfLessThan: | 
					
						
							|  |  |  |         return WaitForAddressIfLessThan(address, value, timeout_ns, true); | 
					
						
							|  |  |  |     case ArbitrationType::WaitIfEqual: | 
					
						
							|  |  |  |         return WaitForAddressIfEqual(address, value, timeout_ns); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return ERR_INVALID_ENUM_VALUE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, | 
					
						
							|  |  |  |                                                     bool should_decrement) { | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |     auto& memory = system.Memory(); | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     auto& kernel = system.Kernel(); | 
					
						
							|  |  |  |     Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     Handle event_handle = InvalidHandle; | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 12:51:24 -04:00
										 |  |  |         if (current_thread->IsPendingTermination()) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return ERR_THREAD_TERMINATING; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |         // Ensure that we can read the address.
 | 
					
						
							|  |  |  |         if (!memory.IsValidVirtualAddress(address)) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return ERR_INVALID_ADDRESS_STATE; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         s32 current_value = static_cast<s32>(memory.Read32(address)); | 
					
						
							|  |  |  |         if (current_value >= value) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return ERR_INVALID_STATE; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 12:51:24 -04:00
										 |  |  |         current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |         s32 decrement_value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const std::size_t current_core = system.CurrentCoreIndex(); | 
					
						
							|  |  |  |         auto& monitor = system.Monitor(); | 
					
						
							|  |  |  |         do { | 
					
						
							| 
									
										
										
										
											2020-03-15 15:54:40 -04:00
										 |  |  |             current_value = static_cast<s32>(monitor.ExclusiveRead32(current_core, address)); | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |             if (should_decrement) { | 
					
						
							|  |  |  |                 decrement_value = current_value - 1; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 decrement_value = current_value; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } while ( | 
					
						
							|  |  |  |             !monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(decrement_value))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Short-circuit without rescheduling, if timeout is zero.
 | 
					
						
							|  |  |  |         if (timeout == 0) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return RESULT_TIMEOUT; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         current_thread->SetArbiterWaitAddress(address); | 
					
						
							|  |  |  |         InsertThread(SharedFrom(current_thread)); | 
					
						
							|  |  |  |         current_thread->SetStatus(ThreadStatus::WaitArb); | 
					
						
							|  |  |  |         current_thread->WaitForArbitration(true); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-05 12:22:13 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     if (event_handle != InvalidHandle) { | 
					
						
							|  |  |  |         auto& time_manager = kernel.TimeManager(); | 
					
						
							|  |  |  |         time_manager.UnscheduleTimeEvent(event_handle); | 
					
						
							| 
									
										
										
										
											2019-03-05 12:22:13 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     { | 
					
						
							|  |  |  |         SchedulerLock lock(kernel); | 
					
						
							|  |  |  |         if (current_thread->IsWaitingForArbitration()) { | 
					
						
							|  |  |  |             RemoveThread(SharedFrom(current_thread)); | 
					
						
							|  |  |  |             current_thread->WaitForArbitration(false); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     return current_thread->GetSignalingResult(); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |     auto& memory = system.Memory(); | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     auto& kernel = system.Kernel(); | 
					
						
							|  |  |  |     Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     Handle event_handle = InvalidHandle; | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 12:51:24 -04:00
										 |  |  |         if (current_thread->IsPendingTermination()) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return ERR_THREAD_TERMINATING; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |         // Ensure that we can read the address.
 | 
					
						
							|  |  |  |         if (!memory.IsValidVirtualAddress(address)) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return ERR_INVALID_ADDRESS_STATE; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         s32 current_value = static_cast<s32>(memory.Read32(address)); | 
					
						
							|  |  |  |         if (current_value != value) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return ERR_INVALID_STATE; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Short-circuit without rescheduling, if timeout is zero.
 | 
					
						
							|  |  |  |         if (timeout == 0) { | 
					
						
							|  |  |  |             lock.CancelSleep(); | 
					
						
							|  |  |  |             return RESULT_TIMEOUT; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); | 
					
						
							|  |  |  |         current_thread->SetArbiterWaitAddress(address); | 
					
						
							|  |  |  |         InsertThread(SharedFrom(current_thread)); | 
					
						
							|  |  |  |         current_thread->SetStatus(ThreadStatus::WaitArb); | 
					
						
							|  |  |  |         current_thread->WaitForArbitration(true); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     if (event_handle != InvalidHandle) { | 
					
						
							|  |  |  |         auto& time_manager = kernel.TimeManager(); | 
					
						
							|  |  |  |         time_manager.UnscheduleTimeEvent(event_handle); | 
					
						
							| 
									
										
										
										
											2018-06-21 21:05:34 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     { | 
					
						
							|  |  |  |         SchedulerLock lock(kernel); | 
					
						
							|  |  |  |         if (current_thread->IsWaitingForArbitration()) { | 
					
						
							|  |  |  |             RemoveThread(SharedFrom(current_thread)); | 
					
						
							|  |  |  |             current_thread->WaitForArbitration(false); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     return current_thread->GetSignalingResult(); | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  | void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) { | 
					
						
							|  |  |  |     ASSERT(thread->GetStatus() == ThreadStatus::WaitArb); | 
					
						
							|  |  |  |     RemoveThread(thread); | 
					
						
							|  |  |  |     thread->SetArbiterWaitAddress(0); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-03-29 17:13:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  | void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) { | 
					
						
							|  |  |  |     const VAddr arb_addr = thread->GetArbiterWaitAddress(); | 
					
						
							|  |  |  |     std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; | 
					
						
							| 
									
										
										
										
											2020-02-12 15:26:31 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const auto iter = | 
					
						
							|  |  |  |         std::find_if(thread_list.cbegin(), thread_list.cend(), [&thread](const auto& entry) { | 
					
						
							|  |  |  |             return entry->GetPriority() >= thread->GetPriority(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (iter == thread_list.cend()) { | 
					
						
							|  |  |  |         thread_list.push_back(std::move(thread)); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         thread_list.insert(iter, std::move(thread)); | 
					
						
							| 
									
										
										
										
											2019-03-29 17:13:00 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  | void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) { | 
					
						
							|  |  |  |     const VAddr arb_addr = thread->GetArbiterWaitAddress(); | 
					
						
							|  |  |  |     std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; | 
					
						
							| 
									
										
										
										
											2020-02-12 15:26:31 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(), | 
					
						
							|  |  |  |                                    [&thread](const auto& entry) { return thread == entry; }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 17:19:44 -04:00
										 |  |  |     if (iter != thread_list.cend()) { | 
					
						
							|  |  |  |         thread_list.erase(iter); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-12 15:07:15 -05:00
										 |  |  | std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress( | 
					
						
							|  |  |  |     VAddr address) const { | 
					
						
							|  |  |  |     const auto iter = arb_threads.find(address); | 
					
						
							|  |  |  |     if (iter == arb_threads.cend()) { | 
					
						
							|  |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-12-11 11:55:38 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-12 15:07:15 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const std::list<std::shared_ptr<Thread>>& thread_list = iter->second; | 
					
						
							|  |  |  |     return {thread_list.cbegin(), thread_list.cend()}; | 
					
						
							| 
									
										
										
										
											2019-03-05 11:54:06 -05:00
										 |  |  | } | 
					
						
							|  |  |  | } // namespace Kernel
 |