mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
kernel: poll system and poll syscall
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user