From 3fc1edede052fec17b136e83b798a3d3e10c610b Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 12 Feb 2024 17:26:33 +0200 Subject: [PATCH] Kernel/LibC: Implement super basic select This does not really even block but it works... :D --- kernel/include/kernel/Device/DebugDevice.h | 4 + .../include/kernel/Device/FramebufferDevice.h | 4 + kernel/include/kernel/Device/NullDevice.h | 4 + kernel/include/kernel/Device/ZeroDevice.h | 4 + kernel/include/kernel/FS/Ext2/Inode.h | 4 + kernel/include/kernel/FS/Inode.h | 12 ++- kernel/include/kernel/FS/Pipe.h | 4 + kernel/include/kernel/FS/ProcFS/Inode.h | 5 +- kernel/include/kernel/FS/TmpFS/Inode.h | 18 ++++- kernel/include/kernel/Input/PS2/Keyboard.h | 5 +- kernel/include/kernel/Input/PS2/Mouse.h | 5 +- .../include/kernel/Networking/E1000/E1000.h | 4 + kernel/include/kernel/Networking/TCPSocket.h | 4 + kernel/include/kernel/Networking/UDPSocket.h | 4 + .../include/kernel/Networking/UNIX/Socket.h | 4 + kernel/include/kernel/Process.h | 3 + .../include/kernel/Storage/NVMe/Controller.h | 5 ++ kernel/include/kernel/Storage/Partition.h | 4 + kernel/include/kernel/Storage/StorageDevice.h | 4 + kernel/include/kernel/Terminal/TTY.h | 4 +- kernel/kernel/FS/Inode.cpp | 16 +++- kernel/kernel/Input/PS2/Keyboard.cpp | 6 -- kernel/kernel/Input/PS2/Mouse.cpp | 6 -- kernel/kernel/Networking/UNIX/Socket.cpp | 23 ++++++ kernel/kernel/OpenFileDescriptorSet.cpp | 4 +- kernel/kernel/Process.cpp | 80 +++++++++++++++++++ kernel/kernel/Syscall.cpp | 3 + kernel/kernel/Terminal/TTY.cpp | 6 -- libc/CMakeLists.txt | 1 + libc/include/bits/types/timeval.h | 20 +++++ libc/include/sys/select.h | 14 +++- libc/include/sys/syscall.h | 1 + libc/include/sys/time.h | 10 +-- libc/sys/select.cpp | 31 +++++++ 34 files changed, 285 insertions(+), 41 deletions(-) create mode 100644 libc/include/bits/types/timeval.h create mode 100644 libc/sys/select.cpp diff --git a/kernel/include/kernel/Device/DebugDevice.h b/kernel/include/kernel/Device/DebugDevice.h index 2487e1ea..57897b3f 100644 --- a/kernel/include/kernel/Device/DebugDevice.h +++ b/kernel/include/kernel/Device/DebugDevice.h @@ -21,6 +21,10 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override { return 0; } virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan buffer) override; + 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; } + private: const dev_t m_rdev; }; diff --git a/kernel/include/kernel/Device/FramebufferDevice.h b/kernel/include/kernel/Device/FramebufferDevice.h index ec5502fe..d3bdf46e 100644 --- a/kernel/include/kernel/Device/FramebufferDevice.h +++ b/kernel/include/kernel/Device/FramebufferDevice.h @@ -30,6 +30,10 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override; + 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; } + 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); BAN::ErrorOr initialize(); diff --git a/kernel/include/kernel/Device/NullDevice.h b/kernel/include/kernel/Device/NullDevice.h index 57009b2e..ce3ba6fa 100644 --- a/kernel/include/kernel/Device/NullDevice.h +++ b/kernel/include/kernel/Device/NullDevice.h @@ -23,6 +23,10 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override { return 0; } virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan buffer) override { return buffer.size(); }; + 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; } + private: const dev_t m_rdev; }; diff --git a/kernel/include/kernel/Device/ZeroDevice.h b/kernel/include/kernel/Device/ZeroDevice.h index 45183488..809f54e6 100644 --- a/kernel/include/kernel/Device/ZeroDevice.h +++ b/kernel/include/kernel/Device/ZeroDevice.h @@ -21,6 +21,10 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan buffer) override { return buffer.size(); }; + 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; } + private: const dev_t m_rdev; }; diff --git a/kernel/include/kernel/FS/Ext2/Inode.h b/kernel/include/kernel/FS/Ext2/Inode.h index 1160d70f..4674ff81 100644 --- a/kernel/include/kernel/FS/Ext2/Inode.h +++ b/kernel/include/kernel/FS/Ext2/Inode.h @@ -43,6 +43,10 @@ namespace Kernel virtual BAN::ErrorOr truncate_impl(size_t) override; virtual BAN::ErrorOr chmod_impl(mode_t) override; + 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; } + private: // Returns maximum number of data blocks in use // NOTE: the inode might have more blocks than what this suggests if it has been shrinked diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index 80bd97fe..d5954d20 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -113,7 +113,11 @@ namespace Kernel BAN::ErrorOr truncate(size_t); BAN::ErrorOr chmod(mode_t); BAN::ErrorOr chown(uid_t, gid_t); - bool has_data() const; + + // Select/Non blocking API + bool can_read() const; + bool can_write() const; + bool has_error() const; BAN::ErrorOr ioctl(int request, void* arg); @@ -144,7 +148,11 @@ namespace Kernel virtual BAN::ErrorOr truncate_impl(size_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr chmod_impl(mode_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr chown_impl(uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); } - virtual bool has_data_impl() const { dwarnln("nonblock not supported"); return true; } + + // Select/Non blocking API + virtual bool can_read_impl() const = 0; + virtual bool can_write_impl() const = 0; + virtual bool has_error_impl() const = 0; virtual BAN::ErrorOr ioctl_impl(int request, void* arg) { return BAN::Error::from_errno(ENOTSUP); } diff --git a/kernel/include/kernel/FS/Pipe.h b/kernel/include/kernel/FS/Pipe.h index f5b11f00..bbcf6a44 100644 --- a/kernel/include/kernel/FS/Pipe.h +++ b/kernel/include/kernel/FS/Pipe.h @@ -34,6 +34,10 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override; + virtual bool can_read_impl() const override { return !m_buffer.empty(); } + virtual bool can_write_impl() const override { return true; } + virtual bool has_error_impl() const override { return false; } + private: Pipe(const Credentials&); diff --git a/kernel/include/kernel/FS/ProcFS/Inode.h b/kernel/include/kernel/FS/ProcFS/Inode.h index 1323195e..324e218e 100644 --- a/kernel/include/kernel/FS/ProcFS/Inode.h +++ b/kernel/include/kernel/FS/ProcFS/Inode.h @@ -43,7 +43,10 @@ namespace Kernel // You may not write here and this is always non blocking virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); } virtual BAN::ErrorOr truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); } - virtual bool has_data_impl() const override { return true; } + + 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; } private: ProcROInode(Process&, size_t (Process::*)(off_t, BAN::ByteSpan) const, TmpFileSystem&, const TmpInodeInfo&); diff --git a/kernel/include/kernel/FS/TmpFS/Inode.h b/kernel/include/kernel/FS/TmpFS/Inode.h index 38fe0c1c..5a78c974 100644 --- a/kernel/include/kernel/FS/TmpFS/Inode.h +++ b/kernel/include/kernel/FS/TmpFS/Inode.h @@ -72,7 +72,10 @@ namespace Kernel virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override; virtual BAN::ErrorOr truncate_impl(size_t) override; virtual BAN::ErrorOr chmod_impl(mode_t) override; - virtual bool has_data_impl() const override { return true; } + + 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; } private: TmpFileInode(TmpFileSystem&, ino_t, const TmpInodeInfo&); @@ -91,7 +94,10 @@ namespace Kernel virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(ENODEV); } virtual BAN::ErrorOr truncate_impl(size_t) override { return BAN::Error::from_errno(ENODEV); } virtual BAN::ErrorOr chmod_impl(mode_t) override; - virtual bool has_data_impl() const override { return true; } + + 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; } private: TmpSocketInode(TmpFileSystem&, ino_t, const TmpInodeInfo&); @@ -110,6 +116,10 @@ namespace Kernel protected: virtual BAN::ErrorOr link_target_impl() override; + 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; } + private: TmpSymlinkInode(TmpFileSystem&, ino_t, const TmpInodeInfo&); }; @@ -136,6 +146,10 @@ namespace Kernel virtual BAN::ErrorOr create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final; virtual BAN::ErrorOr unlink_impl(BAN::StringView) override; + 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; } + private: template void for_each_valid_entry(F callback); diff --git a/kernel/include/kernel/Input/PS2/Keyboard.h b/kernel/include/kernel/Input/PS2/Keyboard.h index 425ede52..2fcd915f 100644 --- a/kernel/include/kernel/Input/PS2/Keyboard.h +++ b/kernel/include/kernel/Input/PS2/Keyboard.h @@ -48,7 +48,10 @@ namespace Kernel::Input protected: virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; - virtual bool has_data_impl() const override; + + virtual bool can_read_impl() const override { return !m_event_queue.empty(); } + virtual bool can_write_impl() const override { return false; } + virtual bool has_error_impl() const override { return false; } }; } diff --git a/kernel/include/kernel/Input/PS2/Mouse.h b/kernel/include/kernel/Input/PS2/Mouse.h index b9c84dfb..f0977a2a 100644 --- a/kernel/include/kernel/Input/PS2/Mouse.h +++ b/kernel/include/kernel/Input/PS2/Mouse.h @@ -42,7 +42,10 @@ namespace Kernel::Input protected: virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; - virtual bool has_data_impl() const override; + + virtual bool can_read_impl() const override { return !m_event_queue.empty(); } + virtual bool can_write_impl() const override { return false; } + virtual bool has_error_impl() const override { return false; } }; } diff --git a/kernel/include/kernel/Networking/E1000/E1000.h b/kernel/include/kernel/Networking/E1000/E1000.h index de9440d1..55a3b380 100644 --- a/kernel/include/kernel/Networking/E1000/E1000.h +++ b/kernel/include/kernel/Networking/E1000/E1000.h @@ -46,6 +46,10 @@ namespace Kernel virtual BAN::ErrorOr send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override; + 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; } + private: BAN::ErrorOr read_mac_address(); diff --git a/kernel/include/kernel/Networking/TCPSocket.h b/kernel/include/kernel/Networking/TCPSocket.h index 068f39a4..d82b4b38 100644 --- a/kernel/include/kernel/Networking/TCPSocket.h +++ b/kernel/include/kernel/Networking/TCPSocket.h @@ -57,6 +57,10 @@ namespace Kernel virtual BAN::ErrorOr sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override; virtual BAN::ErrorOr recvfrom_impl(BAN::ByteSpan message, sockaddr* address, socklen_t* address_len) override; + virtual bool can_read_impl() const override { return m_recv_window.data_size; } + virtual bool can_write_impl() const override { return m_state == State::Established; } + virtual bool has_error_impl() const override { return m_state != State::Established && m_state != State::Listen && m_state != State::SynSent && m_state != State::SynReceived; } + private: enum class State { diff --git a/kernel/include/kernel/Networking/UDPSocket.h b/kernel/include/kernel/Networking/UDPSocket.h index 0a72a7a3..d9bdae9b 100644 --- a/kernel/include/kernel/Networking/UDPSocket.h +++ b/kernel/include/kernel/Networking/UDPSocket.h @@ -38,6 +38,10 @@ namespace Kernel virtual BAN::ErrorOr sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override; virtual BAN::ErrorOr recvfrom_impl(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len) override; + 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; } + private: UDPSocket(NetworkLayer&, ino_t, const TmpInodeInfo&); diff --git a/kernel/include/kernel/Networking/UNIX/Socket.h b/kernel/include/kernel/Networking/UNIX/Socket.h index e1769a56..b58ab646 100644 --- a/kernel/include/kernel/Networking/UNIX/Socket.h +++ b/kernel/include/kernel/Networking/UNIX/Socket.h @@ -26,6 +26,10 @@ namespace Kernel virtual BAN::ErrorOr sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override; virtual BAN::ErrorOr recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override; + virtual bool can_read_impl() const override; + virtual bool can_write_impl() const override; + virtual bool has_error_impl() const override { return false; } + private: UnixDomainSocket(SocketType, ino_t, const TmpInodeInfo&); diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 7a97eb23..c4f2d157 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -126,6 +127,8 @@ namespace Kernel BAN::ErrorOr sys_ioctl(int fildes, int request, void* arg); + BAN::ErrorOr sys_pselect(sys_pselect_t* arguments); + BAN::ErrorOr sys_pipe(int fildes[2]); BAN::ErrorOr sys_dup(int fildes); BAN::ErrorOr sys_dup2(int fildes, int fildes2); diff --git a/kernel/include/kernel/Storage/NVMe/Controller.h b/kernel/include/kernel/Storage/NVMe/Controller.h index 6152799a..db01d4b9 100644 --- a/kernel/include/kernel/Storage/NVMe/Controller.h +++ b/kernel/include/kernel/Storage/NVMe/Controller.h @@ -24,6 +24,11 @@ namespace Kernel virtual dev_t rdev() const override { return m_rdev; } virtual BAN::StringView name() const override { return m_name; } + protected: + 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; } + private: NVMeController(PCI::Device& pci_device); virtual BAN::ErrorOr initialize() override; diff --git a/kernel/include/kernel/Storage/Partition.h b/kernel/include/kernel/Storage/Partition.h index 450d8a8c..aec7c5ec 100644 --- a/kernel/include/kernel/Storage/Partition.h +++ b/kernel/include/kernel/Storage/Partition.h @@ -46,6 +46,10 @@ namespace Kernel protected: virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; + 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; } + private: const dev_t m_rdev; }; diff --git a/kernel/include/kernel/Storage/StorageDevice.h b/kernel/include/kernel/Storage/StorageDevice.h index 194908ed..aa8dc7f4 100644 --- a/kernel/include/kernel/Storage/StorageDevice.h +++ b/kernel/include/kernel/Storage/StorageDevice.h @@ -39,6 +39,10 @@ namespace Kernel virtual BAN::ErrorOr write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan) = 0; void add_disk_cache(); + 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; } + private: SpinLock m_lock; BAN::Optional m_disk_cache; diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index 8daa278d..e88b2915 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -44,7 +44,9 @@ namespace Kernel virtual BAN::ErrorOr chmod_impl(mode_t) override; virtual BAN::ErrorOr chown_impl(uid_t, gid_t) override; - virtual bool has_data_impl() const override; + 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; } protected: TTY(mode_t mode, uid_t uid, gid_t gid) diff --git a/kernel/kernel/FS/Inode.cpp b/kernel/kernel/FS/Inode.cpp index 451f7fd2..74702e49 100644 --- a/kernel/kernel/FS/Inode.cpp +++ b/kernel/kernel/FS/Inode.cpp @@ -201,10 +201,22 @@ namespace Kernel return chown_impl(uid, gid); } - bool Inode::has_data() const + bool Inode::can_read() const { LockGuard _(m_lock); - return has_data_impl(); + return can_read_impl(); + } + + bool Inode::can_write() const + { + LockGuard _(m_lock); + return can_write_impl(); + } + + bool Inode::has_error() const + { + LockGuard _(m_lock); + return has_error_impl(); } BAN::ErrorOr Inode::ioctl(int request, void* arg) diff --git a/kernel/kernel/Input/PS2/Keyboard.cpp b/kernel/kernel/Input/PS2/Keyboard.cpp index 2240c7af..ae028f35 100644 --- a/kernel/kernel/Input/PS2/Keyboard.cpp +++ b/kernel/kernel/Input/PS2/Keyboard.cpp @@ -208,10 +208,4 @@ namespace Kernel::Input } } - bool PS2Keyboard::has_data_impl() const - { - CriticalScope _; - return !m_event_queue.empty(); - } - } diff --git a/kernel/kernel/Input/PS2/Mouse.cpp b/kernel/kernel/Input/PS2/Mouse.cpp index 959190e5..dfcc3ac0 100644 --- a/kernel/kernel/Input/PS2/Mouse.cpp +++ b/kernel/kernel/Input/PS2/Mouse.cpp @@ -192,10 +192,4 @@ namespace Kernel::Input } } - bool PS2Mouse::has_data_impl() const - { - CriticalScope _; - return !m_event_queue.empty(); - } - } diff --git a/kernel/kernel/Networking/UNIX/Socket.cpp b/kernel/kernel/Networking/UNIX/Socket.cpp index 0646b7f3..a78d6f79 100644 --- a/kernel/kernel/Networking/UNIX/Socket.cpp +++ b/kernel/kernel/Networking/UNIX/Socket.cpp @@ -248,6 +248,29 @@ namespace Kernel return {}; } + bool UnixDomainSocket::can_read_impl() const + { + if (m_info.has()) + { + auto& connection_info = m_info.get(); + if (!connection_info.connection) + return false; + } + + return m_packet_size_total > 0; + } + + bool UnixDomainSocket::can_write_impl() const + { + if (m_info.has()) + { + auto& connection_info = m_info.get(); + return connection_info.connection.valid(); + } + + return true; + } + BAN::ErrorOr UnixDomainSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) { if (message.size() > s_packet_buffer_size) diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index a4518745..0054fdf3 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -331,7 +331,7 @@ namespace Kernel { TRY(validate_fd(fd)); auto& open_file = m_open_files[fd]; - if ((open_file->flags & O_NONBLOCK) && !open_file->inode->has_data()) + if ((open_file->flags & O_NONBLOCK) && !open_file->inode->can_read()) return 0; size_t nread = TRY(open_file->inode->read(open_file->offset, buffer)); open_file->offset += nread; @@ -342,6 +342,8 @@ namespace Kernel { TRY(validate_fd(fd)); auto& open_file = m_open_files[fd]; + if ((open_file->flags & O_NONBLOCK) && !open_file->inode->can_write()) + return 0; if (open_file->flags & O_APPEND) open_file->offset = open_file->inode->size(); size_t nwrite = TRY(open_file->inode->write(open_file->offset, buffer)); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index fb2b669f..e8269a7b 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1018,6 +1018,86 @@ namespace Kernel return TRY(inode->ioctl(request, arg)); } + BAN::ErrorOr Process::sys_pselect(sys_pselect_t* arguments) + { + LockGuard _(m_lock); + + TRY(validate_pointer_access(arguments, sizeof(sys_pselect_t))); + if (arguments->readfds) + TRY(validate_pointer_access(arguments->readfds, sizeof(fd_set))); + if (arguments->writefds) + TRY(validate_pointer_access(arguments->writefds, sizeof(fd_set))); + if (arguments->errorfds) + TRY(validate_pointer_access(arguments->errorfds, sizeof(fd_set))); + if (arguments->timeout) + TRY(validate_pointer_access(arguments->timeout, sizeof(timespec))); + if (arguments->sigmask) + TRY(validate_pointer_access(arguments->sigmask, sizeof(sigset_t))); + + if (arguments->sigmask) + return BAN::Error::from_errno(ENOTSUP); + + uint64_t timedout_ms = SystemTimer::get().ms_since_boot(); + if (arguments->timeout) + { + timedout_ms += arguments->timeout->tv_sec * 1000; + timedout_ms += arguments->timeout->tv_nsec / 1'000'000; + } + + fd_set readfds; FD_ZERO(&readfds); + fd_set writefds; FD_ZERO(&writefds); + fd_set errorfds; FD_ZERO(&errorfds); + + long set_bits = 0; + while (set_bits == 0) + { + if (arguments->timeout && SystemTimer::get().ms_since_boot() >= timedout_ms) + break; + + auto update_fds = + [&](int fd, fd_set* source, fd_set* dest, bool (Inode::*func)() const) + { + if (source == nullptr) + return; + + if (!FD_ISSET(fd, source)) + return; + + auto inode_or_error = m_open_file_descriptors.inode_of(fd); + if (inode_or_error.is_error()) + return; + + auto inode = inode_or_error.release_value(); + auto mode = inode->mode(); + if (!mode.ifreg() && !mode.ififo() && !mode.ifsock() && !inode->is_pipe() && !inode->is_tty()) + return; + + if ((inode_or_error.value().ptr()->*func)()) + { + FD_SET(fd, dest); + set_bits++; + } + }; + + for (int i = 0; i < arguments->nfds; i++) + { + update_fds(i, arguments->readfds, &readfds, &Inode::can_read); + update_fds(i, arguments->writefds, &writefds, &Inode::can_write); + update_fds(i, arguments->errorfds, &errorfds, &Inode::can_read); + } + + SystemTimer::get().sleep(1); + } + + if (arguments->readfds) + memcpy(arguments->readfds, &readfds, sizeof(fd_set)); + if (arguments->writefds) + memcpy(arguments->writefds, &writefds, sizeof(fd_set)); + if (arguments->errorfds) + memcpy(arguments->errorfds, &errorfds, sizeof(fd_set)); + return set_bits; + } + BAN::ErrorOr Process::sys_pipe(int fildes[2]) { LockGuard _(m_lock); diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index 383bc9b7..1e8dbab3 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -237,6 +237,9 @@ namespace Kernel case SYS_LISTEN: ret = Process::current().sys_listen((int)arg1, (int)arg2); break; + case SYS_PSELECT: + ret = Process::current().sys_pselect((sys_pselect_t*)arg1); + break; default: dwarnln("Unknown syscall {}", syscall); break; diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index 5c501d5f..0e3e594c 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -358,12 +358,6 @@ namespace Kernel return buffer.size(); } - bool TTY::has_data_impl() const - { - LockGuard _(m_lock); - return m_output.flush; - } - void TTY::putchar_current(uint8_t ch) { ASSERT(s_tty); diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 8f3f8673..8d49a855 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -21,6 +21,7 @@ set(LIBC_SOURCES stropts.cpp sys/banan-os.cpp sys/mman.cpp + sys/select.cpp sys/socket.cpp sys/stat.cpp sys/wait.cpp diff --git a/libc/include/bits/types/timeval.h b/libc/include/bits/types/timeval.h new file mode 100644 index 00000000..04d0083f --- /dev/null +++ b/libc/include/bits/types/timeval.h @@ -0,0 +1,20 @@ +#ifndef _BITS_TIMEVAL_H +#define _BITS_TIMEVAL_H 1 + +#include + +__BEGIN_DECLS + +#define __need_time_t +#define __need_suseconds_t +#include + +struct timeval +{ + time_t tv_sec; /* Seconds. */ + suseconds_t tc_usec; /* Microseconds. */ +}; + +__END_DECLS + +#endif diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h index d5901680..c09e545d 100644 --- a/libc/include/sys/select.h +++ b/libc/include/sys/select.h @@ -7,9 +7,7 @@ __BEGIN_DECLS -#define __need_time_t -#define __need_suseconds_t -#include +#include #include #include @@ -50,6 +48,16 @@ typedef struct { (setp)->__bits[i] = (__fd_mask)0; \ } while (0) +struct sys_pselect_t +{ + int nfds; + fd_set* readfds; + fd_set* writefds; + fd_set* errorfds; + const struct timespec* timeout; + const sigset_t* sigmask; +}; + int pselect(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, fd_set* __restrict errorfds, const struct timespec* __restrict timeout, const sigset_t* __restrict sigmask); int select(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, fd_set* __restrict errorfds, struct timeval* __restrict timeout); diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index 780103d8..6fa892a1 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -71,6 +71,7 @@ __BEGIN_DECLS #define SYS_ACCEPT 70 #define SYS_CONNECT 71 #define SYS_LISTEN 72 +#define SYS_PSELECT 73 __END_DECLS diff --git a/libc/include/sys/time.h b/libc/include/sys/time.h index 41869123..2508deae 100644 --- a/libc/include/sys/time.h +++ b/libc/include/sys/time.h @@ -7,18 +7,10 @@ __BEGIN_DECLS -#define __need_time_t -#define __need_suseconds_t -#include - // NOTE: select is declared from here #include -struct timeval -{ - time_t tv_sec; /* Seconds. */ - suseconds_t tc_usec; /* Microseconds. */ -}; +#include struct itimerval { diff --git a/libc/sys/select.cpp b/libc/sys/select.cpp new file mode 100644 index 00000000..52333086 --- /dev/null +++ b/libc/sys/select.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +int pselect(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, fd_set* __restrict errorfds, const struct timespec* __restrict timeout, const sigset_t* __restrict sigmask) +{ + sys_pselect_t arguments { + .nfds = nfds, + .readfds = readfds, + .writefds = writefds, + .errorfds = errorfds, + .timeout = timeout, + .sigmask = sigmask + }; + return syscall(SYS_PSELECT, &arguments); +} + +int select(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, fd_set* __restrict errorfds, struct timeval* __restrict timeout) +{ + timespec* pts = nullptr; + timespec ts; + if (timeout) + { + ts.tv_sec = timeout->tv_sec; + ts.tv_nsec = timeout->tc_usec * 1000; + pts = &ts; + } + + // TODO: "select may update timeout", should we? + return pselect(nfds, readfds, writefds, errorfds, pts, nullptr); +}