kernel.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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/arm/arm_interface.h"
  8. #include "core/core.h"
  9. #include "core/hle/kernel/kernel.h"
  10. #include "core/hle/kernel/process.h"
  11. #include "core/hle/kernel/thread.h"
  12. #include "core/hle/kernel/timer.h"
  13. namespace Kernel {
  14. unsigned int Object::next_object_id;
  15. SharedPtr<Thread> g_main_thread;
  16. HandleTable g_handle_table;
  17. u64 g_program_id;
  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 (itr != waiting_threads.end())
  26. waiting_threads.erase(itr);
  27. }
  28. SharedPtr<Thread> WaitObject::WakeupNextThread() {
  29. if (waiting_threads.empty())
  30. return nullptr;
  31. auto next_thread = std::move(waiting_threads.front());
  32. waiting_threads.erase(waiting_threads.begin());
  33. next_thread->ReleaseWaitObject(this);
  34. return next_thread;
  35. }
  36. void WaitObject::WakeupAllWaitingThreads() {
  37. auto waiting_threads_copy = waiting_threads;
  38. // We use a copy because ReleaseWaitObject will remove the thread from this object's
  39. // waiting_threads list
  40. for (auto thread : waiting_threads_copy)
  41. thread->ReleaseWaitObject(this);
  42. ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!");
  43. }
  44. HandleTable::HandleTable() {
  45. next_generation = 1;
  46. Clear();
  47. }
  48. ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
  49. DEBUG_ASSERT(obj != nullptr);
  50. u16 slot = next_free_slot;
  51. if (slot >= generations.size()) {
  52. LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
  53. return ERR_OUT_OF_HANDLES;
  54. }
  55. next_free_slot = generations[slot];
  56. u16 generation = next_generation++;
  57. // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
  58. // CTR-OS doesn't use generation 0, so skip straight to 1.
  59. if (next_generation >= (1 << 15)) next_generation = 1;
  60. generations[slot] = generation;
  61. objects[slot] = std::move(obj);
  62. Handle handle = generation | (slot << 15);
  63. return MakeResult<Handle>(handle);
  64. }
  65. ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
  66. SharedPtr<Object> object = GetGeneric(handle);
  67. if (object == nullptr) {
  68. LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
  69. return ERR_INVALID_HANDLE;
  70. }
  71. return Create(std::move(object));
  72. }
  73. ResultCode HandleTable::Close(Handle handle) {
  74. if (!IsValid(handle))
  75. return ERR_INVALID_HANDLE;
  76. u16 slot = GetSlot(handle);
  77. objects[slot] = nullptr;
  78. generations[slot] = next_free_slot;
  79. next_free_slot = slot;
  80. return RESULT_SUCCESS;
  81. }
  82. bool HandleTable::IsValid(Handle handle) const {
  83. size_t slot = GetSlot(handle);
  84. u16 generation = GetGeneration(handle);
  85. return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
  86. }
  87. SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
  88. if (handle == CurrentThread) {
  89. return GetCurrentThread();
  90. } else if (handle == CurrentProcess) {
  91. LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess);
  92. return nullptr;
  93. }
  94. if (!IsValid(handle)) {
  95. return nullptr;
  96. }
  97. return objects[GetSlot(handle)];
  98. }
  99. void HandleTable::Clear() {
  100. for (u16 i = 0; i < MAX_COUNT; ++i) {
  101. generations[i] = i + 1;
  102. objects[i] = nullptr;
  103. }
  104. next_free_slot = 0;
  105. }
  106. /// Initialize the kernel
  107. void Init() {
  108. Kernel::ThreadingInit();
  109. Kernel::TimersInit();
  110. Object::next_object_id = 0;
  111. g_program_id = 0;
  112. g_main_thread = nullptr;
  113. }
  114. /// Shutdown the kernel
  115. void Shutdown() {
  116. Kernel::ThreadingShutdown();
  117. Kernel::TimersShutdown();
  118. g_handle_table.Clear(); // Free all kernel objects
  119. g_current_process = nullptr;
  120. }
  121. } // namespace