diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/base/Base.cpp | 1 | ||||
-rw-r--r-- | src/base/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/base/platform/unix/EventLoop.cpp | 92 | ||||
-rw-r--r-- | src/base/platform/unix/Timer.cpp | 5 |
4 files changed, 94 insertions, 6 deletions
diff --git a/src/base/Base.cpp b/src/base/Base.cpp index 1704f8a9..c6d9ac07 100644 --- a/src/base/Base.cpp +++ b/src/base/Base.cpp @@ -4,4 +4,5 @@ namespace cru { void UnreachableCode() { std::terminate(); } +void NotImplemented() { std::terminate(); } } // namespace cru diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 300898af..7e7b0127 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -24,8 +24,8 @@ target_compile_definitions(CruBase PUBLIC $<$<CONFIG:Debug>:CRU_DEBUG>) if (UNIX AND NOT EMSCRIPTEN) target_sources(CruBase PRIVATE + platform/unix/EventLoop.cpp platform/unix/PosixSpawnSubProcess.cpp - platform/unix/Timer.cpp platform/unix/UnixFile.cpp platform/unix/UnixFileStream.cpp ) diff --git a/src/base/platform/unix/EventLoop.cpp b/src/base/platform/unix/EventLoop.cpp new file mode 100644 index 00000000..337d8a44 --- /dev/null +++ b/src/base/platform/unix/EventLoop.cpp @@ -0,0 +1,92 @@ +#include "cru/base/platform/unix/EventLoop.h" +#include "cru/base/Exception.h" + +#include <poll.h> +#include <algorithm> +#include <chrono> +#include <thread> + +namespace cru::platform::unix { +int UnixTimerFile::GetReadFd() const { return this->read_fd_; } + +UnixEventLoop::UnixEventLoop() : timer_tag_(1) {} + +int UnixEventLoop::Run() { + running_thread_ = std::this_thread::get_id(); + + pollfd poll_fds[1]; + + while (!exit_code_) { + int poll_timeout = -1; + + auto iter = std::ranges::find_if(timers_, [](const TimerData &timer) { + return timer.timeout <= std::chrono::milliseconds::zero(); + }); + if (iter != timers_.end()) { + auto &timer = *iter; + if (timer.repeat) { + while (timer.timeout <= std::chrono::milliseconds::zero()) { + timer.timeout += timer.original_timeout; + timer.action(); + } + } else { + auto action = timer.action; + timers_.erase(iter); + action(); + } + continue; + } + + if (!timers_.empty()) { + poll_timeout = + std::ranges::min_element(timers_, [](const TimerData &left, + const TimerData &right) { + return left.timeout < right.timeout; + })->timeout.count(); + } + + auto start = std::chrono::steady_clock::now(); + + ::poll(poll_fds, sizeof poll_fds / sizeof *poll_fds, poll_timeout); + + // TODO: A Big Implement to handle X events. + + auto end = std::chrono::steady_clock::now(); + auto time = + std::chrono::duration_cast<std::chrono::milliseconds>(end - start); + + for (auto &timer : timers_) { + timer.timeout -= time; + } + } + + return exit_code_.value(); +} + +void UnixEventLoop::RequestQuit(int exit_code) {} + +int UnixEventLoop::SetTimer(std::function<void()> action, + std::chrono::milliseconds timeout, bool repeat) { + if (repeat) { + if (timeout <= std::chrono::milliseconds::zero()) { + throw Exception("Interval must be bigger than 0."); + } + } else { + if (timeout < std::chrono::milliseconds::zero()) { + throw Exception("Timeout must be at least 0."); + } + } + + auto tag = timer_tag_++; + + if (std::this_thread::get_id() == running_thread_) { + timers_.push_back( + TimerData(tag, std::move(timeout), repeat, std::move(action))); + } else { + // TODO: Implement + } + + return tag; +} + +} // namespace cru::platform::unix diff --git a/src/base/platform/unix/Timer.cpp b/src/base/platform/unix/Timer.cpp deleted file mode 100644 index 25264dc8..00000000 --- a/src/base/platform/unix/Timer.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "cru/base/platform/unix/Timer.h" - -namespace cru::platform::unix { -int UnixTimerFile::GetReadFd() const { return this->read_fd_; } -} // namespace cru::platform::unix |