From c1a424a6357443d5effbc07412a401df443ed8cd Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 17 Mar 2026 20:24:06 +0200 Subject: [PATCH] Kernel: Implement linux's eventfd --- kernel/include/kernel/FS/EventFD.h | 52 ++++++++++++++++++ kernel/include/kernel/Process.h | 2 + kernel/kernel/FS/EventFD.cpp | 54 +++++++++++++++++++ kernel/kernel/Process.cpp | 23 ++++++++ .../libraries/LibC/include/sys/eventfd.h | 16 ++++++ .../libraries/LibC/include/sys/syscall.h | 1 + userspace/libraries/LibC/sys/eventfd.cpp | 8 +++ 7 files changed, 156 insertions(+) create mode 100644 kernel/include/kernel/FS/EventFD.h create mode 100644 kernel/kernel/FS/EventFD.cpp create mode 100644 userspace/libraries/LibC/include/sys/eventfd.h create mode 100644 userspace/libraries/LibC/sys/eventfd.cpp diff --git a/kernel/include/kernel/FS/EventFD.h b/kernel/include/kernel/FS/EventFD.h new file mode 100644 index 00000000..89c97cc5 --- /dev/null +++ b/kernel/include/kernel/FS/EventFD.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +namespace Kernel +{ + + class EventFD final : public Inode + { + public: + static BAN::ErrorOr> create(uint64_t initval, bool semaphore); + + ino_t ino() const override { return 0; } + Mode mode() const override { return { Mode::IFCHR | Mode::IRUSR | Mode::IWUSR }; } + nlink_t nlink() const override { return ref_count(); } + uid_t uid() const override { return 0; } + gid_t gid() const override { return 0; } + off_t size() const override { return 0; } + timespec atime() const override { return {}; } + timespec mtime() const override { return {}; } + timespec ctime() const override { return {}; } + blksize_t blksize() const override { return 8; } + blkcnt_t blocks() const override { return 0; } + dev_t dev() const override { return 0; } + dev_t rdev() const override { return 0; } + + const FileSystem* filesystem() const override { return nullptr; } + + protected: + BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; + BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override; + BAN::ErrorOr fsync_impl() final override { return {}; } + + bool can_read_impl() const override { return m_value > 0; } + bool can_write_impl() const override { return m_value < UINT64_MAX - 1; } + bool has_error_impl() const override { return false; } + bool has_hungup_impl() const override { return false; } + + private: + EventFD(uint64_t initval, bool is_semaphore) + : m_is_semaphore(is_semaphore) + , m_value(initval) + { } + + private: + const bool m_is_semaphore; + uint64_t m_value; + + ThreadBlocker m_thread_blocker; + }; + +} diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 34cff894..fea857d7 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -147,6 +147,8 @@ namespace Kernel BAN::ErrorOr sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event); BAN::ErrorOr sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask); + BAN::ErrorOr sys_eventfd(unsigned int initval_hi, int flags); + BAN::ErrorOr sys_pipe(int fildes[2]); BAN::ErrorOr sys_dup2(int fildes, int fildes2); diff --git a/kernel/kernel/FS/EventFD.cpp b/kernel/kernel/FS/EventFD.cpp new file mode 100644 index 00000000..3fc50a60 --- /dev/null +++ b/kernel/kernel/FS/EventFD.cpp @@ -0,0 +1,54 @@ +#include + +#include + +namespace Kernel +{ + + BAN::ErrorOr> EventFD::create(uint64_t initval, bool semaphore) + { + auto* eventfd_ptr = new EventFD(initval, semaphore); + if (eventfd_ptr == nullptr) + return BAN::Error::from_errno(ENOMEM); + return BAN::RefPtr(BAN::RefPtr::adopt(eventfd_ptr)); + } + + BAN::ErrorOr EventFD::read_impl(off_t, BAN::ByteSpan buffer) + { + if (buffer.size() < sizeof(uint64_t)) + return BAN::Error::from_errno(EINVAL); + + while (m_value == 0) + TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); + + const uint64_t read_value = m_is_semaphore ? 1 : m_value; + m_value -= read_value; + + buffer.as() = read_value; + + epoll_notify(EPOLLOUT); + + return sizeof(uint64_t); + } + + BAN::ErrorOr EventFD::write_impl(off_t, BAN::ConstByteSpan buffer) + { + if (buffer.size() < sizeof(uint64_t)) + return BAN::Error::from_errno(EINVAL); + + const uint64_t write_value = buffer.as(); + if (write_value == UINT64_MAX) + return BAN::Error::from_errno(EINVAL); + + while (m_value + write_value < m_value) + TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); + + m_value += write_value; + + if (m_value > 0) + epoll_notify(EPOLLIN); + + return sizeof(uint64_t); + } + +} diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index fa8df3ac..42dcfc33 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -2160,6 +2162,27 @@ namespace Kernel return TRY(static_cast(epoll_inode.ptr())->wait(BAN::Span(events, maxevents), waketime_ns)); } + BAN::ErrorOr Process::sys_eventfd(unsigned int initval, int flags) + { + if (flags & ~(EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE)) + return BAN::Error::from_errno(EINVAL); + + int oflags = 0; + if (flags & EFD_CLOEXEC) + oflags |= O_CLOEXEC; + if (flags & EFD_NONBLOCK) + oflags |= O_NONBLOCK; + + const bool is_semaphore = !!(flags & EFD_SEMAPHORE); + + return TRY(m_open_file_descriptors.open( + VirtualFileSystem::File { + TRY(EventFD::create(initval, is_semaphore)), + ""_sv + }, oflags + )); + } + BAN::ErrorOr Process::sys_pipe(int user_fildes[2]) { int fildes[2]; diff --git a/userspace/libraries/LibC/include/sys/eventfd.h b/userspace/libraries/LibC/include/sys/eventfd.h new file mode 100644 index 00000000..e7a16d10 --- /dev/null +++ b/userspace/libraries/LibC/include/sys/eventfd.h @@ -0,0 +1,16 @@ +#ifndef _SYS_EVENTFD_H +#define _SYS_EVENTFD_H 1 + +#include + +__BEGIN_DECLS + +#define EFD_CLOEXEC 0x1 +#define EFD_NONBLOCK 0x2 +#define EFD_SEMAPHORE 0x4 + +int eventfd(unsigned int initval, int flags); + +__END_DECLS + +#endif diff --git a/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index 8105cfee..4798b58c 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -119,6 +119,7 @@ __BEGIN_DECLS O(SYS_GETGROUPS, getgroups) \ O(SYS_SETGROUPS, setgroups) \ O(SYS_CHROOT, chroot) \ + O(SYS_EVENTFD, eventfd) \ enum Syscall { diff --git a/userspace/libraries/LibC/sys/eventfd.cpp b/userspace/libraries/LibC/sys/eventfd.cpp new file mode 100644 index 00000000..3b539478 --- /dev/null +++ b/userspace/libraries/LibC/sys/eventfd.cpp @@ -0,0 +1,8 @@ +#include +#include +#include + +int eventfd(unsigned int initval, int flags) +{ + return syscall(SYS_EVENTFD, initval, flags); +}