kernel: poll system and poll syscall

This commit is contained in:
Matheus
2023-07-08 22:02:36 -03:00
parent 0ed524f456
commit e938d0332e
11 changed files with 287 additions and 22 deletions
+3 -1
View File
@@ -33,6 +33,7 @@ extern syscall_readlinkat
extern syscall_fchmod
extern syscall_fchmodat
extern syscall_umask
extern syscall_poll
syscalltab:
dq syscall_print
dq syscall_mmap
@@ -68,7 +69,8 @@ dq syscall_readlinkat
dq syscall_fchmod
dq syscall_fchmodat
dq syscall_umask
syscallcount equ 34
dq syscall_poll
syscallcount equ 35
section .text
global arch_syscall_entry
; on entry:
+5 -3
View File
@@ -4,7 +4,7 @@
#ifdef SYSCALL_LOGGING
#define SYSCALL_COUNT 34
#define SYSCALL_COUNT 35
#define LOGSTR(x) arch_e9_puts(x)
static char *name[] = {
@@ -41,7 +41,8 @@ static char *name[] = {
"readlinkat",
"fchmod",
"fchmodat",
"umask"
"umask",
"poll"
};
static char *args[] = {
@@ -78,7 +79,8 @@ static char *args[] = {
"dirfd %d path %s buffer %p buffer length %lu", // readlinkat
"fd %d mode %o", // fchmod
"dirfd %d path %s mode %o flags %d", // fchmodat
"mode %o" // umask
"mode %o", // umask
"fds %p nfds %d timeout %d" // poll
};
#endif
+2 -2
View File
@@ -145,7 +145,7 @@ int devfs_setattr(vnode_t *node, vattr_t *attr, cred_t *cred) {
return 0;
}
int devfs_poll(vnode_t *node, int events) {
int devfs_poll(vnode_t *node, polldata_t *data, int events) {
devnode_t *devnode = (devnode_t *)node;
if (devnode->master)
devnode = devnode->master;
@@ -153,7 +153,7 @@ int devfs_poll(vnode_t *node, int events) {
if (devnode->devops->poll == NULL)
return ENODEV;
return devnode->devops->poll(devnode->attr.rdevminor, events);
return devnode->devops->poll(devnode->attr.rdevminor, data, events);
}
int devfs_mmap(vnode_t *node, void *addr, uintmax_t offset, int flags, cred_t *cred) {
+2 -1
View File
@@ -7,6 +7,7 @@
#include <logging.h>
#include <errno.h>
#include <kernel/abi.h>
#include <kernel/poll.h>
#define BUFFER_SIZE 16 * PAGE_SIZE
@@ -147,7 +148,7 @@ int pipefs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int
return error;
}
int pipefs_poll(vnode_t *node, int events) {
int pipefs_poll(vnode_t *node, polldata_t *data, int events) {
pipenode_t *pipenode = (pipenode_t *)node;
int revents = 0;
VOP_LOCK(node);
+1 -12
View File
@@ -29,17 +29,6 @@ static int tmpfs_mount(vfs_t **vfs, vnode_t *mountpoint, vnode_t *backing, void
return 0;
}
static int tmpfs_poll(vnode_t *node, int event) {
int ret = 0;
if (event & POLLIN)
ret |= POLLIN;
if (event & POLLOUT)
ret |= POLLOUT;
return ret;
}
#define DATAMMUFLAGS (ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_NOEXEC)
// expects to be called with node locked
@@ -491,7 +480,7 @@ static vops_t vnops = {
.getattr = tmpfs_getattr,
.setattr = tmpfs_setattr,
.lookup = tmpfs_lookup,
.poll = tmpfs_poll,
.poll = vfs_pollstub,
.read = tmpfs_read,
.write = tmpfs_write,
.access = tmpfs_access,
+13
View File
@@ -5,6 +5,7 @@
#include <kernel/alloc.h>
#include <errno.h>
#include <arch/cpu.h>
#include <kernel/poll.h>
#define PATHNAME_MAX 512
#define MAXLINKDEPTH 64
@@ -27,6 +28,18 @@ static cred_t *getcred() {
return &_cpu()->thread->proc->cred;
}
int vfs_pollstub(vnode_t *node, struct polldata *, int events) {
int revents = 0;
if (events & POLLIN)
revents |= POLLIN;
if (events & POLLOUT)
revents |= POLLOUT;
return revents;
}
void vfs_init() {
__assert(hashtable_init(&fstable, 20) == 0);
vfsroot = alloc(sizeof(vnode_t));
+3 -1
View File
@@ -3,6 +3,8 @@
#include <kernel/vfs.h>
#include <kernel/poll.h>
#define DEV_MAJOR_NULL 1
#define DEV_MAJOR_FULL 2
#define DEV_MAJOR_ZERO 3
@@ -13,7 +15,7 @@ typedef struct {
int (*close)(int minor, int flags);
int (*read)(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc);
int (*write)(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec);
int (*poll)(int minor, int events);
int (*poll)(int minor, polldata_t *data, int events);
int (*mmap)(int minor, void *addr, uintmax_t offset, int flags);
int (*munmap)(int minor, void *addr, uintmax_t offset, int flags);
int (*isatty)(int minor);
+43
View File
@@ -0,0 +1,43 @@
#ifndef _POLL_H
#define _POLL_H
#include <kernel/scheduler.h>
#include <spinlock.h>
#include <mutex.h>
struct polldata;
typedef struct {
thread_t *thread;
spinlock_t lock;
mutex_t eventlock;
struct polldata *data;
struct polldata *event;
size_t size;
} polldesc_t;
typedef struct {
mutex_t lock;
struct polldata *data;
} pollheader_t;
typedef struct polldata {
struct polldata *next;
struct polldata *prev;
pollheader_t *header;
polldesc_t *desc;
int events;
int revents;
} polldata_t;
#define POLL_INITHEADER(x) \
MUTEX_INIT(&(x)->lock);
int poll_initdesc(polldesc_t *, size_t size);
void poll_add(pollheader_t *, polldata_t *, int events);
void poll_leave(polldesc_t *);
int poll_dowait(polldesc_t *);
void poll_event(pollheader_t *, int events);
void poll_destroydesc(polldesc_t *);
#endif
+5 -2
View File
@@ -72,6 +72,8 @@ typedef struct vfsops_t {
int (*root)(vfs_t *vfs, vnode_t **root);
} vfsops_t;
struct polldata;
typedef struct vops_t {
int (*open)(vnode_t **node, int flags, cred_t *cred);
int (*close)(vnode_t *node, int flags, cred_t *cred);
@@ -81,7 +83,7 @@ typedef struct vops_t {
int (*create)(vnode_t *parent, char *name, vattr_t *attr, int type, vnode_t **result, cred_t *cred);
int (*getattr)(vnode_t *node, vattr_t *attr, cred_t *cred);
int (*setattr)(vnode_t *node, vattr_t *attr, cred_t *cred);
int (*poll)(vnode_t *node, int events);
int (*poll)(vnode_t *node, struct polldata *, int events);
int (*access)(vnode_t *node, mode_t mode, cred_t *cred);
int (*unlink)(vnode_t *node, char *name, cred_t *cred);
int (*link)(vnode_t *node, vnode_t *dir, char *name, cred_t *cred);
@@ -119,7 +121,7 @@ typedef struct vops_t {
#define VOP_MMAP(v, a, o, f, c) (v)->ops->mmap(v, a, o, f, c)
#define VOP_MUNMAP(v, a, o, f, c) (v)->ops->munmap(v, a, o, f, c)
#define VOP_GETDENTS(v, b, c, o, rc) (v)->ops->getdents(v, b, c, o, rc)
#define VOP_POLL(v, p) (v)->ops->poll(v, p)
#define VOP_POLL(v, d, p) (v)->ops->poll(v, d, p)
#define VOP_ISATTY(v) ((v)->ops->isatty ? (v)->ops->isatty(v) : ENOTTY)
#define VOP_IOCTL(v, r, a, rp) ((v)->ops->ioctl ? (v)->ops->ioctl(v, r, a, rp) : ENOTTY)
#define VOP_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST)
@@ -143,6 +145,7 @@ int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t
int vfs_create(vnode_t *ref, char *path, vattr_t *attr, int type, vnode_t **node);
int vfs_link(vnode_t *destref, char *destpath, vnode_t *linkref, char *linkpath, int type, vattr_t *attr);
int vfs_unlink(vnode_t *ref, char *path);
int vfs_pollstub(vnode_t *node, struct polldata *, int events);
#define VFS_LOOKUP_PARENT 1
#define VFS_LOOKUP_NOLINK 2
+128
View File
@@ -0,0 +1,128 @@
#include <kernel/poll.h>
#include <arch/cpu.h>
#include <kernel/alloc.h>
#include <logging.h>
#include <kernel/interrupt.h>
static void insertinheader(pollheader_t *header, polldata_t *data) {
data->prev = NULL;
data->next = header->data;
if (header->data)
header->data->prev = data;
header->data = data;
}
static void removefromlist(polldata_t **list, polldata_t *data) {
if (data->next)
data->next->prev = data->prev;
if (data->prev)
data->prev->next = data->next;
else
*list = data->next;
data->prev = NULL;
data->next = NULL;
}
int poll_initdesc(polldesc_t *desc, size_t size) {
__assert(size);
desc->data = alloc(sizeof(polldata_t) * size);
if (desc->data == NULL)
return ENOMEM;
desc->thread = _cpu()->thread;
desc->size = size;
SPINLOCK_INIT(desc->lock);
MUTEX_INIT(&desc->eventlock);
for (uintmax_t i = 0; i < size; ++i)
desc->data[i].desc = desc;
return 0;
}
void poll_add(pollheader_t *header, polldata_t *data, int events) {
MUTEX_ACQUIRE(&header->lock, false);
data->events = events;
data->header = header;
insertinheader(header, data);
MUTEX_RELEASE(&header->lock);
}
void poll_leave(polldesc_t *desc) {
for (uintmax_t i = 0; i < desc->size; ++i) {
pollheader_t *header = desc->data[i].header;
if (header == NULL)
continue;
MUTEX_ACQUIRE(&header->lock, false);
removefromlist(&header->data, &desc->data[i]);
MUTEX_RELEASE(&header->lock);
}
}
int poll_dowait(polldesc_t *desc) {
MUTEX_ACQUIRE(&desc->eventlock, false);
if (desc->event) {
MUTEX_RELEASE(&desc->eventlock);
return 0;
}
sched_preparesleep(true);
spinlock_release(&desc->lock);
MUTEX_RELEASE(&desc->eventlock);
int ret = sched_yield();
// on return, the desc lock is REQUIRED to be left locked by the poll_event function.
// XXX interruptible wait breaks this
__assert(spinlock_try(&desc->lock) == false);
return ret;
}
void poll_event(pollheader_t *header, int events) {
MUTEX_ACQUIRE(&header->lock, false);
polldata_t *pending = header->data;
header->data = NULL;
polldata_t *iterator = pending;
while (iterator) {
polldesc_t *desc = iterator->desc;
polldata_t *next = iterator->next;
MUTEX_ACQUIRE(&desc->eventlock, false);
// TODO POLLHUP and POLLERR
int revents = iterator->events & events;
if (spinlock_try(&desc->lock) == false) {
removefromlist(&pending, iterator);
insertinheader(header, iterator);
}
if (revents && desc->event == NULL) {
iterator->revents = revents;
desc->event = iterator;
}
MUTEX_RELEASE(&desc->eventlock);
iterator = next;
}
int ipl = interrupt_raiseipl(IPL_DPC);
iterator = pending;
while (iterator) {
polldata_t *next = iterator->next;
sched_wakeup(iterator->desc->thread, 0);
insertinheader(header, iterator);
iterator = next;
}
MUTEX_RELEASE(&header->lock);
interrupt_loweripl(ipl);
}
void poll_destroydesc(polldesc_t *desc) {
free(desc->data);
}
+82
View File
@@ -0,0 +1,82 @@
#include <kernel/syscalls.h>
#include <kernel/file.h>
#include <kernel/poll.h>
#include <kernel/vmm.h>
#include <logging.h>
#include <kernel/alloc.h>
typedef struct {
int fd;
short events;
short revents;
} pollfd_t;
syscallret_t syscall_poll(context_t *, pollfd_t *fds, size_t nfds, int timeoutms) {
syscallret_t ret = {
.ret = -1
};
// timeouts are not supported yet
__assert(timeoutms <= 0);
if ((void *)fds > USERSPACE_END) {
ret.errno = EFAULT;
return ret;
}
size_t fdsbuffsize = nfds * sizeof(pollfd_t);
pollfd_t *fdsbuff = alloc(fdsbuffsize);
if (fdsbuff == NULL) {
ret.errno = ENOMEM;
return ret;
}
memcpy(fdsbuff, fds, fdsbuffsize);
polldesc_t desc = {0};
ret.errno = poll_initdesc(&desc, nfds);
if (ret.errno) {
goto cleanup;
}
__assert(spinlock_try(&desc.lock));
size_t eventcount = 0;
for (uintmax_t i = 0; i < nfds; ++i) {
file_t *file = fd_get(fdsbuff[i].fd);
if (file == NULL) {
fdsbuff[i].revents = POLLNVAL;
++eventcount;
continue;
}
int revents = VOP_POLL(file->vnode, timeoutms == 0 ? NULL : &desc.data[i], fdsbuff[i].events);
if (revents) {
fdsbuff[i].revents = revents;
++eventcount;
}
fd_release(file);
}
if (eventcount == 0 && timeoutms != 0) {
// TODO timeout
ret.errno = poll_dowait(&desc);
if (ret.errno == 0) {
int fd = ((uintptr_t)desc.event - (uintptr_t)desc.data) / sizeof(pollfd_t);
fdsbuff[fd].revents = desc.data[fd].revents;
eventcount = 1;
}
}
memcpy(fds, fdsbuff, fdsbuffsize);
poll_leave(&desc);
ret.ret = eventcount;
cleanup:
free(fdsbuff);
return ret;
}