EventLoopImplementation.mm 13 KB

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