semaphore.cpp 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <queue>
  5. #include "common/common.h"
  6. #include "core/hle/kernel/kernel.h"
  7. #include "core/hle/kernel/semaphore.h"
  8. #include "core/hle/kernel/thread.h"
  9. namespace Kernel {
  10. class Semaphore : public Object {
  11. public:
  12. std::string GetTypeName() const override { return "Semaphore"; }
  13. std::string GetName() const override { return name; }
  14. static const HandleType HANDLE_TYPE = HandleType::Semaphore;
  15. HandleType GetHandleType() const override { return HANDLE_TYPE; }
  16. s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
  17. s32 available_count; ///< Number of free slots left in the semaphore
  18. std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore
  19. std::string name; ///< Name of semaphore (optional)
  20. /**
  21. * Tests whether a semaphore still has free slots
  22. * @return Whether the semaphore is available
  23. */
  24. bool IsAvailable() const {
  25. return available_count > 0;
  26. }
  27. ResultVal<bool> WaitSynchronization() override {
  28. bool wait = !IsAvailable();
  29. if (wait) {
  30. Kernel::WaitCurrentThread(WAITTYPE_SEMA, this);
  31. waiting_threads.push(GetCurrentThread()->GetHandle());
  32. } else {
  33. --available_count;
  34. }
  35. return MakeResult<bool>(wait);
  36. }
  37. };
  38. ////////////////////////////////////////////////////////////////////////////////////////////////////
  39. ResultCode CreateSemaphore(Handle* handle, s32 initial_count,
  40. s32 max_count, const std::string& name) {
  41. if (initial_count > max_count)
  42. return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
  43. ErrorSummary::WrongArgument, ErrorLevel::Permanent);
  44. Semaphore* semaphore = new Semaphore;
  45. // TOOD(yuriks): Fix error reporting
  46. *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE);
  47. // When the semaphore is created, some slots are reserved for other threads,
  48. // and the rest is reserved for the caller thread
  49. semaphore->max_count = max_count;
  50. semaphore->available_count = initial_count;
  51. semaphore->name = name;
  52. return RESULT_SUCCESS;
  53. }
  54. ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
  55. Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get();
  56. if (semaphore == nullptr)
  57. return InvalidHandle(ErrorModule::Kernel);
  58. if (semaphore->max_count - semaphore->available_count < release_count)
  59. return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
  60. ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
  61. *count = semaphore->available_count;
  62. semaphore->available_count += release_count;
  63. // Notify some of the threads that the semaphore has been released
  64. // stop once the semaphore is full again or there are no more waiting threads
  65. while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) {
  66. Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()).get();
  67. if (thread != nullptr)
  68. thread->ResumeFromWait();
  69. semaphore->waiting_threads.pop();
  70. --semaphore->available_count;
  71. }
  72. return RESULT_SUCCESS;
  73. }
  74. } // namespace