EventLoopImplementationMacOS.mm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. * Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Assertions.h>
  7. #include <AK/HashMap.h>
  8. #include <AK/IDAllocator.h>
  9. #include <AK/Singleton.h>
  10. #include <AK/TemporaryChange.h>
  11. #include <LibCore/Event.h>
  12. #include <LibCore/Notifier.h>
  13. #include <LibCore/ThreadEventQueue.h>
  14. #include <LibWebView/EventLoop/EventLoopImplementationMacOS.h>
  15. #import <Cocoa/Cocoa.h>
  16. #import <CoreFoundation/CoreFoundation.h>
  17. #include <sys/event.h>
  18. #include <sys/time.h>
  19. #include <sys/types.h>
  20. namespace WebView {
  21. struct ThreadData {
  22. static ThreadData& the()
  23. {
  24. static thread_local ThreadData s_thread_data;
  25. return s_thread_data;
  26. }
  27. Core::Notifier& notifier_by_fd(int fd)
  28. {
  29. for (auto notifier : notifiers) {
  30. if (notifier.key->fd() == fd)
  31. return *notifier.key;
  32. }
  33. // If we didn't have a notifier for the provided FD, it should have been unregistered.
  34. VERIFY_NOT_REACHED();
  35. }
  36. IDAllocator timer_id_allocator;
  37. HashMap<int, CFRunLoopTimerRef> timers;
  38. HashMap<Core::Notifier*, CFRunLoopSourceRef> notifiers;
  39. };
  40. class SignalHandlers : public RefCounted<SignalHandlers> {
  41. AK_MAKE_NONCOPYABLE(SignalHandlers);
  42. AK_MAKE_NONMOVABLE(SignalHandlers);
  43. public:
  44. SignalHandlers(int signal_number, CFFileDescriptorCallBack);
  45. ~SignalHandlers();
  46. void dispatch();
  47. int add(Function<void(int)>&& handler);
  48. bool remove(int handler_id);
  49. bool is_empty() const
  50. {
  51. if (m_calling_handlers) {
  52. for (auto const& handler : m_handlers_pending) {
  53. if (handler.value)
  54. return false; // an add is pending
  55. }
  56. }
  57. return m_handlers.is_empty();
  58. }
  59. bool have(int handler_id) const
  60. {
  61. if (m_calling_handlers) {
  62. auto it = m_handlers_pending.find(handler_id);
  63. if (it != m_handlers_pending.end()) {
  64. if (!it->value)
  65. return false; // a deletion is pending
  66. }
  67. }
  68. return m_handlers.contains(handler_id);
  69. }
  70. int m_signal_number;
  71. void (*m_original_handler)(int);
  72. HashMap<int, Function<void(int)>> m_handlers;
  73. HashMap<int, Function<void(int)>> m_handlers_pending;
  74. bool m_calling_handlers { false };
  75. CFRunLoopSourceRef m_source { nullptr };
  76. int m_kevent_fd = { -1 };
  77. };
  78. SignalHandlers::SignalHandlers(int signal_number, CFFileDescriptorCallBack handle_signal)
  79. : m_signal_number(signal_number)
  80. , m_original_handler(signal(signal_number, [](int) { }))
  81. {
  82. m_kevent_fd = kqueue();
  83. if (m_kevent_fd < 0) {
  84. dbgln("Unable to create kqueue to register signal {}: {}", signal_number, strerror(errno));
  85. VERIFY_NOT_REACHED();
  86. }
  87. struct kevent changes = {};
  88. EV_SET(&changes, signal_number, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, 0, 0, nullptr);
  89. if (auto res = kevent(m_kevent_fd, &changes, 1, &changes, 1, NULL); res < 0) {
  90. dbgln("Unable to register signal {}: {}", signal_number, strerror(errno));
  91. VERIFY_NOT_REACHED();
  92. }
  93. CFFileDescriptorContext context = { 0, this, nullptr, nullptr, nullptr };
  94. CFFileDescriptorRef kq_ref = CFFileDescriptorCreate(kCFAllocatorDefault, m_kevent_fd, FALSE, handle_signal, &context);
  95. m_source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, kq_ref, 0);
  96. CFRunLoopAddSource(CFRunLoopGetMain(), m_source, kCFRunLoopDefaultMode);
  97. CFFileDescriptorEnableCallBacks(kq_ref, kCFFileDescriptorReadCallBack);
  98. CFRelease(kq_ref);
  99. }
  100. SignalHandlers::~SignalHandlers()
  101. {
  102. CFRunLoopRemoveSource(CFRunLoopGetMain(), m_source, kCFRunLoopDefaultMode);
  103. CFRelease(m_source);
  104. (void)::signal(m_signal_number, m_original_handler);
  105. ::close(m_kevent_fd);
  106. }
  107. struct SignalHandlersInfo {
  108. HashMap<int, NonnullRefPtr<SignalHandlers>> signal_handlers;
  109. int next_signal_id { 0 };
  110. };
  111. static Singleton<SignalHandlersInfo> s_signals;
  112. static SignalHandlersInfo* signals_info()
  113. {
  114. return s_signals.ptr();
  115. }
  116. void SignalHandlers::dispatch()
  117. {
  118. TemporaryChange change(m_calling_handlers, true);
  119. for (auto& handler : m_handlers)
  120. handler.value(m_signal_number);
  121. if (!m_handlers_pending.is_empty()) {
  122. // Apply pending adds/removes
  123. for (auto& handler : m_handlers_pending) {
  124. if (handler.value) {
  125. auto result = m_handlers.set(handler.key, move(handler.value));
  126. VERIFY(result == AK::HashSetResult::InsertedNewEntry);
  127. } else {
  128. m_handlers.remove(handler.key);
  129. }
  130. }
  131. m_handlers_pending.clear();
  132. }
  133. }
  134. int SignalHandlers::add(Function<void(int)>&& handler)
  135. {
  136. int id = ++signals_info()->next_signal_id; // TODO: worry about wrapping and duplicates?
  137. if (m_calling_handlers)
  138. m_handlers_pending.set(id, move(handler));
  139. else
  140. m_handlers.set(id, move(handler));
  141. return id;
  142. }
  143. bool SignalHandlers::remove(int handler_id)
  144. {
  145. VERIFY(handler_id != 0);
  146. if (m_calling_handlers) {
  147. auto it = m_handlers.find(handler_id);
  148. if (it != m_handlers.end()) {
  149. // Mark pending remove
  150. m_handlers_pending.set(handler_id, {});
  151. return true;
  152. }
  153. it = m_handlers_pending.find(handler_id);
  154. if (it != m_handlers_pending.end()) {
  155. if (!it->value)
  156. return false; // already was marked as deleted
  157. it->value = nullptr;
  158. return true;
  159. }
  160. return false;
  161. }
  162. return m_handlers.remove(handler_id);
  163. }
  164. static void post_application_event()
  165. {
  166. auto* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
  167. location:NSMakePoint(0, 0)
  168. modifierFlags:0
  169. timestamp:0
  170. windowNumber:0
  171. context:nil
  172. subtype:0
  173. data1:0
  174. data2:0];
  175. [NSApp postEvent:event atStart:NO];
  176. }
  177. NonnullOwnPtr<Core::EventLoopImplementation> EventLoopManagerMacOS::make_implementation()
  178. {
  179. return EventLoopImplementationMacOS::create();
  180. }
  181. intptr_t EventLoopManagerMacOS::register_timer(Core::EventReceiver& receiver, int interval_milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible should_fire_when_not_visible)
  182. {
  183. auto& thread_data = ThreadData::the();
  184. auto timer_id = thread_data.timer_id_allocator.allocate();
  185. auto weak_receiver = receiver.make_weak_ptr();
  186. auto interval_seconds = static_cast<double>(interval_milliseconds) / 1000.0;
  187. auto first_fire_time = CFAbsoluteTimeGetCurrent() + interval_seconds;
  188. auto* timer = CFRunLoopTimerCreateWithHandler(
  189. kCFAllocatorDefault, first_fire_time, should_reload ? interval_seconds : 0, 0, 0,
  190. ^(CFRunLoopTimerRef) {
  191. auto receiver = weak_receiver.strong_ref();
  192. if (!receiver) {
  193. return;
  194. }
  195. if (should_fire_when_not_visible == Core::TimerShouldFireWhenNotVisible::No) {
  196. if (!receiver->is_visible_for_timer_purposes()) {
  197. return;
  198. }
  199. }
  200. Core::TimerEvent event;
  201. receiver->dispatch_event(event);
  202. });
  203. CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
  204. thread_data.timers.set(timer_id, timer);
  205. return timer_id;
  206. }
  207. void EventLoopManagerMacOS::unregister_timer(intptr_t timer_id)
  208. {
  209. auto& thread_data = ThreadData::the();
  210. thread_data.timer_id_allocator.deallocate(static_cast<int>(timer_id));
  211. auto timer = thread_data.timers.take(static_cast<int>(timer_id));
  212. VERIFY(timer.has_value());
  213. CFRunLoopTimerInvalidate(*timer);
  214. CFRelease(*timer);
  215. }
  216. static void socket_notifier(CFSocketRef socket, CFSocketCallBackType notification_type, CFDataRef, void const*, void*)
  217. {
  218. auto& notifier = ThreadData::the().notifier_by_fd(CFSocketGetNative(socket));
  219. // This socket callback is not quite re-entrant. If Core::Notifier::dispatch_event blocks, e.g.
  220. // to wait upon a Core::Promise, this socket will not receive any more notifications until that
  221. // promise is resolved or rejected. So we mark this socket as able to receive more notifications
  222. // before dispatching the event, which allows it to be triggered again.
  223. CFSocketEnableCallBacks(socket, notification_type);
  224. Core::NotifierActivationEvent event(notifier.fd(), notifier.type());
  225. notifier.dispatch_event(event);
  226. // This manual process of enabling the callbacks also seems to require waking the event loop,
  227. // otherwise it hangs indefinitely in any ongoing pump(PumpMode::WaitForEvents) invocation.
  228. post_application_event();
  229. }
  230. void EventLoopManagerMacOS::register_notifier(Core::Notifier& notifier)
  231. {
  232. auto notification_type = kCFSocketNoCallBack;
  233. switch (notifier.type()) {
  234. case Core::Notifier::Type::Read:
  235. notification_type = kCFSocketReadCallBack;
  236. break;
  237. case Core::Notifier::Type::Write:
  238. notification_type = kCFSocketWriteCallBack;
  239. break;
  240. default:
  241. TODO();
  242. break;
  243. }
  244. CFSocketContext context { .version = 0, .info = nullptr, .retain = nullptr, .release = nullptr, .copyDescription = nullptr };
  245. auto* socket = CFSocketCreateWithNative(kCFAllocatorDefault, notifier.fd(), notification_type, &socket_notifier, &context);
  246. CFOptionFlags sockopt = CFSocketGetSocketFlags(socket);
  247. sockopt &= ~kCFSocketAutomaticallyReenableReadCallBack;
  248. sockopt &= ~kCFSocketCloseOnInvalidate;
  249. CFSocketSetSocketFlags(socket, sockopt);
  250. auto* source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
  251. CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
  252. CFRelease(socket);
  253. ThreadData::the().notifiers.set(&notifier, source);
  254. }
  255. void EventLoopManagerMacOS::unregister_notifier(Core::Notifier& notifier)
  256. {
  257. if (auto source = ThreadData::the().notifiers.take(&notifier); source.has_value()) {
  258. CFRunLoopRemoveSource(CFRunLoopGetCurrent(), *source, kCFRunLoopCommonModes);
  259. CFRelease(*source);
  260. }
  261. }
  262. void EventLoopManagerMacOS::did_post_event()
  263. {
  264. post_application_event();
  265. }
  266. static void handle_signal(CFFileDescriptorRef f, CFOptionFlags callback_types, void* info)
  267. {
  268. VERIFY(callback_types & kCFFileDescriptorReadCallBack);
  269. auto* signal_handlers = static_cast<SignalHandlers*>(info);
  270. struct kevent event {};
  271. // returns number of events that have occurred since last call
  272. (void)::kevent(CFFileDescriptorGetNativeDescriptor(f), nullptr, 0, &event, 1, nullptr);
  273. CFFileDescriptorEnableCallBacks(f, kCFFileDescriptorReadCallBack);
  274. signal_handlers->dispatch();
  275. }
  276. int EventLoopManagerMacOS::register_signal(int signal_number, Function<void(int)> handler)
  277. {
  278. VERIFY(signal_number != 0);
  279. auto& info = *signals_info();
  280. auto handlers = info.signal_handlers.find(signal_number);
  281. if (handlers == info.signal_handlers.end()) {
  282. auto signal_handlers = adopt_ref(*new SignalHandlers(signal_number, &handle_signal));
  283. auto handler_id = signal_handlers->add(move(handler));
  284. info.signal_handlers.set(signal_number, move(signal_handlers));
  285. return handler_id;
  286. } else {
  287. return handlers->value->add(move(handler));
  288. }
  289. }
  290. void EventLoopManagerMacOS::unregister_signal(int handler_id)
  291. {
  292. VERIFY(handler_id != 0);
  293. int remove_signal_number = 0;
  294. auto& info = *signals_info();
  295. for (auto& h : info.signal_handlers) {
  296. auto& handlers = *h.value;
  297. if (handlers.remove(handler_id)) {
  298. if (handlers.is_empty())
  299. remove_signal_number = handlers.m_signal_number;
  300. break;
  301. }
  302. }
  303. if (remove_signal_number != 0)
  304. info.signal_handlers.remove(remove_signal_number);
  305. }
  306. NonnullOwnPtr<EventLoopImplementationMacOS> EventLoopImplementationMacOS::create()
  307. {
  308. return adopt_own(*new EventLoopImplementationMacOS);
  309. }
  310. int EventLoopImplementationMacOS::exec()
  311. {
  312. [NSApp run];
  313. return m_exit_code;
  314. }
  315. size_t EventLoopImplementationMacOS::pump(PumpMode mode)
  316. {
  317. auto* wait_until = mode == PumpMode::WaitForEvents ? [NSDate distantFuture] : [NSDate distantPast];
  318. auto* event = [NSApp nextEventMatchingMask:NSEventMaskAny
  319. untilDate:wait_until
  320. inMode:NSDefaultRunLoopMode
  321. dequeue:YES];
  322. while (event) {
  323. [NSApp sendEvent:event];
  324. event = [NSApp nextEventMatchingMask:NSEventMaskAny
  325. untilDate:nil
  326. inMode:NSDefaultRunLoopMode
  327. dequeue:YES];
  328. }
  329. return 0;
  330. }
  331. void EventLoopImplementationMacOS::quit(int exit_code)
  332. {
  333. m_exit_code = exit_code;
  334. [NSApp stop:nil];
  335. }
  336. void EventLoopImplementationMacOS::wake()
  337. {
  338. CFRunLoopWakeUp(CFRunLoopGetCurrent());
  339. }
  340. void EventLoopImplementationMacOS::post_event(Core::EventReceiver& receiver, NonnullOwnPtr<Core::Event>&& event)
  341. {
  342. m_thread_event_queue.post_event(receiver, move(event));
  343. if (&m_thread_event_queue != &Core::ThreadEventQueue::current())
  344. wake();
  345. }
  346. }