kernel.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include "common/assert.h"
  6. #include "common/logging/log.h"
  7. #include "core/hle/config_mem.h"
  8. #include "core/hle/kernel/kernel.h"
  9. #include "core/hle/kernel/memory.h"
  10. #include "core/hle/kernel/process.h"
  11. #include "core/hle/kernel/resource_limit.h"
  12. #include "core/hle/kernel/thread.h"
  13. #include "core/hle/kernel/timer.h"
  14. #include "core/hle/shared_page.h"
  15. namespace Kernel {
  16. unsigned int Object::next_object_id;
  17. HandleTable g_handle_table;
  18. void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
  19. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  20. if (itr == waiting_threads.end())
  21. waiting_threads.push_back(std::move(thread));
  22. }
  23. void WaitObject::RemoveWaitingThread(Thread* thread) {
  24. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  25. // If a thread passed multiple handles to the same object,
  26. // the kernel might attempt to remove the thread from the object's
  27. // waiting threads list multiple times.
  28. if (itr != waiting_threads.end())
  29. waiting_threads.erase(itr);
  30. }
  31. SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
  32. Thread* candidate = nullptr;
  33. s32 candidate_priority = THREADPRIO_LOWEST + 1;
  34. for (const auto& thread : waiting_threads) {
  35. // The list of waiting threads must not contain threads that are not waiting to be awakened.
  36. ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
  37. thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
  38. "Inconsistent thread statuses in waiting_threads");
  39. if (thread->current_priority >= candidate_priority)
  40. continue;
  41. if (ShouldWait(thread.get()))
  42. continue;
  43. // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
  44. // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
  45. bool ready_to_run = true;
  46. if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
  47. ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
  48. [&thread](const SharedPtr<WaitObject>& object) {
  49. return object->ShouldWait(thread.get());
  50. });
  51. }
  52. if (ready_to_run) {
  53. candidate = thread.get();
  54. candidate_priority = thread->current_priority;
  55. }
  56. }
  57. return candidate;
  58. }
  59. void WaitObject::WakeupAllWaitingThreads() {
  60. while (auto thread = GetHighestPriorityReadyThread()) {
  61. if (!thread->IsSleepingOnWaitAll()) {
  62. Acquire(thread.get());
  63. // Set the output index of the WaitSynchronizationN call to the index of this object.
  64. if (thread->wait_set_output) {
  65. thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
  66. thread->wait_set_output = false;
  67. }
  68. } else {
  69. for (auto& object : thread->wait_objects) {
  70. object->Acquire(thread.get());
  71. }
  72. // Note: This case doesn't update the output index of WaitSynchronizationN.
  73. }
  74. for (auto& object : thread->wait_objects)
  75. object->RemoveWaitingThread(thread.get());
  76. thread->wait_objects.clear();
  77. thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
  78. thread->ResumeFromWait();
  79. }
  80. }
  81. const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
  82. return waiting_threads;
  83. }
  84. HandleTable::HandleTable() {
  85. next_generation = 1;
  86. Clear();
  87. }
  88. ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
  89. DEBUG_ASSERT(obj != nullptr);
  90. u16 slot = next_free_slot;
  91. if (slot >= generations.size()) {
  92. LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
  93. return ERR_OUT_OF_HANDLES;
  94. }
  95. next_free_slot = generations[slot];
  96. u16 generation = next_generation++;
  97. // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
  98. // CTR-OS doesn't use generation 0, so skip straight to 1.
  99. if (next_generation >= (1 << 15))
  100. next_generation = 1;
  101. generations[slot] = generation;
  102. objects[slot] = std::move(obj);
  103. Handle handle = generation | (slot << 15);
  104. return MakeResult<Handle>(handle);
  105. }
  106. ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
  107. SharedPtr<Object> object = GetGeneric(handle);
  108. if (object == nullptr) {
  109. LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
  110. return ERR_INVALID_HANDLE;
  111. }
  112. return Create(std::move(object));
  113. }
  114. ResultCode HandleTable::Close(Handle handle) {
  115. if (!IsValid(handle))
  116. return ERR_INVALID_HANDLE;
  117. u16 slot = GetSlot(handle);
  118. objects[slot] = nullptr;
  119. generations[slot] = next_free_slot;
  120. next_free_slot = slot;
  121. return RESULT_SUCCESS;
  122. }
  123. bool HandleTable::IsValid(Handle handle) const {
  124. size_t slot = GetSlot(handle);
  125. u16 generation = GetGeneration(handle);
  126. return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
  127. }
  128. SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
  129. if (handle == CurrentThread) {
  130. return GetCurrentThread();
  131. } else if (handle == CurrentProcess) {
  132. return g_current_process;
  133. }
  134. if (!IsValid(handle)) {
  135. return nullptr;
  136. }
  137. return objects[GetSlot(handle)];
  138. }
  139. void HandleTable::Clear() {
  140. for (u16 i = 0; i < MAX_COUNT; ++i) {
  141. generations[i] = i + 1;
  142. objects[i] = nullptr;
  143. }
  144. next_free_slot = 0;
  145. }
  146. /// Initialize the kernel
  147. void Init(u32 system_mode) {
  148. ConfigMem::Init();
  149. SharedPage::Init();
  150. Kernel::MemoryInit(system_mode);
  151. Kernel::ResourceLimitsInit();
  152. Kernel::ThreadingInit();
  153. Kernel::TimersInit();
  154. Object::next_object_id = 0;
  155. // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
  156. // reserved for low-level services
  157. Process::next_process_id = 10;
  158. }
  159. /// Shutdown the kernel
  160. void Shutdown() {
  161. g_handle_table.Clear(); // Free all kernel objects
  162. Kernel::ThreadingShutdown();
  163. g_current_process = nullptr;
  164. Kernel::TimersShutdown();
  165. Kernel::ResourceLimitsShutdown();
  166. Kernel::MemoryShutdown();
  167. }
  168. } // namespace