Kernel/LibC: Implement basic epoll

This implementation is on top of inodes instead of fds as linux does it.
If I start finding ports/software that relies on epoll allowing
duplicate inodes, I will do what linux does.

I'm probably missing multiple epoll_notify's which may cause hangs but
the system seems to work fine :dd:
This commit is contained in:
2025-05-13 10:10:35 +03:00
parent 143a00626b
commit 1bcd1edbf5
43 changed files with 627 additions and 119 deletions

View File

@@ -3,7 +3,7 @@
namespace Kernel
{
class DebugDevice : public CharacterDevice
class DebugDevice final : public CharacterDevice
{
public:
static BAN::ErrorOr<BAN::RefPtr<DebugDevice>> create(mode_t, uid_t, gid_t);
@@ -24,6 +24,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
const dev_t m_rdev;

View File

@@ -38,6 +38,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
FramebufferDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev, paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp);

View File

@@ -5,7 +5,7 @@
namespace Kernel
{
class NullDevice : public CharacterDevice
class NullDevice final : public CharacterDevice
{
public:
static BAN::ErrorOr<BAN::RefPtr<NullDevice>> create(mode_t, uid_t, gid_t);
@@ -26,6 +26,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
const dev_t m_rdev;

View File

@@ -3,7 +3,7 @@
namespace Kernel
{
class RandomDevice : public CharacterDevice
class RandomDevice final : public CharacterDevice
{
public:
static BAN::ErrorOr<BAN::RefPtr<RandomDevice>> create(mode_t, uid_t, gid_t);
@@ -24,6 +24,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
const dev_t m_rdev;

View File

@@ -3,7 +3,7 @@
namespace Kernel
{
class ZeroDevice : public CharacterDevice
class ZeroDevice final : public CharacterDevice
{
public:
static BAN::ErrorOr<BAN::RefPtr<ZeroDevice>> create(mode_t, uid_t, gid_t);
@@ -24,6 +24,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
const dev_t m_rdev;

View File

@@ -0,0 +1,68 @@
#pragma once
#include <BAN/CircularQueue.h>
#include <BAN/HashMap.h>
#include <BAN/HashSet.h>
#include <kernel/FS/Inode.h>
#include <sys/epoll.h>
namespace Kernel
{
class Epoll final : public Inode
{
public:
static BAN::ErrorOr<BAN::RefPtr<Epoll>> create();
~Epoll();
BAN::ErrorOr<void> ctl(int op, BAN::RefPtr<Inode> inode, epoll_event event);
BAN::ErrorOr<size_t> wait(BAN::Span<epoll_event> events, uint64_t waketime_ns);
void notify(BAN::RefPtr<Inode> inode, uint32_t event);
private:
Epoll() = default;
public:
ino_t ino() const override { return 0; }
Mode mode() const override { return { Mode::IRUSR | Mode::IWUSR }; }
nlink_t nlink() const override { return 0; }
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 PAGE_SIZE; }
blkcnt_t blocks() const override { return 0; }
dev_t dev() const override { return 0; }
dev_t rdev() const override { return 0; }
bool is_epoll() const override { return true; }
const FileSystem* filesystem() const override { return nullptr; }
bool can_read_impl() const override { return false; }
bool can_write_impl() const override { return false; }
bool has_error_impl() const override { return false; }
bool has_hangup_impl() const override { return false; }
BAN::ErrorOr<void> fsync_impl() override { return {}; }
private:
struct InodeRefPtrHash
{
BAN::hash_t operator()(const BAN::RefPtr<Inode>& inode)
{
return BAN::hash<const Inode*>()(inode.ptr());
}
};
private:
ThreadBlocker m_thread_blocker;
BAN::HashMap<BAN::RefPtr<Inode>, uint32_t, InodeRefPtrHash> m_ready_events;
BAN::HashMap<BAN::RefPtr<Inode>, epoll_event, InodeRefPtrHash> m_listening_events;
};
}

View File

@@ -51,6 +51,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
// Returns maximum number of data blocks in use

View File

@@ -49,6 +49,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
FATInode(FATFS& fs, const FAT::DirectoryEntry& entry, ino_t ino, uint32_t block_count)

View File

@@ -1,6 +1,7 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <BAN/LinkedList.h>
#include <BAN/RefPtr.h>
#include <BAN/String.h>
#include <BAN/StringView.h>
@@ -19,9 +20,8 @@
namespace Kernel
{
class FileSystem;
class FileBackedRegion;
class FileSystem;
class SharedFileData;
class Inode : public BAN::RefCounted<Inode>
@@ -85,6 +85,7 @@ namespace Kernel
virtual dev_t rdev() const = 0;
virtual bool is_device() const { return false; }
virtual bool is_epoll() const { return false; }
virtual bool is_pipe() const { return false; }
virtual bool is_tty() const { return false; }
@@ -123,9 +124,14 @@ namespace Kernel
bool can_read() const;
bool can_write() const;
bool has_error() const;
bool has_hangup() const;
BAN::ErrorOr<long> ioctl(int request, void* arg);
BAN::ErrorOr<void> add_epoll(class Epoll*);
void del_epoll(class Epoll*);
void epoll_notify(uint32_t event);
protected:
// Directory API
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
@@ -160,6 +166,7 @@ namespace Kernel
virtual bool can_read_impl() const = 0;
virtual bool can_write_impl() const = 0;
virtual bool has_error_impl() const = 0;
virtual bool has_hangup_impl() const = 0;
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) { return BAN::Error::from_errno(ENOTSUP); }
@@ -168,6 +175,7 @@ namespace Kernel
private:
BAN::WeakPtr<SharedFileData> m_shared_region;
BAN::LinkedList<class Epoll*> m_epolls;
friend class FileBackedRegion;
friend class OpenFileDescriptorSet;
friend class SharedFileData;

View File

@@ -40,6 +40,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return m_buffer_size > 0; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return m_writing_count == 0; }
private:
Pipe(const Credentials&);

View File

@@ -47,6 +47,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
ProcROProcessInode(Process&, size_t (Process::*)(off_t, BAN::ByteSpan) const, TmpFileSystem&, const TmpInodeInfo&);
@@ -72,6 +73,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
ProcROInode(size_t (*callback)(off_t, BAN::ByteSpan), TmpFileSystem&, const TmpInodeInfo&);

View File

@@ -80,6 +80,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
TmpFileInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
@@ -102,6 +103,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
TmpSocketInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
@@ -123,6 +125,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
TmpSymlinkInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
@@ -153,6 +156,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
template<TmpFuncs::for_each_valid_entry_callback F>

View File

@@ -31,7 +31,7 @@ namespace Kernel
bool can_read_impl() const override { SpinLockGuard _(m_event_lock); return m_event_count > 0; }
bool can_write_impl() const override { return false; }
bool has_error_impl() const override { return false; }
bool has_hangup_impl() const override { return false; }
private:
BAN::ErrorOr<size_t> read_non_block(BAN::ByteSpan);
@@ -64,7 +64,7 @@ namespace Kernel
public:
static BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> create(mode_t mode, uid_t uid, gid_t gid);
void notify() { m_thread_blocker.unblock(); }
void notify();
private:
KeyboardDevice(mode_t mode, uid_t uid, gid_t gid);
@@ -73,6 +73,7 @@ namespace Kernel
bool can_read_impl() const override;
bool can_write_impl() const override { return false; }
bool has_error_impl() const override { return false; }
bool has_hangup_impl() const override { return false; }
BAN::StringView name() const final override { return m_name; }
dev_t rdev() const final override { return m_rdev; }
@@ -90,7 +91,7 @@ namespace Kernel
public:
static BAN::ErrorOr<BAN::RefPtr<MouseDevice>> create(mode_t mode, uid_t uid, gid_t gid);
void notify() { m_thread_blocker.unblock(); }
void notify();
private:
MouseDevice(mode_t mode, uid_t uid, gid_t gid);
@@ -99,6 +100,7 @@ namespace Kernel
bool can_read_impl() const override;
bool can_write_impl() const override { return false; }
bool has_error_impl() const override { return false; }
bool has_hangup_impl() const override { return false; }
BAN::StringView name() const final override { return m_name; }
dev_t rdev() const final override { return m_rdev; }

View File

@@ -28,7 +28,7 @@ namespace Kernel
virtual bool link_up() override { return m_link_up; }
virtual int link_speed() override;
virtual size_t payload_mtu() const { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); }
virtual size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); }
virtual void handle_irq() final override;
@@ -50,6 +50,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
BAN::ErrorOr<void> read_mac_address();

View File

@@ -30,6 +30,7 @@ namespace Kernel
bool can_read_impl() const override { return false; }
bool can_write_impl() const override { return false; }
bool has_error_impl() const override { return false; }
bool has_hangup_impl() const override { return false; }
private:
SpinLock m_buffer_lock;

View File

@@ -36,6 +36,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
BAN::ErrorOr<void> reset();

View File

@@ -67,6 +67,7 @@ namespace Kernel
virtual bool can_read_impl() const override;
virtual bool can_write_impl() const override;
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override;
private:
enum class State

View File

@@ -40,6 +40,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return !m_packets.empty(); }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
UDPSocket(NetworkLayer&, const Socket::Info&);

View File

@@ -1,5 +1,6 @@
#pragma once
#include <BAN/CircularQueue.h>
#include <BAN/Queue.h>
#include <BAN/WeakPtr.h>
#include <kernel/FS/Socket.h>
@@ -28,6 +29,7 @@ namespace Kernel
virtual bool can_read_impl() const override;
virtual bool can_write_impl() const override;
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override;
private:
UnixDomainSocket(Socket::Type, const Socket::Info&);
@@ -48,7 +50,7 @@ namespace Kernel
mutable BAN::Atomic<bool> target_closed { false };
BAN::WeakPtr<UnixDomainSocket> connection;
BAN::Queue<BAN::RefPtr<UnixDomainSocket>> pending_connections;
ThreadBlocker pending_thread_blocker;
ThreadBlocker pending_thread_blocker;
SpinLock pending_lock;
};
@@ -67,7 +69,7 @@ namespace Kernel
size_t m_packet_size_total { 0 };
BAN::UniqPtr<VirtualRange> m_packet_buffer;
SpinLock m_packet_lock;
ThreadBlocker m_packet_thread_blocker;
ThreadBlocker m_packet_thread_blocker;
friend class BAN::RefPtr<UnixDomainSocket>;
};

