semaphore.cpp 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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 WaitObject {
  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::string name; ///< Name of semaphore (optional)
  19. /**
  20. * Tests whether a semaphore still has free slots
  21. * @return Whether the semaphore is available
  22. */
  23. bool IsAvailable() const {
  24. return available_count > 0;
  25. }
  26. ResultVal<bool> WaitSynchronization(unsigned index) override {
  27. bool wait = !IsAvailable();
  28. if (wait) {
  29. Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index);
  30. AddWaitingThread(GetCurrentThread());
  31. } else {
  32. --available_count;
  33. }
  34. return MakeResult<bool>(wait);
  35. }
  36. };
  37. ////////////////////////////////////////////////////////////////////////////////////////////////////
  38. ResultCode CreateSemaphore(Handle* handle, s32 initial_count,
  39. s32 max_count, const std::string& name) {
  40. if (initial_count > max_count)
  41. return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
  42. ErrorSummary::WrongArgument, ErrorLevel::Permanent);
  43. Semaphore* semaphore = new Semaphore;
  44. // TOOD(yuriks): Fix error reporting
  45. *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE);
  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).get();
  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->IsAvailable() && semaphore->ReleaseNextThread() != nullptr) {
  65. --semaphore->available_count;
  66. }
  67. return RESULT_SUCCESS;
  68. }
  69. } // namespace