opuntiaOS - an operating system targeting x86 and ARMv7
at master 2.8 kB view raw
1/* 2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors. 3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com> 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include <cstring> 10#include <ctime> 11#include <iostream> 12#include <libfoundation/EventLoop.h> 13#include <libfoundation/Logger.h> 14#include <memory> 15#include <sched.h> 16#include <sys/select.h> 17#include <sys/time.h> 18#include <unistd.h> 19 20namespace LFoundation { 21 22EventLoop* s_LFoundation_EventLoop_the = nullptr; 23 24EventLoop::EventLoop() 25{ 26 s_LFoundation_EventLoop_the = this; 27} 28 29void EventLoop::check_fds() 30{ 31 if (m_waiting_fds.empty()) { 32 return; 33 } 34 fd_set_t readfds; 35 fd_set_t writefds; 36 FD_ZERO(&readfds); 37 FD_ZERO(&writefds); 38 int nfds = -1; 39 for (int i = 0; i < m_waiting_fds.size(); i++) { 40 if (m_waiting_fds[i].m_on_read) { 41 FD_SET(m_waiting_fds[i].m_fd, &readfds); 42 } 43 if (m_waiting_fds[i].m_on_write) { 44 FD_SET(m_waiting_fds[i].m_fd, &writefds); 45 } 46 if (nfds < m_waiting_fds[i].m_fd) { 47 nfds = m_waiting_fds[i].m_fd; 48 } 49 } 50 51 // For now, that means, that we don't wait for fds. 52 timeval_t timeout; 53 timeout.tv_sec = 0; 54 timeout.tv_usec = 0; 55 56 int res = select(nfds + 1, &readfds, &writefds, nullptr, &timeout); 57 58 for (int i = 0; i < m_waiting_fds.size(); i++) { 59 if (m_waiting_fds[i].m_on_read) { 60 if (FD_ISSET(m_waiting_fds[i].m_fd, &readfds)) { 61 m_event_queue.push_back(QueuedEvent(m_waiting_fds[i], new FDWaiterReadEvent())); 62 } 63 } 64 if (m_waiting_fds[i].m_on_write) { 65 if (FD_ISSET(m_waiting_fds[i].m_fd, &writefds)) { 66 m_event_queue.push_back(QueuedEvent(m_waiting_fds[i], new FDWaiterWriteEvent())); 67 } 68 } 69 } 70} 71 72void EventLoop::check_timers() 73{ 74 if (m_timers.empty()) { 75 return; 76 } 77 78 std::timespec tp; 79 clock_gettime(CLOCK_MONOTONIC, &tp); 80 81 for (auto& timer : m_timers) { 82 if (!timer.expired(tp)) { 83 continue; 84 } 85 86 m_event_queue.push_back(QueuedEvent(timer, new TimerEvent())); 87 88 if (timer.repeated()) { 89 timer.reload(tp); 90 } 91 } 92} 93 94[[gnu::flatten]] void EventLoop::pump() 95{ 96 check_fds(); 97 check_timers(); 98 std::vector<QueuedEvent> events_to_dispatch(std::move(m_event_queue)); 99 m_event_queue.clear(); 100 for (auto& event : events_to_dispatch) { 101 event.receiver.receive_event(std::move(event.event)); 102 } 103 104 if (!events_to_dispatch.size()) { 105 sched_yield(); 106 } 107} 108 109int EventLoop::run() 110{ 111 while (!m_stop_flag) { 112 pump(); 113 } 114 return m_exit_code; 115} 116 117} // namespace LFoundation