View File

@@ -24,6 +24,8 @@
#include <sys/time.h>
#include <termios.h>
struct epoll_event;
namespace Kernel
{
@@ -130,6 +132,10 @@ namespace Kernel
BAN::ErrorOr<long> sys_pselect(sys_pselect_t* arguments);
BAN::ErrorOr<long> sys_epoll_create1(int flags);
BAN::ErrorOr<long> sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
BAN::ErrorOr<long> sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask);
BAN::ErrorOr<long> sys_pipe(int fildes[2]);
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);

View File

@@ -27,6 +27,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
NVMeController(PCI::Device& pci_device);

View File

@@ -17,7 +17,7 @@ namespace Kernel
virtual uint64_t total_size() const override { return m_block_size * m_block_count; }
virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const { return m_name; }
virtual BAN::StringView name() const override { return m_name; }
private:
NVMeNamespace(NVMeController&, uint32_t ns_index, uint32_t nsid, uint64_t block_count, uint32_t block_size);

View File

@@ -53,6 +53,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
const dev_t m_rdev;

View File

@@ -47,6 +47,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
private:
Mutex m_mutex;

View File

@@ -29,6 +29,7 @@ namespace Kernel
bool can_read_impl() const override { SpinLockGuard _(m_buffer_lock); return m_buffer_size > 0; }
bool can_write_impl() const override { SpinLockGuard _(m_buffer_lock); return m_buffer_size < m_buffer->size(); }
bool has_error_impl() const override { return false; }
bool has_hangup_impl() const override { return !m_slave.valid(); }
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
@@ -63,6 +64,8 @@ namespace Kernel
protected:
bool putchar_impl(uint8_t ch) override;
bool has_hangup_impl() const override { return !m_master.valid(); }
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
private:

View File

@@ -54,6 +54,7 @@ namespace Kernel
virtual bool can_read_impl() const override { return m_output.flush; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hangup_impl() const override { return false; }
protected:
TTY(mode_t mode, uid_t uid, gid_t gid);