EventLoopImplementationWindows.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
  3. * Copyright (c) 2024, stasoid <stasoid@yahoo.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibCore/EventLoopImplementationWindows.h>
  8. #include <LibCore/Notifier.h>
  9. #include <LibCore/System.h>
  10. #include <LibCore/ThreadEventQueue.h>
  11. #include <AK/Windows.h>
  12. struct Handle {
  13. HANDLE handle = NULL;
  14. explicit Handle(HANDLE h = NULL)
  15. : handle(h)
  16. {
  17. }
  18. Handle(Handle&& h)
  19. {
  20. handle = h.handle;
  21. h.handle = NULL;
  22. }
  23. void operator=(Handle&& h)
  24. {
  25. VERIFY(!handle);
  26. handle = h.handle;
  27. h.handle = NULL;
  28. }
  29. ~Handle()
  30. {
  31. if (handle)
  32. CloseHandle(handle);
  33. }
  34. bool operator==(Handle const& h) const { return handle == h.handle; }
  35. bool operator==(HANDLE h) const { return handle == h; }
  36. };
  37. template<>
  38. struct Traits<Handle> : DefaultTraits<Handle> {
  39. static unsigned hash(Handle const& h) { return Traits<HANDLE>::hash(h.handle); }
  40. };
  41. template<>
  42. constexpr bool IsHashCompatible<HANDLE, Handle> = true;
  43. namespace Core {
  44. struct EventLoopTimer {
  45. WeakPtr<EventReceiver> owner;
  46. TimerShouldFireWhenNotVisible fire_when_not_visible = TimerShouldFireWhenNotVisible::No;
  47. };
  48. struct ThreadData {
  49. static ThreadData& the()
  50. {
  51. thread_local OwnPtr<ThreadData> thread_data = make<ThreadData>();
  52. return *thread_data;
  53. }
  54. ThreadData()
  55. {
  56. wake_event.handle = CreateEvent(NULL, FALSE, FALSE, NULL);
  57. VERIFY(wake_event.handle);
  58. }
  59. // Each thread has its own timers, notifiers and a wake event.
  60. HashMap<Handle, EventLoopTimer> timers;
  61. HashMap<Handle, Notifier*> notifiers;
  62. // The wake event is used to notify another event loop that someone has called wake().
  63. Handle wake_event;
  64. };
  65. EventLoopImplementationWindows::EventLoopImplementationWindows()
  66. : m_wake_event(ThreadData::the().wake_event.handle)
  67. {
  68. }
  69. int EventLoopImplementationWindows::exec()
  70. {
  71. for (;;) {
  72. if (m_exit_requested)
  73. return m_exit_code;
  74. pump(PumpMode::WaitForEvents);
  75. }
  76. VERIFY_NOT_REACHED();
  77. }
  78. size_t EventLoopImplementationWindows::pump(PumpMode)
  79. {
  80. auto& thread_data = ThreadData::the();
  81. auto& notifiers = thread_data.notifiers;
  82. auto& timers = thread_data.timers;
  83. size_t event_count = 1 + notifiers.size() + timers.size();
  84. // If 64 events limit proves to be insufficient RegisterWaitForSingleObject or other methods
  85. // can be used instead as mentioned in https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects
  86. // TODO: investigate if event_count can realistically exceed 64
  87. VERIFY(event_count <= MAXIMUM_WAIT_OBJECTS);
  88. Vector<HANDLE, MAXIMUM_WAIT_OBJECTS> event_handles;
  89. event_handles.append(thread_data.wake_event.handle);
  90. for (auto& entry : notifiers)
  91. event_handles.append(entry.key.handle);
  92. for (auto& entry : timers)
  93. event_handles.append(entry.key.handle);
  94. DWORD result = WaitForMultipleObjects(event_count, event_handles.data(), FALSE, INFINITE);
  95. size_t index = result - WAIT_OBJECT_0;
  96. VERIFY(index < event_count);
  97. if (index != 0) {
  98. if (index <= notifiers.size()) {
  99. Notifier* notifier = *notifiers.get(event_handles[index]);
  100. ThreadEventQueue::current().post_event(*notifier, make<NotifierActivationEvent>(notifier->fd(), notifier->type()));
  101. } else {
  102. auto& timer = *timers.get(event_handles[index]);
  103. if (auto strong_owner = timer.owner.strong_ref())
  104. if (timer.fire_when_not_visible == TimerShouldFireWhenNotVisible::Yes || strong_owner->is_visible_for_timer_purposes())
  105. ThreadEventQueue::current().post_event(*strong_owner, make<TimerEvent>());
  106. }
  107. }
  108. return ThreadEventQueue::current().process();
  109. }
  110. void EventLoopImplementationWindows::quit(int code)
  111. {
  112. m_exit_requested = true;
  113. m_exit_code = code;
  114. }
  115. void EventLoopImplementationWindows::unquit()
  116. {
  117. m_exit_requested = false;
  118. m_exit_code = 0;
  119. }
  120. bool EventLoopImplementationWindows::was_exit_requested() const
  121. {
  122. return m_exit_requested;
  123. }
  124. void EventLoopImplementationWindows::post_event(EventReceiver& receiver, NonnullOwnPtr<Event>&& event)
  125. {
  126. m_thread_event_queue.post_event(receiver, move(event));
  127. if (&m_thread_event_queue != &ThreadEventQueue::current())
  128. wake();
  129. }
  130. void EventLoopImplementationWindows::wake()
  131. {
  132. SetEvent(m_wake_event);
  133. }
  134. void EventLoopImplementationWindows::notify_forked_and_in_child()
  135. {
  136. dbgln("Core::EventLoopManagerWindows::notify_forked_and_in_child() is not implemented");
  137. VERIFY_NOT_REACHED();
  138. }
  139. static int notifier_type_to_network_event(NotificationType type)
  140. {
  141. switch (type) {
  142. case NotificationType::Read:
  143. return FD_READ;
  144. case NotificationType::Write:
  145. return FD_WRITE;
  146. default:
  147. dbgln("This notification type is not implemented: {}", (int)type);
  148. VERIFY_NOT_REACHED();
  149. }
  150. }
  151. void EventLoopManagerWindows::register_notifier(Notifier& notifier)
  152. {
  153. HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
  154. VERIFY(event);
  155. SOCKET socket = (SOCKET)System::fd_to_handle(notifier.fd());
  156. VERIFY(socket != INVALID_SOCKET);
  157. int rc = WSAEventSelect(socket, event, notifier_type_to_network_event(notifier.type()));
  158. VERIFY(rc == 0);
  159. auto& notifiers = ThreadData::the().notifiers;
  160. VERIFY(!notifiers.get(event).has_value());
  161. notifiers.set(Handle(event), &notifier);
  162. }
  163. void EventLoopManagerWindows::unregister_notifier(Notifier& notifier)
  164. {
  165. // remove_first_matching would be clearer, but currently there is no such method in HashMap
  166. ThreadData::the().notifiers.remove_all_matching([&](auto&, auto value) { return value == &notifier; });
  167. }
  168. intptr_t EventLoopManagerWindows::register_timer(EventReceiver& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible)
  169. {
  170. VERIFY(milliseconds >= 0);
  171. HANDLE timer = CreateWaitableTimer(NULL, FALSE, NULL);
  172. VERIFY(timer);
  173. LARGE_INTEGER first_time = {};
  174. // Measured in 0.1μs intervals, negative means starting from now
  175. first_time.QuadPart = -10'000 * milliseconds;
  176. BOOL rc = SetWaitableTimer(timer, &first_time, should_reload ? milliseconds : 0, NULL, NULL, FALSE);
  177. VERIFY(rc);
  178. auto& timers = ThreadData::the().timers;
  179. VERIFY(!timers.get(timer).has_value());
  180. timers.set(Handle(timer), { object, fire_when_not_visible });
  181. return (intptr_t)timer;
  182. }
  183. void EventLoopManagerWindows::unregister_timer(intptr_t timer_id)
  184. {
  185. ThreadData::the().timers.remove((HANDLE)timer_id);
  186. }
  187. int EventLoopManagerWindows::register_signal([[maybe_unused]] int signal_number, [[maybe_unused]] Function<void(int)> handler)
  188. {
  189. dbgln("Core::EventLoopManagerWindows::register_signal() is not implemented");
  190. VERIFY_NOT_REACHED();
  191. }
  192. void EventLoopManagerWindows::unregister_signal([[maybe_unused]] int handler_id)
  193. {
  194. dbgln("Core::EventLoopManagerWindows::unregister_signal() is not implemented");
  195. VERIFY_NOT_REACHED();
  196. }
  197. void EventLoopManagerWindows::did_post_event()
  198. {
  199. }
  200. NonnullOwnPtr<EventLoopImplementation> EventLoopManagerWindows::make_implementation()
  201. {
  202. return make<EventLoopImplementationWindows>();
  203. }
  204. }