Kernel/LibC: Implement super basic select

This does not really even block but it works... :D
This commit is contained in:
Bananymous 2024-02-12 17:26:33 +02:00
parent f50b4be162
commit 3fc1edede0
34 changed files with 285 additions and 41 deletions

View File

@ -21,6 +21,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override { return 0; }
virtual BAN::ErrorOr<size_t> 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;
};

View File

@ -30,6 +30,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> 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<void> initialize();

View File

@ -23,6 +23,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override { return 0; }
virtual BAN::ErrorOr<size_t> 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;
};

View File

@ -21,6 +21,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> 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;
};

View File

@ -43,6 +43,10 @@ namespace Kernel
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
virtual BAN::ErrorOr<void> 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

View File

@ -113,7 +113,11 @@ namespace Kernel
BAN::ErrorOr<void> truncate(size_t);
BAN::ErrorOr<void> chmod(mode_t);
BAN::ErrorOr<void> 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<long> ioctl(int request, void* arg);
@ -144,7 +148,11 @@ namespace Kernel
virtual BAN::ErrorOr<void> truncate_impl(size_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> chmod_impl(mode_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> 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<long> ioctl_impl(int request, void* arg) { return BAN::Error::from_errno(ENOTSUP); }

View File

@ -34,6 +34,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> 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&);

View File

@ -43,7 +43,10 @@ namespace Kernel
// You may not write here and this is always non blocking
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
virtual BAN::ErrorOr<void> 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&);

View File

@ -72,7 +72,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
virtual BAN::ErrorOr<void> 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<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(ENODEV); }
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(ENODEV); }
virtual BAN::ErrorOr<void> 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<BAN::String> 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<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> 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<TmpFuncs::for_each_valid_entry_callback F>
void for_each_valid_entry(F callback);

View File

@ -48,7 +48,10 @@ namespace Kernel::Input
protected:
virtual BAN::ErrorOr<size_t> 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; }
};
}

View File

@ -42,7 +42,10 @@ namespace Kernel::Input
protected:
virtual BAN::ErrorOr<size_t> 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; }
};
}

View File

@ -46,6 +46,10 @@ namespace Kernel
virtual BAN::ErrorOr<void> 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<void> read_mac_address();

View File

@ -57,6 +57,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> 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
{

View File

@ -38,6 +38,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> 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&);

View File

@ -26,6 +26,10 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> 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&);

View File

@ -16,6 +16,7 @@
#include <sys/banan-os.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <termios.h>
@ -126,6 +127,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_ioctl(int fildes, int request, void* arg);
BAN::ErrorOr<long> sys_pselect(sys_pselect_t* arguments);
BAN::ErrorOr<long> sys_pipe(int fildes[2]);
BAN::ErrorOr<long> sys_dup(int fildes);
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);

View File

@ -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<void> initialize() override;

View File

@ -46,6 +46,10 @@ namespace Kernel
protected:
virtual BAN::ErrorOr<size_t> 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;
};

View File

@ -39,6 +39,10 @@ namespace Kernel
virtual BAN::ErrorOr<void> 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<DiskCache> m_disk_cache;

View File

@ -44,7 +44,9 @@ namespace Kernel
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
virtual BAN::ErrorOr<void> 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)

View File

@ -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<long> Inode::ioctl(int request, void* arg)

View File

@ -208,10 +208,4 @@ namespace Kernel::Input
}
}
bool PS2Keyboard::has_data_impl() const
{
CriticalScope _;
return !m_event_queue.empty();
}
}

View File

@ -192,10 +192,4 @@ namespace Kernel::Input
}
}
bool PS2Mouse::has_data_impl() const
{
CriticalScope _;
return !m_event_queue.empty();
}
}

View File

@ -248,6 +248,29 @@ namespace Kernel
return {};
}
bool UnixDomainSocket::can_read_impl() const
{
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
if (!connection_info.connection)
return false;
}
return m_packet_size_total > 0;
}
bool UnixDomainSocket::can_write_impl() const
{
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
return connection_info.connection.valid();
}
return true;
}
BAN::ErrorOr<size_t> UnixDomainSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
{
if (message.size() > s_packet_buffer_size)

View File

@ -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));

View File

@ -1018,6 +1018,86 @@ namespace Kernel
return TRY(inode->ioctl(request, arg));
}
BAN::ErrorOr<long> 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<long> Process::sys_pipe(int fildes[2])
{
LockGuard _(m_lock);

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -0,0 +1,20 @@
#ifndef _BITS_TIMEVAL_H
#define _BITS_TIMEVAL_H 1
#include <sys/cdefs.h>
__BEGIN_DECLS
#define __need_time_t
#define __need_suseconds_t
#include <sys/types.h>
struct timeval
{
time_t tv_sec; /* Seconds. */
suseconds_t tc_usec; /* Microseconds. */
};
__END_DECLS
#endif

View File

@ -7,9 +7,7 @@
__BEGIN_DECLS
#define __need_time_t
#define __need_suseconds_t
#include <sys/types.h>
#include <bits/types/timeval.h>
#include <signal.h>
#include <time.h>
@ -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);

View File

@ -71,6 +71,7 @@ __BEGIN_DECLS
#define SYS_ACCEPT 70
#define SYS_CONNECT 71
#define SYS_LISTEN 72
#define SYS_PSELECT 73
__END_DECLS

View File

@ -7,18 +7,10 @@
__BEGIN_DECLS
#define __need_time_t
#define __need_suseconds_t
#include <sys/types.h>
// NOTE: select is declared from here
#include <sys/select.h>
struct timeval
{
time_t tv_sec; /* Seconds. */
suseconds_t tc_usec; /* Microseconds. */
};
#include <bits/types/timeval.h>
struct itimerval
{

31
libc/sys/select.cpp Normal file
View File

@ -0,0 +1,31 @@
#include <sys/select.h>
#include <sys/syscall.h>
#include <unistd.h>
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);
}