event.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #include <map>
  5. #include <algorithm>
  6. #include <vector>
  7. #include "common/common.h"
  8. #include "core/hle/kernel/kernel.h"
  9. #include "core/hle/kernel/event.h"
  10. #include "core/hle/kernel/thread.h"
  11. namespace Kernel {
  12. class Event : public Object {
  13. public:
  14. std::string GetTypeName() const override { return "Event"; }
  15. std::string GetName() const override { return name; }
  16. static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
  17. Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; }
  18. ResetType intitial_reset_type; ///< ResetType specified at Event initialization
  19. ResetType reset_type; ///< Current ResetType
  20. bool locked; ///< Event signal wait
  21. bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough)
  22. std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
  23. std::string name; ///< Name of event (optional)
  24. ResultVal<bool> WaitSynchronization() override {
  25. bool wait = locked;
  26. if (locked) {
  27. Handle thread = GetCurrentThreadHandle();
  28. if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
  29. waiting_threads.push_back(thread);
  30. }
  31. Kernel::WaitCurrentThread(WAITTYPE_EVENT, GetHandle());
  32. }
  33. if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
  34. locked = true;
  35. }
  36. return MakeResult<bool>(wait);
  37. }
  38. };
  39. /**
  40. * Hackish function to set an events permanent lock state, used to pass through synch blocks
  41. * @param handle Handle to event to change
  42. * @param permanent_locked Boolean permanent locked value to set event
  43. * @return Result of operation, 0 on success, otherwise error code
  44. */
  45. ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
  46. Event* evt = g_object_pool.Get<Event>(handle);
  47. if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
  48. evt->permanent_locked = permanent_locked;
  49. return RESULT_SUCCESS;
  50. }
  51. /**
  52. * Changes whether an event is locked or not
  53. * @param handle Handle to event to change
  54. * @param locked Boolean locked value to set event
  55. * @return Result of operation, 0 on success, otherwise error code
  56. */
  57. ResultCode SetEventLocked(const Handle handle, const bool locked) {
  58. Event* evt = g_object_pool.Get<Event>(handle);
  59. if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
  60. if (!evt->permanent_locked) {
  61. evt->locked = locked;
  62. }
  63. return RESULT_SUCCESS;
  64. }
  65. /**
  66. * Signals an event
  67. * @param handle Handle to event to signal
  68. * @return Result of operation, 0 on success, otherwise error code
  69. */
  70. ResultCode SignalEvent(const Handle handle) {
  71. Event* evt = g_object_pool.Get<Event>(handle);
  72. if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
  73. // Resume threads waiting for event to signal
  74. bool event_caught = false;
  75. for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
  76. ResumeThreadFromWait( evt->waiting_threads[i]);
  77. // If any thread is signalled awake by this event, assume the event was "caught" and reset
  78. // the event. This will result in the next thread waiting on the event to block. Otherwise,
  79. // the event will not be reset, and the next thread to call WaitSynchronization on it will
  80. // not block. Not sure if this is correct behavior, but it seems to work.
  81. event_caught = true;
  82. }
  83. evt->waiting_threads.clear();
  84. if (!evt->permanent_locked) {
  85. evt->locked = event_caught;
  86. }
  87. return RESULT_SUCCESS;
  88. }
  89. /**
  90. * Clears an event
  91. * @param handle Handle to event to clear
  92. * @return Result of operation, 0 on success, otherwise error code
  93. */
  94. ResultCode ClearEvent(Handle handle) {
  95. Event* evt = g_object_pool.Get<Event>(handle);
  96. if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
  97. if (!evt->permanent_locked) {
  98. evt->locked = true;
  99. }
  100. return RESULT_SUCCESS;
  101. }
  102. /**
  103. * Creates an event
  104. * @param handle Reference to handle for the newly created mutex
  105. * @param reset_type ResetType describing how to create event
  106. * @param name Optional name of event
  107. * @return Newly created Event object
  108. */
  109. Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) {
  110. Event* evt = new Event;
  111. handle = Kernel::g_object_pool.Create(evt);
  112. evt->locked = true;
  113. evt->permanent_locked = false;
  114. evt->reset_type = evt->intitial_reset_type = reset_type;
  115. evt->name = name;
  116. return evt;
  117. }
  118. /**
  119. * Creates an event
  120. * @param reset_type ResetType describing how to create event
  121. * @param name Optional name of event
  122. * @return Handle to newly created Event object
  123. */
  124. Handle CreateEvent(const ResetType reset_type, const std::string& name) {
  125. Handle handle;
  126. Event* evt = CreateEvent(handle, reset_type, name);
  127. return handle;
  128. }
  129. } // namespace