semaphore.cpp 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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 Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; }
  15. Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; }
  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, GetHandle());
  31. waiting_threads.push(GetCurrentThreadHandle());
  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. *handle = g_handle_table.Create(semaphore);
  46. // When the semaphore is created, some slots are reserved for other threads,
  47. // and the rest is reserved for the caller thread
  48. semaphore->max_count = max_count;
  49. semaphore->available_count = initial_count;
  50. semaphore->name = name;
  51. return RESULT_SUCCESS;
  52. }
  53. ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
  54. Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle);
  55. if (semaphore == nullptr)
  56. return InvalidHandle(ErrorModule::Kernel);
  57. if (semaphore->max_count - semaphore->available_count < release_count)
  58. return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
  59. ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
  60. *count = semaphore->available_count;
  61. semaphore->available_count += release_count;
  62. // Notify some of the threads that the semaphore has been released
  63. // stop once the semaphore is full again or there are no more waiting threads
  64. while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) {
  65. Kernel::ResumeThreadFromWait(semaphore->waiting_threads.front());
  66. semaphore->waiting_threads.pop();
  67. --semaphore->available_count;
  68. }
  69. return RESULT_SUCCESS;
  70. }
  71. } // namespace