Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, kleines Filmröllchen <malu.bertsch@gmail.com>
4 * Copyright (c) 2022, the SerenityOS developers.
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 */
8
9#include <AK/Assertions.h>
10#include <AK/Badge.h>
11#include <AK/Debug.h>
12#include <AK/Format.h>
13#include <AK/IDAllocator.h>
14#include <AK/JsonObject.h>
15#include <AK/JsonValue.h>
16#include <AK/NeverDestroyed.h>
17#include <AK/Singleton.h>
18#include <AK/TemporaryChange.h>
19#include <AK/Time.h>
20#include <LibCore/Event.h>
21#include <LibCore/EventLoop.h>
22#include <LibCore/LocalServer.h>
23#include <LibCore/Notifier.h>
24#include <LibCore/Object.h>
25#include <LibCore/Promise.h>
26#include <LibCore/SessionManagement.h>
27#include <LibCore/Socket.h>
28#include <LibThreading/Mutex.h>
29#include <LibThreading/MutexProtected.h>
30#include <errno.h>
31#include <fcntl.h>
32#include <signal.h>
33#include <stdio.h>
34#include <string.h>
35#include <sys/select.h>
36#include <sys/socket.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <time.h>
40#include <unistd.h>
41
42#ifdef AK_OS_SERENITY
43# include <LibCore/Account.h>
44
45extern bool s_global_initializers_ran;
46#endif
47
48namespace Core {
49
50class InspectorServerConnection;
51
52[[maybe_unused]] static bool connect_to_inspector_server();
53
54struct EventLoopTimer {
55 int timer_id { 0 };
56 Time interval;
57 Time fire_time;
58 bool should_reload { false };
59 TimerShouldFireWhenNotVisible fire_when_not_visible { TimerShouldFireWhenNotVisible::No };
60 WeakPtr<Object> owner;
61
62 void reload(Time const& now);
63 bool has_expired(Time const& now) const;
64};
65
66struct EventLoop::Private {
67 Threading::Mutex lock;
68};
69
70static Threading::MutexProtected<NeverDestroyed<IDAllocator>> s_id_allocator;
71static Threading::MutexProtected<RefPtr<InspectorServerConnection>> s_inspector_server_connection;
72
73// Each thread has its own event loop stack, its own timers, notifiers and a wake pipe.
74static thread_local Vector<EventLoop&>* s_event_loop_stack;
75static thread_local HashMap<int, NonnullOwnPtr<EventLoopTimer>>* s_timers;
76static thread_local HashTable<Notifier*>* s_notifiers;
77// The wake pipe is both responsible for notifying us when someone calls wake(), as well as POSIX signals.
78// While wake() pushes zero into the pipe, signal numbers (by defintion nonzero, see signal_numbers.h) are pushed into the pipe verbatim.
79thread_local int EventLoop::s_wake_pipe_fds[2];
80thread_local bool EventLoop::s_wake_pipe_initialized { false };
81thread_local bool s_warned_promise_count { false };
82
83void EventLoop::initialize_wake_pipes()
84{
85 if (!s_wake_pipe_initialized) {
86#if defined(SOCK_NONBLOCK)
87 int rc = pipe2(s_wake_pipe_fds, O_CLOEXEC);
88#else
89 int rc = pipe(s_wake_pipe_fds);
90 fcntl(s_wake_pipe_fds[0], F_SETFD, FD_CLOEXEC);
91 fcntl(s_wake_pipe_fds[1], F_SETFD, FD_CLOEXEC);
92
93#endif
94 VERIFY(rc == 0);
95 s_wake_pipe_initialized = true;
96 }
97}
98
99bool EventLoop::has_been_instantiated()
100{
101 return s_event_loop_stack != nullptr && !s_event_loop_stack->is_empty();
102}
103
104class SignalHandlers : public RefCounted<SignalHandlers> {
105 AK_MAKE_NONCOPYABLE(SignalHandlers);
106 AK_MAKE_NONMOVABLE(SignalHandlers);
107
108public:
109 SignalHandlers(int signo, void (*handle_signal)(int));
110 ~SignalHandlers();
111
112 void dispatch();
113 int add(Function<void(int)>&& handler);
114 bool remove(int handler_id);
115
116 bool is_empty() const
117 {
118 if (m_calling_handlers) {
119 for (auto& handler : m_handlers_pending) {
120 if (handler.value)
121 return false; // an add is pending
122 }
123 }
124 return m_handlers.is_empty();
125 }
126
127 bool have(int handler_id) const
128 {
129 if (m_calling_handlers) {
130 auto it = m_handlers_pending.find(handler_id);
131 if (it != m_handlers_pending.end()) {
132 if (!it->value)
133 return false; // a deletion is pending
134 }
135 }
136 return m_handlers.contains(handler_id);
137 }
138
139 int m_signo;
140 void (*m_original_handler)(int); // TODO: can't use sighandler_t?
141 HashMap<int, Function<void(int)>> m_handlers;
142 HashMap<int, Function<void(int)>> m_handlers_pending;
143 bool m_calling_handlers { false };
144};
145
146struct SignalHandlersInfo {
147 HashMap<int, NonnullRefPtr<SignalHandlers>> signal_handlers;
148 int next_signal_id { 0 };
149};
150
151static Singleton<SignalHandlersInfo> s_signals;
152template<bool create_if_null = true>
153inline SignalHandlersInfo* signals_info()
154{
155 return s_signals.ptr();
156}
157
158pid_t EventLoop::s_pid;
159
160class InspectorServerConnection : public Object {
161 C_OBJECT(InspectorServerConnection)
162private:
163 explicit InspectorServerConnection(NonnullOwnPtr<LocalSocket> socket)
164 : m_socket(move(socket))
165 , m_client_id(s_id_allocator.with_locked([](auto& allocator) {
166 return allocator->allocate();
167 }))
168 {
169#ifdef AK_OS_SERENITY
170 m_socket->on_ready_to_read = [this] {
171 u32 length;
172 auto maybe_bytes_read = m_socket->read_some({ (u8*)&length, sizeof(length) });
173 if (maybe_bytes_read.is_error()) {
174 dbgln("InspectorServerConnection: Failed to read message length from inspector server connection: {}", maybe_bytes_read.error());
175 shutdown();
176 return;
177 }
178
179 auto bytes_read = maybe_bytes_read.release_value();
180 if (bytes_read.is_empty()) {
181 dbgln_if(EVENTLOOP_DEBUG, "RPC client disconnected");
182 shutdown();
183 return;
184 }
185
186 VERIFY(bytes_read.size() == sizeof(length));
187
188 auto request_buffer = ByteBuffer::create_uninitialized(length).release_value();
189 maybe_bytes_read = m_socket->read_some(request_buffer.bytes());
190 if (maybe_bytes_read.is_error()) {
191 dbgln("InspectorServerConnection: Failed to read message content from inspector server connection: {}", maybe_bytes_read.error());
192 shutdown();
193 return;
194 }
195
196 bytes_read = maybe_bytes_read.release_value();
197
198 auto request_json = JsonValue::from_string(request_buffer);
199 if (request_json.is_error() || !request_json.value().is_object()) {
200 dbgln("RPC client sent invalid request");
201 shutdown();
202 return;
203 }
204
205 handle_request(request_json.value().as_object());
206 };
207#else
208 warnln("RPC Client constructed outside serenity, this is very likely a bug!");
209#endif
210 }
211 virtual ~InspectorServerConnection() override
212 {
213 if (auto inspected_object = m_inspected_object.strong_ref())
214 inspected_object->decrement_inspector_count({});
215 }
216
217public:
218 void send_response(JsonObject const& response)
219 {
220 auto serialized = response.to_deprecated_string();
221 auto bytes_to_send = serialized.bytes();
222 u32 length = bytes_to_send.size();
223 // FIXME: Propagate errors
224 MUST(m_socket->write_value(length));
225 while (!bytes_to_send.is_empty()) {
226 size_t bytes_sent = MUST(m_socket->write_some(bytes_to_send));
227 bytes_to_send = bytes_to_send.slice(bytes_sent);
228 }
229 }
230
231 void handle_request(JsonObject const& request)
232 {
233 auto type = request.get_deprecated_string("type"sv);
234
235 if (!type.has_value()) {
236 dbgln("RPC client sent request without type field");
237 return;
238 }
239
240 if (type == "Identify") {
241 JsonObject response;
242 response.set("type", type.value());
243 response.set("pid", getpid());
244#ifdef AK_OS_SERENITY
245 char buffer[1024];
246 if (get_process_name(buffer, sizeof(buffer)) >= 0) {
247 response.set("process_name", buffer);
248 } else {
249 response.set("process_name", JsonValue());
250 }
251#endif
252 send_response(response);
253 return;
254 }
255
256 if (type == "GetAllObjects") {
257 JsonObject response;
258 response.set("type", type.value());
259 JsonArray objects;
260 for (auto& object : Object::all_objects()) {
261 JsonObject json_object;
262 object.save_to(json_object);
263 objects.append(move(json_object));
264 }
265 response.set("objects", move(objects));
266 send_response(response);
267 return;
268 }
269
270 if (type == "SetInspectedObject") {
271 auto address = request.get_addr("address"sv);
272 for (auto& object : Object::all_objects()) {
273 if ((FlatPtr)&object == address) {
274 if (auto inspected_object = m_inspected_object.strong_ref())
275 inspected_object->decrement_inspector_count({});
276 m_inspected_object = object;
277 object.increment_inspector_count({});
278 break;
279 }
280 }
281 return;
282 }
283
284 if (type == "SetProperty") {
285 auto address = request.get_addr("address"sv);
286 for (auto& object : Object::all_objects()) {
287 if ((FlatPtr)&object == address) {
288 bool success = object.set_property(request.get_deprecated_string("name"sv).value(), request.get("value"sv).value());
289 JsonObject response;
290 response.set("type", "SetProperty");
291 response.set("success", success);
292 send_response(response);
293 break;
294 }
295 }
296 return;
297 }
298
299 if (type == "Disconnect") {
300 shutdown();
301 return;
302 }
303 }
304
305 void shutdown()
306 {
307 s_id_allocator.with_locked([this](auto& allocator) { allocator->deallocate(m_client_id); });
308 }
309
310private:
311 NonnullOwnPtr<LocalSocket> m_socket;
312 WeakPtr<Object> m_inspected_object;
313 int m_client_id { -1 };
314};
315
316EventLoop::EventLoop([[maybe_unused]] MakeInspectable make_inspectable)
317 : m_wake_pipe_fds(&s_wake_pipe_fds)
318 , m_private(make<Private>())
319{
320#ifdef AK_OS_SERENITY
321 if (!s_global_initializers_ran) {
322 // NOTE: Trying to have an event loop as a global variable will lead to initialization-order fiascos,
323 // as the event loop constructor accesses and/or sets other global variables.
324 // Therefore, we crash the program before ASAN catches us.
325 // If you came here because of the assertion failure, please redesign your program to not have global event loops.
326 // The common practice is to initialize the main event loop in the main function, and if necessary,
327 // pass event loop references around or access them with EventLoop::with_main_locked() and EventLoop::current().
328 VERIFY_NOT_REACHED();
329 }
330#endif
331
332 if (!s_event_loop_stack) {
333 s_event_loop_stack = new Vector<EventLoop&>;
334 s_timers = new HashMap<int, NonnullOwnPtr<EventLoopTimer>>;
335 s_notifiers = new HashTable<Notifier*>;
336 }
337
338 if (s_event_loop_stack->is_empty()) {
339 s_pid = getpid();
340 s_event_loop_stack->append(*this);
341
342#ifdef AK_OS_SERENITY
343 if (getuid() != 0) {
344 if (getenv("MAKE_INSPECTABLE") == "1"sv)
345 make_inspectable = Core::EventLoop::MakeInspectable::Yes;
346
347 if (make_inspectable == MakeInspectable::Yes
348 && !s_inspector_server_connection.with_locked([](auto inspector_server_connection) { return inspector_server_connection; })) {
349 if (!connect_to_inspector_server())
350 dbgln("Core::EventLoop: Failed to connect to InspectorServer");
351 }
352 }
353#endif
354 }
355
356 initialize_wake_pipes();
357
358 dbgln_if(EVENTLOOP_DEBUG, "{} Core::EventLoop constructed :)", getpid());
359}
360
361EventLoop::~EventLoop()
362{
363 if (!s_event_loop_stack->is_empty() && &s_event_loop_stack->last() == this)
364 s_event_loop_stack->take_last();
365}
366
367bool connect_to_inspector_server()
368{
369#ifdef AK_OS_SERENITY
370 auto maybe_path = SessionManagement::parse_path_with_sid("/tmp/session/%sid/portal/inspectables"sv);
371 if (maybe_path.is_error()) {
372 dbgln("connect_to_inspector_server: {}", maybe_path.error());
373 return false;
374 }
375 auto inspector_server_path = maybe_path.value();
376 auto maybe_socket = LocalSocket::connect(inspector_server_path, Socket::PreventSIGPIPE::Yes);
377 if (maybe_socket.is_error()) {
378 dbgln("connect_to_inspector_server: Failed to connect: {}", maybe_socket.error());
379 return false;
380 }
381 s_inspector_server_connection.with_locked([&](auto& inspector_server_connection) {
382 inspector_server_connection = InspectorServerConnection::construct(maybe_socket.release_value());
383 });
384 return true;
385#else
386 VERIFY_NOT_REACHED();
387#endif
388}
389
390#define VERIFY_EVENT_LOOP_INITIALIZED() \
391 do { \
392 if (!s_event_loop_stack) { \
393 warnln("EventLoop static API was called without prior EventLoop init!"); \
394 VERIFY_NOT_REACHED(); \
395 } \
396 } while (0)
397
398EventLoop& EventLoop::current()
399{
400 VERIFY_EVENT_LOOP_INITIALIZED();
401 return s_event_loop_stack->last();
402}
403
404void EventLoop::quit(int code)
405{
406 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::quit({})", code);
407 m_exit_requested = true;
408 m_exit_code = code;
409}
410
411void EventLoop::unquit()
412{
413 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::unquit()");
414 m_exit_requested = false;
415 m_exit_code = 0;
416}
417
418struct EventLoopPusher {
419public:
420 EventLoopPusher(EventLoop& event_loop)
421 : m_event_loop(event_loop)
422 {
423 if (EventLoop::has_been_instantiated()) {
424 m_event_loop.take_pending_events_from(EventLoop::current());
425 s_event_loop_stack->append(event_loop);
426 }
427 }
428 ~EventLoopPusher()
429 {
430 if (EventLoop::has_been_instantiated()) {
431 s_event_loop_stack->take_last();
432 for (auto& job : m_event_loop.m_pending_promises) {
433 // When this event loop was not running below another event loop, the jobs may very well have finished in the meantime.
434 if (!job->is_resolved())
435 job->cancel(Error::from_string_view("EventLoop is exiting"sv));
436 }
437 EventLoop::current().take_pending_events_from(m_event_loop);
438 }
439 }
440
441private:
442 EventLoop& m_event_loop;
443};
444
445int EventLoop::exec()
446{
447 EventLoopPusher pusher(*this);
448 for (;;) {
449 if (m_exit_requested)
450 return m_exit_code;
451 pump();
452 }
453 VERIFY_NOT_REACHED();
454}
455
456void EventLoop::spin_until(Function<bool()> goal_condition)
457{
458 EventLoopPusher pusher(*this);
459 while (!goal_condition())
460 pump();
461}
462
463size_t EventLoop::pump(WaitMode mode)
464{
465 wait_for_event(mode);
466
467 decltype(m_queued_events) events;
468 {
469 Threading::MutexLocker locker(m_private->lock);
470 events = move(m_queued_events);
471 }
472
473 m_pending_promises.remove_all_matching([](auto& job) { return job->is_resolved() || job->is_canceled(); });
474
475 size_t processed_events = 0;
476 for (size_t i = 0; i < events.size(); ++i) {
477 auto& queued_event = events.at(i);
478 auto receiver = queued_event.receiver.strong_ref();
479 auto& event = *queued_event.event;
480 if (receiver)
481 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop: {} event {}", *receiver, event.type());
482
483 if (!receiver) {
484 switch (event.type()) {
485 case Event::Quit:
486 VERIFY_NOT_REACHED();
487 default:
488 dbgln_if(EVENTLOOP_DEBUG, "Event type {} with no receiver :(", event.type());
489 break;
490 }
491 } else if (event.type() == Event::Type::DeferredInvoke) {
492 dbgln_if(DEFERRED_INVOKE_DEBUG, "DeferredInvoke: receiver = {}", *receiver);
493 static_cast<DeferredInvocationEvent&>(event).m_invokee();
494 } else {
495 NonnullRefPtr<Object> protector(*receiver);
496 receiver->dispatch_event(event);
497 }
498 ++processed_events;
499
500 if (m_exit_requested) {
501 Threading::MutexLocker locker(m_private->lock);
502 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop: Exit requested. Rejigging {} events.", events.size() - i);
503 decltype(m_queued_events) new_event_queue;
504 new_event_queue.ensure_capacity(m_queued_events.size() + events.size());
505 for (++i; i < events.size(); ++i)
506 new_event_queue.unchecked_append(move(events[i]));
507 new_event_queue.extend(move(m_queued_events));
508 m_queued_events = move(new_event_queue);
509 break;
510 }
511 }
512
513 if (m_pending_promises.size() > 30 && !s_warned_promise_count) {
514 s_warned_promise_count = true;
515 dbgln("EventLoop {:p} warning: Job queue wasn't designed for this load ({} promises). Please begin optimizing EventLoop::pump() -> m_pending_promises.remove_all_matching", this, m_pending_promises.size());
516 }
517
518 return processed_events;
519}
520
521void EventLoop::post_event(Object& receiver, NonnullOwnPtr<Event>&& event, ShouldWake should_wake)
522{
523 Threading::MutexLocker lock(m_private->lock);
524 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::post_event: ({}) << receiver={}, event={}", m_queued_events.size(), receiver, event);
525 m_queued_events.empend(receiver, move(event));
526 if (should_wake == ShouldWake::Yes)
527 wake();
528}
529
530void EventLoop::wake_once(Object& receiver, int custom_event_type)
531{
532 Threading::MutexLocker lock(m_private->lock);
533 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::wake_once: event type {}", custom_event_type);
534 auto identical_events = m_queued_events.find_if([&](auto& queued_event) {
535 if (queued_event.receiver.is_null())
536 return false;
537 auto const& event = queued_event.event;
538 auto is_receiver_identical = queued_event.receiver.ptr() == &receiver;
539 auto event_id_matches = event->type() == Event::Type::Custom && static_cast<CustomEvent const*>(event.ptr())->custom_type() == custom_event_type;
540 return is_receiver_identical && event_id_matches;
541 });
542 // Event is not in the queue yet, so we want to wake.
543 if (identical_events.is_end())
544 post_event(receiver, make<CustomEvent>(custom_event_type), ShouldWake::Yes);
545}
546
547void EventLoop::add_job(NonnullRefPtr<Promise<NonnullRefPtr<Object>>> job_promise)
548{
549 m_pending_promises.append(move(job_promise));
550}
551
552SignalHandlers::SignalHandlers(int signo, void (*handle_signal)(int))
553 : m_signo(signo)
554 , m_original_handler(signal(signo, handle_signal))
555{
556 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop: Registered handler for signal {}", m_signo);
557}
558
559SignalHandlers::~SignalHandlers()
560{
561 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop: Unregistering handler for signal {}", m_signo);
562 signal(m_signo, m_original_handler);
563}
564
565void SignalHandlers::dispatch()
566{
567 TemporaryChange change(m_calling_handlers, true);
568 for (auto& handler : m_handlers)
569 handler.value(m_signo);
570 if (!m_handlers_pending.is_empty()) {
571 // Apply pending adds/removes
572 for (auto& handler : m_handlers_pending) {
573 if (handler.value) {
574 auto result = m_handlers.set(handler.key, move(handler.value));
575 VERIFY(result == AK::HashSetResult::InsertedNewEntry);
576 } else {
577 m_handlers.remove(handler.key);
578 }
579 }
580 m_handlers_pending.clear();
581 }
582}
583
584int SignalHandlers::add(Function<void(int)>&& handler)
585{
586 int id = ++signals_info()->next_signal_id; // TODO: worry about wrapping and duplicates?
587 if (m_calling_handlers)
588 m_handlers_pending.set(id, move(handler));
589 else
590 m_handlers.set(id, move(handler));
591 return id;
592}
593
594bool SignalHandlers::remove(int handler_id)
595{
596 VERIFY(handler_id != 0);
597 if (m_calling_handlers) {
598 auto it = m_handlers.find(handler_id);
599 if (it != m_handlers.end()) {
600 // Mark pending remove
601 m_handlers_pending.set(handler_id, {});
602 return true;
603 }
604 it = m_handlers_pending.find(handler_id);
605 if (it != m_handlers_pending.end()) {
606 if (!it->value)
607 return false; // already was marked as deleted
608 it->value = nullptr;
609 return true;
610 }
611 return false;
612 }
613 return m_handlers.remove(handler_id);
614}
615
616void EventLoop::dispatch_signal(int signo)
617{
618 auto& info = *signals_info();
619 auto handlers = info.signal_handlers.find(signo);
620 if (handlers != info.signal_handlers.end()) {
621 // Make sure we bump the ref count while dispatching the handlers!
622 // This allows a handler to unregister/register while the handlers
623 // are being called!
624 auto handler = handlers->value;
625 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop: dispatching signal {}", signo);
626 handler->dispatch();
627 }
628}
629
630void EventLoop::handle_signal(int signo)
631{
632 VERIFY(signo != 0);
633 // We MUST check if the current pid still matches, because there
634 // is a window between fork() and exec() where a signal delivered
635 // to our fork could be inadvertently routed to the parent process!
636 if (getpid() == s_pid) {
637 int nwritten = write(s_wake_pipe_fds[1], &signo, sizeof(signo));
638 if (nwritten < 0) {
639 perror("EventLoop::register_signal: write");
640 VERIFY_NOT_REACHED();
641 }
642 } else {
643 // We're a fork who received a signal, reset s_pid
644 s_pid = 0;
645 }
646}
647
648int EventLoop::register_signal(int signo, Function<void(int)> handler)
649{
650 VERIFY(signo != 0);
651 auto& info = *signals_info();
652 auto handlers = info.signal_handlers.find(signo);
653 if (handlers == info.signal_handlers.end()) {
654 auto signal_handlers = adopt_ref(*new SignalHandlers(signo, EventLoop::handle_signal));
655 auto handler_id = signal_handlers->add(move(handler));
656 info.signal_handlers.set(signo, move(signal_handlers));
657 return handler_id;
658 } else {
659 return handlers->value->add(move(handler));
660 }
661}
662
663void EventLoop::unregister_signal(int handler_id)
664{
665 VERIFY(handler_id != 0);
666 int remove_signo = 0;
667 auto& info = *signals_info();
668 for (auto& h : info.signal_handlers) {
669 auto& handlers = *h.value;
670 if (handlers.remove(handler_id)) {
671 if (handlers.is_empty())
672 remove_signo = handlers.m_signo;
673 break;
674 }
675 }
676 if (remove_signo != 0)
677 info.signal_handlers.remove(remove_signo);
678}
679
680void EventLoop::notify_forked(ForkEvent event)
681{
682 VERIFY_EVENT_LOOP_INITIALIZED();
683 switch (event) {
684 case ForkEvent::Child:
685 s_event_loop_stack->clear();
686 s_timers->clear();
687 s_notifiers->clear();
688 s_wake_pipe_initialized = false;
689 initialize_wake_pipes();
690 if (auto* info = signals_info<false>()) {
691 info->signal_handlers.clear();
692 info->next_signal_id = 0;
693 }
694 s_pid = 0;
695 return;
696 }
697
698 VERIFY_NOT_REACHED();
699}
700
701void EventLoop::wait_for_event(WaitMode mode)
702{
703 fd_set rfds;
704 fd_set wfds;
705retry:
706
707 // Set up the file descriptors for select().
708 // Basically, we translate high-level event information into low-level selectable file descriptors.
709 FD_ZERO(&rfds);
710 FD_ZERO(&wfds);
711
712 int max_fd = 0;
713 auto add_fd_to_set = [&max_fd](int fd, fd_set& set) {
714 FD_SET(fd, &set);
715 if (fd > max_fd)
716 max_fd = fd;
717 };
718
719 int max_fd_added = -1;
720 // The wake pipe informs us of POSIX signals as well as manual calls to wake()
721 add_fd_to_set(s_wake_pipe_fds[0], rfds);
722 max_fd = max(max_fd, max_fd_added);
723
724 for (auto& notifier : *s_notifiers) {
725 if (notifier->event_mask() & Notifier::Read)
726 add_fd_to_set(notifier->fd(), rfds);
727 if (notifier->event_mask() & Notifier::Write)
728 add_fd_to_set(notifier->fd(), wfds);
729 if (notifier->event_mask() & Notifier::Exceptional)
730 VERIFY_NOT_REACHED();
731 }
732
733 bool queued_events_is_empty;
734 {
735 Threading::MutexLocker locker(m_private->lock);
736 queued_events_is_empty = m_queued_events.is_empty();
737 }
738
739 // Figure out how long to wait at maximum.
740 // This mainly depends on the WaitMode and whether we have pending events, but also the next expiring timer.
741 Time now;
742 struct timeval timeout = { 0, 0 };
743 bool should_wait_forever = false;
744 if (mode == WaitMode::WaitForEvents && queued_events_is_empty) {
745 auto next_timer_expiration = get_next_timer_expiration();
746 if (next_timer_expiration.has_value()) {
747 now = Time::now_monotonic_coarse();
748 auto computed_timeout = next_timer_expiration.value() - now;
749 if (computed_timeout.is_negative())
750 computed_timeout = Time::zero();
751 timeout = computed_timeout.to_timeval();
752 } else {
753 should_wait_forever = true;
754 }
755 }
756
757try_select_again:
758 // select() and wait for file system events, calls to wake(), POSIX signals, or timer expirations.
759 int marked_fd_count = select(max_fd + 1, &rfds, &wfds, nullptr, should_wait_forever ? nullptr : &timeout);
760 // Because POSIX, we might spuriously return from select() with EINTR; just select again.
761 if (marked_fd_count < 0) {
762 int saved_errno = errno;
763 if (saved_errno == EINTR) {
764 if (m_exit_requested)
765 return;
766 goto try_select_again;
767 }
768 dbgln("Core::EventLoop::wait_for_event: {} ({}: {})", marked_fd_count, saved_errno, strerror(saved_errno));
769 VERIFY_NOT_REACHED();
770 }
771
772 // We woke up due to a call to wake() or a POSIX signal.
773 // Handle signals and see whether we need to handle events as well.
774 if (FD_ISSET(s_wake_pipe_fds[0], &rfds)) {
775 int wake_events[8];
776 ssize_t nread;
777 // We might receive another signal while read()ing here. The signal will go to the handle_signal properly,
778 // but we get interrupted. Therefore, just retry while we were interrupted.
779 do {
780 errno = 0;
781 nread = read(s_wake_pipe_fds[0], wake_events, sizeof(wake_events));
782 if (nread == 0)
783 break;
784 } while (nread < 0 && errno == EINTR);
785 if (nread < 0) {
786 perror("Core::EventLoop::wait_for_event: read from wake pipe");
787 VERIFY_NOT_REACHED();
788 }
789 VERIFY(nread > 0);
790 bool wake_requested = false;
791 int event_count = nread / sizeof(wake_events[0]);
792 for (int i = 0; i < event_count; i++) {
793 if (wake_events[i] != 0)
794 dispatch_signal(wake_events[i]);
795 else
796 wake_requested = true;
797 }
798
799 if (!wake_requested && nread == sizeof(wake_events))
800 goto retry;
801 }
802
803 if (!s_timers->is_empty()) {
804 now = Time::now_monotonic_coarse();
805 }
806
807 // Handle expired timers.
808 for (auto& it : *s_timers) {
809 auto& timer = *it.value;
810 if (!timer.has_expired(now))
811 continue;
812 auto owner = timer.owner.strong_ref();
813 if (timer.fire_when_not_visible == TimerShouldFireWhenNotVisible::No
814 && owner && !owner->is_visible_for_timer_purposes()) {
815 continue;
816 }
817
818 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop: Timer {} has expired, sending Core::TimerEvent to {}", timer.timer_id, *owner);
819
820 if (owner)
821 post_event(*owner, make<TimerEvent>(timer.timer_id));
822 if (timer.should_reload) {
823 timer.reload(now);
824 } else {
825 // FIXME: Support removing expired timers that don't want to reload.
826 VERIFY_NOT_REACHED();
827 }
828 }
829
830 if (!marked_fd_count)
831 return;
832
833 // Handle file system notifiers by making them normal events.
834 for (auto& notifier : *s_notifiers) {
835 if (FD_ISSET(notifier->fd(), &rfds)) {
836 if (notifier->event_mask() & Notifier::Event::Read)
837 post_event(*notifier, make<NotifierReadEvent>(notifier->fd()));
838 }
839 if (FD_ISSET(notifier->fd(), &wfds)) {
840 if (notifier->event_mask() & Notifier::Event::Write)
841 post_event(*notifier, make<NotifierWriteEvent>(notifier->fd()));
842 }
843 }
844}
845
846bool EventLoopTimer::has_expired(Time const& now) const
847{
848 return now > fire_time;
849}
850
851void EventLoopTimer::reload(Time const& now)
852{
853 fire_time = now + interval;
854}
855
856Optional<Time> EventLoop::get_next_timer_expiration()
857{
858 auto now = Time::now_monotonic_coarse();
859 Optional<Time> soonest {};
860 for (auto& it : *s_timers) {
861 auto& fire_time = it.value->fire_time;
862 auto owner = it.value->owner.strong_ref();
863 if (it.value->fire_when_not_visible == TimerShouldFireWhenNotVisible::No
864 && owner && !owner->is_visible_for_timer_purposes()) {
865 continue;
866 }
867 // OPTIMIZATION: If we have a timer that needs to fire right away, we can stop looking here.
868 // FIXME: This whole operation could be O(1) with a better data structure.
869 if (fire_time < now)
870 return now;
871 if (!soonest.has_value() || fire_time < soonest.value())
872 soonest = fire_time;
873 }
874 return soonest;
875}
876
877int EventLoop::register_timer(Object& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible)
878{
879 VERIFY_EVENT_LOOP_INITIALIZED();
880 VERIFY(milliseconds >= 0);
881 auto timer = make<EventLoopTimer>();
882 timer->owner = object;
883 timer->interval = Time::from_milliseconds(milliseconds);
884 timer->reload(Time::now_monotonic_coarse());
885 timer->should_reload = should_reload;
886 timer->fire_when_not_visible = fire_when_not_visible;
887 int timer_id = s_id_allocator.with_locked([](auto& allocator) { return allocator->allocate(); });
888 timer->timer_id = timer_id;
889 s_timers->set(timer_id, move(timer));
890 return timer_id;
891}
892
893bool EventLoop::unregister_timer(int timer_id)
894{
895 VERIFY_EVENT_LOOP_INITIALIZED();
896 s_id_allocator.with_locked([&](auto& allocator) { allocator->deallocate(timer_id); });
897 auto it = s_timers->find(timer_id);
898 if (it == s_timers->end())
899 return false;
900 s_timers->remove(it);
901 return true;
902}
903
904void EventLoop::register_notifier(Badge<Notifier>, Notifier& notifier)
905{
906 VERIFY_EVENT_LOOP_INITIALIZED();
907 s_notifiers->set(¬ifier);
908}
909
910void EventLoop::unregister_notifier(Badge<Notifier>, Notifier& notifier)
911{
912 VERIFY_EVENT_LOOP_INITIALIZED();
913 s_notifiers->remove(¬ifier);
914}
915
916void EventLoop::wake_current()
917{
918 EventLoop::current().wake();
919}
920
921void EventLoop::wake()
922{
923 dbgln_if(EVENTLOOP_DEBUG, "Core::EventLoop::wake()");
924 int wake_event = 0;
925 int nwritten = write((*m_wake_pipe_fds)[1], &wake_event, sizeof(wake_event));
926 if (nwritten < 0) {
927 perror("EventLoop::wake: write");
928 VERIFY_NOT_REACHED();
929 }
930}
931
932EventLoop::QueuedEvent::QueuedEvent(Object& receiver, NonnullOwnPtr<Event> event)
933 : receiver(receiver)
934 , event(move(event))
935{
936}
937
938EventLoop::QueuedEvent::QueuedEvent(QueuedEvent&& other)
939 : receiver(other.receiver)
940 , event(move(other.event))
941{
942}
943
944}