diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index 30874526..7dc82bc7 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -105,6 +105,7 @@ extern syscall_getsockopt extern syscall_clock_getres extern syscall_setpriority extern syscall_sysctl +extern syscall_eventfd syscalltab: dq syscall_print dq syscall_mmap @@ -212,7 +213,8 @@ dq syscall_getsockopt dq syscall_clock_getres dq syscall_setpriority dq syscall_sysctl -syscallcount equ 106 +dq syscall_eventfd +syscallcount equ 107 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index fd7bdc76..5888d7e4 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -9,7 +9,7 @@ void arch_interrupt_disable(); void arch_interrupt_enable(); -#define SYSCALL_COUNT 106 +#define SYSCALL_COUNT 107 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -119,6 +119,7 @@ static char *name[] = { "clock_getres", "setpriority", "sysctl", + "eventfd", }; static char *args[] = { @@ -228,6 +229,7 @@ static char *args[] = { "clockid %d timespec %p", // clock_getres "which %d who %d prio %d", // setpriority "name %p name_len %lu oldp %p old_size %p newp %p new_size %lu", // sysctl + "initval %lu flags %x", //eventfd }; #endif diff --git a/kernel-src/fs/eventfs.c b/kernel-src/fs/eventfs.c new file mode 100644 index 00000000..0d8dfaa9 --- /dev/null +++ b/kernel-src/fs/eventfs.c @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#include + +#define EVENT_COUNTER_MAX 0xfffffffffffffffelu + +typedef struct { + vnode_t vnode; + pollheader_t pollheader; + uint64_t counter; + bool semaphore; +} event_node_t; + +static scache_t *node_cache; + +int eventfs_close(vnode_t *node, int flags, cred_t *cred) { + return 0; // not needed +} + +static int internal_poll(event_node_t *event_node, polldata_t *data, int events, size_t write_limit) { + int revents = 0; + + if ((events & POLLIN) && event_node->counter) + revents |= POLLIN; + + if ((events & POLLOUT) && event_node->counter <= write_limit) + revents |= POLLOUT; + + if (data && !revents) + poll_add(&event_node->pollheader, data, events); + + return revents; +} + +static int internal_poll_wait(event_node_t *event_node, int event, bool non_blocking, size_t write_limit) { + for (;;) { + polldesc_t desc = {0}; + int error = poll_initdesc(&desc, 1); + if (error) + return error; + + int revents = internal_poll(event_node, &desc.data[0], event, write_limit); + if (revents) { + poll_leave(&desc); + poll_destroydesc(&desc); + break; + } + + if (non_blocking) { + poll_leave(&desc); + poll_destroydesc(&desc); + return EAGAIN; + } + + MUTEX_RELEASE(&event_node->vnode.lock); + + error = poll_dowait(&desc, 0); + + poll_leave(&desc); + poll_destroydesc(&desc); + + MUTEX_ACQUIRE(&event_node->vnode.lock); + if (error) + return error; + } + + return 0; +} + +int eventfs_read(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *bytes_read, cred_t *cred) { + event_node_t *event_node = (event_node_t *)node; + + if (size < 8) + return EINVAL; + + MUTEX_ACQUIRE(&node->lock); + + int error = internal_poll_wait(event_node, POLLIN, flags & V_FFLAGS_NONBLOCKING, 0); + if (error) + goto leave; + + uint64_t return_value = event_node->semaphore ? 1 : event_node->counter; + error = iovec_iterator_copy_from_buffer(iovec_iterator, &return_value, 8); + if (error) + goto leave; + + event_node->counter = event_node->semaphore ? (event_node->counter - 1) : 0; + *bytes_read = 8; + + poll_event(&event_node->pollheader, POLLOUT); + + leave: + MUTEX_RELEASE(&node->lock); + return error; +} + +int eventfs_write(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *bytes_written, cred_t *cred) { + event_node_t *event_node = (event_node_t *)node; + + if (size < 8) + return EINVAL; + + uint64_t value_to_write; + int error = iovec_iterator_copy_to_buffer(iovec_iterator, &value_to_write, 8); + if (error) + return error; + + if (value_to_write > EVENT_COUNTER_MAX) + return EINVAL; + + MUTEX_ACQUIRE(&node->lock); + + error = internal_poll_wait(event_node, POLLOUT, flags & V_FFLAGS_NONBLOCKING, EVENT_COUNTER_MAX - value_to_write); + if (error) + goto leave; + + event_node->counter += value_to_write; + __assert(event_node->counter <= EVENT_COUNTER_MAX); + + poll_event(&event_node->pollheader, POLLIN); + *bytes_written = 8; + + leave: + MUTEX_RELEASE(&node->lock); + return error; +} + +int eventfs_poll(vnode_t *node, polldata_t *data, int events) { + MUTEX_ACQUIRE(&node->lock); + int revents = internal_poll((event_node_t *)node, data, events, EVENT_COUNTER_MAX - 1); + MUTEX_RELEASE(&node->lock); + return revents; +} + +static vops_t vnops; + +int eventfs_inactive(vnode_t *node) { + event_node_t *event_node = (event_node_t *)node; + VOP_INIT(&event_node->vnode, &vnops, 0, V_TYPE_CHDEV, NULL); + POLL_INITHEADER(&event_node->pollheader); + slab_free(node_cache, node); + return 0; +} + +static int eventfs_lock(vnode_t *) { + return 0; +} + +static int eventfs_unlock(vnode_t *) { + return 0; +} + +static int eventfs_advlock(vnode_t *node, int op, advlock_t *advlock) { + return vfs_advlock(node, op, advlock); +} + +static int eventfs_enodev() { + return ENODEV; +} + +static vops_t vnops = { + .create = eventfs_enodev, + .open = eventfs_enodev, + .close = eventfs_close, + .getattr = eventfs_enodev, + .setattr = eventfs_enodev, + .lookup = eventfs_enodev, + .poll = eventfs_poll, + .read = eventfs_read, + .write = eventfs_write, + .access = eventfs_enodev, + .unlink = eventfs_enodev, + .link = eventfs_enodev, + .symlink = eventfs_enodev, + .readlink = eventfs_enodev, + .inactive = eventfs_inactive, + .mmap = eventfs_enodev, + .munmap = eventfs_enodev, + .getdents = eventfs_enodev, + .resize = eventfs_enodev, + .rename = eventfs_enodev, + .ioctl = eventfs_enodev, + .putpage = eventfs_enodev, + .getpage = eventfs_enodev, + .sync = eventfs_enodev, + .advlock = eventfs_advlock, + .lock = eventfs_lock, + .unlock = eventfs_unlock +}; + +static bool ctor(scache_t *cache, void *obj) { + event_node_t *node = obj; + VOP_INIT(&node->vnode, &vnops, 0, V_TYPE_CHDEV, NULL); + POLL_INITHEADER(&node->pollheader); + return true; +} + +void eventfs_init() { + node_cache = slab_newcache(sizeof(event_node_t), 0, ctor, NULL); + __assert(node_cache); +} + +INIT_ROUTINE_DEFINE(eventfs, INIT_ROUTINE_FLAGS_NONE, eventfs_init, bsp_early); + +int eventfs_create_node(vnode_t **vnodep, size_t initval, bool semaphore) { + event_node_t *event_node = slab_allocate(node_cache); + if (event_node == NULL) + return ENOMEM; + + event_node->counter = initval; + event_node->semaphore = semaphore; + + *vnodep = &event_node->vnode; + return 0; +} diff --git a/kernel-src/include/kernel/eventfs.h b/kernel-src/include/kernel/eventfs.h new file mode 100644 index 00000000..45de57f9 --- /dev/null +++ b/kernel-src/include/kernel/eventfs.h @@ -0,0 +1,8 @@ +#ifndef _EVENTFS_H +#define _EVENTFS_H + +#include + +int eventfs_create_node(vnode_t **vnodep, size_t initval, bool semaphore); + +#endif diff --git a/kernel-src/sys/syscalls/eventfd.c b/kernel-src/sys/syscalls/eventfd.c new file mode 100644 index 00000000..39ff2368 --- /dev/null +++ b/kernel-src/sys/syscalls/eventfd.c @@ -0,0 +1,40 @@ +#include +#include + +#define EFD_CLOEXEC O_CLOEXEC +#define EFD_NONBLOCK O_NONBLOCK +#define EFD_SEMAPHORE 1 + +#define KNOWN_FLAGS (EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE) + +syscallret_t syscall_eventfd(context_t *, size_t initval, int flags) { + syscallret_t ret = { + .ret = -1 + }; + + if (flags & ~KNOWN_FLAGS) { + ret.errno = EINVAL; + return ret; + } + + vnode_t *vnode; + ret.errno = eventfs_create_node(&vnode, initval, flags & EFD_SEMAPHORE); + if (ret.errno) + return ret; + + file_t *file; + int fd; + ret.errno = fd_new((flags & EFD_CLOEXEC) ? O_CLOEXEC : 0, &file, &fd); + if (ret.errno) { + VOP_RELEASE(vnode); + return ret; + } + + file->vnode = vnode; + file->flags = FILE_WRITE | FILE_READ | ((flags & EFD_NONBLOCK) ? O_NONBLOCK : 0); + file->offset = 0; + file->mode = 0666; + + ret.ret = fd; + return ret; +} diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index ec49b952..73c5b91d 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -452,7 +452,7 @@ index a86353f..3e1a18c 100644 return error ? -1 : ret; } diff --git mlibc-clean/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp -index 3b04372..b7a8ab7 100644 +index 3b04372..5324a35 100644 --- mlibc-clean/sysdeps/astral/generic/generic.cpp +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp @@ -1,7 +1,9 @@ @@ -497,7 +497,7 @@ index 3b04372..b7a8ab7 100644 namespace mlibc { int Sysdeps::operator()(size_t size, const gid_t *list) { -@@ -31,14 +56,313 @@ namespace mlibc { +@@ -31,15 +56,324 @@ namespace mlibc { return 0; } @@ -627,9 +627,9 @@ index 3b04372..b7a8ab7 100644 + int Sysdeps::operator()(void **stack_base, size_t *stack_size) { + *stack_size = 1024 * 1024 * 4; + *stack_base = (void *)(0x0000800000000000 - *stack_size); -+ return 0; -+ } -+ + return 0; + } + +#ifndef MLIBC_BUILDING_RTLD + int Sysdeps::operator()(struct ifaddrs **out) { + struct ifaddrs *list = nullptr; @@ -804,19 +804,30 @@ index 3b04372..b7a8ab7 100644 + *out = arr; + freeifaddrs(ifaddrs); + - return 0; - } ++ return 0; ++ } +#endif + ++ int Sysdeps::operator()(unsigned int initval, int flags, int *fd) { ++ long ret; ++ int error = syscall(SYSCALL_EVENTFD, &ret, initval, flags); ++ if (error) ++ return error; ++ ++ *fd = ret; ++ return 0; ++ } ++ + int Sysdeps::operator()(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + long ret; + return syscall(SYSCALL_GETSOCKOPT, &ret, fd, layer, number, (uint64_t)buffer, (uint64_t)size); + } - ++ int Sysdeps::operator()(bool *ipv4, bool *ipv6) { // there is no ipv6 support in the kernel currently and no way of checking for configured interfaces -@@ -47,6 +371,71 @@ namespace mlibc { + *ipv4 = true; +@@ -47,6 +381,71 @@ namespace mlibc { return 0; } @@ -888,7 +899,7 @@ index 3b04372..b7a8ab7 100644 int Sysdeps::operator()(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) { long r; int error = syscall(SYSCALL_READV, &r, fd, (uint64_t)iovs, iovc); -@@ -86,6 +475,11 @@ namespace mlibc { +@@ -86,6 +485,11 @@ namespace mlibc { return e; } @@ -900,7 +911,7 @@ index 3b04372..b7a8ab7 100644 int Sysdeps::operator()(int sockfd, int how) { long ret; return syscall(SYSCALL_SHUTDOWN, &ret, sockfd, how); -@@ -487,8 +881,15 @@ namespace mlibc { +@@ -487,8 +891,15 @@ namespace mlibc { return err; } @@ -916,7 +927,7 @@ index 3b04372..b7a8ab7 100644 return syscall(SYSCALL_SETSOCKOPT, &ret, fd, layer, number, (uint64_t)buffer, size); } -@@ -511,6 +912,11 @@ namespace mlibc { +@@ -511,6 +922,11 @@ namespace mlibc { return err; } @@ -928,7 +939,7 @@ index 3b04372..b7a8ab7 100644 int Sysdeps::operator()(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { long ret; return syscall(SYSCALL_RENAMEAT, &ret, olddirfd, (uint64_t)old_path, newdirfd, (uint64_t)new_path); -@@ -562,6 +968,16 @@ namespace mlibc { +@@ -562,6 +978,16 @@ namespace mlibc { return sysdep(fd, TCSETS, (void *)attr, &res); } @@ -945,7 +956,7 @@ index 3b04372..b7a8ab7 100644 int Sysdeps::operator()(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { long ret; long error = syscall(SYSCALL_POLL, &ret, (uint64_t)fds, count, timeout); -@@ -932,4 +1348,13 @@ namespace mlibc { +@@ -932,4 +1358,13 @@ namespace mlibc { *nanos = ts.tv_nsec; return err; } @@ -982,10 +993,10 @@ index 7e4f2a1..ecc2677 100644 #ifdef __cplusplus extern "C" { diff --git mlibc-clean/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h -index a6c4067..160a140 100644 +index a6c4067..9040d45 100644 --- mlibc-clean/sysdeps/astral/include/astral/syscall.h +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h -@@ -103,6 +103,13 @@ +@@ -103,6 +103,14 @@ #define SYSCALL_SYSINFO 96 #define SYSCALL_WRITEV 97 #define SYSCALL_READV 98 @@ -996,6 +1007,7 @@ index a6c4067..160a140 100644 +#define SYSCALL_CLOCK_GETRES 103 +#define SYSCALL_SETPRIORITY 104 +#define SYSCALL_SYSCTL 105 ++#define SYSCALL_EVENTFD 106 #ifndef __MLIBC_ABI_ONLY @@ -1062,7 +1074,7 @@ index 0000000..161f634 + +#endif /* _ASTRAL_SYSCTL_H */ diff --git mlibc-clean/sysdeps/astral/include/mlibc/sysdeps.hpp mlibc-workdir/sysdeps/astral/include/mlibc/sysdeps.hpp -index ce91084..54ee08e 100644 +index ce91084..503110a 100644 --- mlibc-clean/sysdeps/astral/include/mlibc/sysdeps.hpp +++ mlibc-workdir/sysdeps/astral/include/mlibc/sysdeps.hpp @@ -7,8 +7,30 @@ namespace mlibc { @@ -1121,7 +1133,7 @@ index ce91084..54ee08e 100644 Poll, Ppoll, Pselect, -@@ -135,7 +161,10 @@ struct AstralSysdepTags : +@@ -135,7 +161,11 @@ struct AstralSysdepTags : VmUnmap, Isatty, ClockGet, @@ -1129,7 +1141,8 @@ index ce91084..54ee08e 100644 + ClockGetres, + PrepareStack, + SetPriority, -+ GetCurrentStackInfo ++ GetCurrentStackInfo, ++ EventfdCreate {}; template