select() syscall for character device reads
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
#include "sys/types.h"
|
||||
#include "sys/fs/dirent.h"
|
||||
#include "sys/stat.h"
|
||||
#include "sys/select.h"
|
||||
|
||||
struct timeval;
|
||||
|
||||
ssize_t sys_read(int fd, void *buf, size_t lim);
|
||||
ssize_t sys_write(int fd, const void *buf, size_t lim);
|
||||
@@ -20,6 +23,11 @@ int sys_rmdir(const char *pathname);
|
||||
int sys_stat(const char *filename, struct stat *st);
|
||||
int sys_access(const char *path, int mode);
|
||||
|
||||
// XXX: Except timeout is const, as I don't want to modify it
|
||||
// No one cares about how much time is remaining once
|
||||
// select() returns, right?
|
||||
int sys_select(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, struct timeval *timeout);
|
||||
|
||||
// TODO: const struct termios *termp, const struct winsize *winp
|
||||
int sys_openpty(int *master, int *slave);
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
#include "sys/ring.h"
|
||||
|
||||
struct chrdev {
|
||||
void *dev_data;
|
||||
struct ring buffer;
|
||||
|
||||
ssize_t (*write) (struct chrdev *chr, const void *buf, size_t pos, size_t lim);
|
||||
ssize_t (*read) (struct chrdev *chr, void *buf, size_t pos, size_t lim);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
struct timeval;
|
||||
|
||||
// 64 bits
|
||||
typedef long int __fd_mask;
|
||||
|
||||
#define __NFDBITS (8 * (int) sizeof(__fd_mask))
|
||||
// TODO: Guess this should be the same as the maximum
|
||||
// per-process filedes count
|
||||
#define __FD_SETSIZE 64
|
||||
|
||||
typedef struct {
|
||||
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
|
||||
} fd_set;
|
||||
|
||||
#define FD_SET(fd, fds) \
|
||||
(fds)->fds_bits[(fd) / __NFDBITS] |= (1ULL << ((fd) % __NFDBITS))
|
||||
|
||||
#define FD_ISSET(fd, fds) \
|
||||
(!!((fds)->fds_bits[(fd) / __NFDBITS] & (1ULL << ((fd) % __NFDBITS))))
|
||||
|
||||
#define FD_ZERO(fds) \
|
||||
for (int __i = 0; __i < (__FD_SETSIZE / __NFDBITS); ++__i) \
|
||||
(fds)->fds_bits[__i] = 0
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
// Implemented by libc
|
||||
int select(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, struct timeval *tv);
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@
|
||||
#define SYSCALL_NR_STAT 4
|
||||
#define SYSCALL_NR_LSEEK 8
|
||||
#define SYSCALL_NR_ACCESS 21
|
||||
#define SYSCALL_NR_SELECT 23
|
||||
#define SYSCALL_NR_GETCWD 79
|
||||
#define SYSCALL_NR_CHDIR 80
|
||||
#define SYSCALL_NR_MKDIR 83
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ KERNEL_HEADERS="include/sys/fcntl.h \
|
||||
include/sys/time.h \
|
||||
include/sys/errno.h \
|
||||
include/sys/signum.h \
|
||||
include/sys/utsname.h"
|
||||
include/sys/utsname.h \
|
||||
include/sys/select.h"
|
||||
|
||||
for src_file in $KERNEL_HEADERS; do
|
||||
dst_file=$INSTALL_HDR$(echo $src_file | sed -e 's/^include//g')
|
||||
|
||||
@@ -216,3 +216,77 @@ off_t sys_lseek(int fd, off_t offset, int whence) {
|
||||
|
||||
return vfs_lseek(&thr->ioctx, ofile, offset, whence);
|
||||
}
|
||||
|
||||
int sys_select(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, struct timeval *tv) {
|
||||
struct thread *thr = get_cpu()->thread;
|
||||
_assert(thr);
|
||||
|
||||
// Not implemented yet
|
||||
_assert(!wr);
|
||||
_assert(!exc);
|
||||
|
||||
// TODO: write fd_set
|
||||
fd_set _rd;
|
||||
memcpy(&_rd, rd, sizeof(fd_set));
|
||||
FD_ZERO(rd);
|
||||
|
||||
if (!rd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check file descriptors
|
||||
for (int i = 0; i < nfds; ++i) {
|
||||
if (FD_ISSET(i, &_rd)) {
|
||||
if (i > THREAD_MAX_FDS) {
|
||||
kwarn("Bad FD: %d\n", i);
|
||||
return -EBADF;
|
||||
}
|
||||
struct ofile *fd = thr->fds[i];
|
||||
if (!fd) {
|
||||
kwarn("Bad FD: %d\n", i);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
_assert(fd->vnode);
|
||||
if (fd->vnode->type != VN_CHR) {
|
||||
// select() does not make sense for non-char devices yet
|
||||
FD_SET(i, rd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t deadline = tv->tv_sec * 1000000000ULL + tv->tv_usec * 1000ULL + system_time;
|
||||
int res;
|
||||
|
||||
while (1) {
|
||||
// Check for any ready FD
|
||||
for (int i = 0; i < nfds; ++i) {
|
||||
if (FD_ISSET(i, &_rd)) {
|
||||
struct ofile *fd = thr->fds[i];
|
||||
_assert(fd && fd->vnode && fd->vnode->type == VN_CHR);
|
||||
|
||||
struct chrdev *chr = fd->vnode->dev;
|
||||
_assert(chr);
|
||||
|
||||
if (ring_avail(&chr->buffer) > 0) {
|
||||
FD_SET(i, rd);
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check timer deadline
|
||||
if (system_time >= deadline) {
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Yield
|
||||
asm volatile ("sti; hlt; cli");
|
||||
}
|
||||
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ const void *amd64_syscall_jmp_table[256] = {
|
||||
[SYSCALL_NR_OPEN] = sys_open,
|
||||
[SYSCALL_NR_CLOSE] = sys_close,
|
||||
[SYSCALL_NR_LSEEK] = sys_lseek,
|
||||
[SYSCALL_NR_SELECT] = sys_select,
|
||||
[SYSCALL_NR_GETCWD] = sys_getcwd,
|
||||
[SYSCALL_NR_CHDIR] = sys_chdir,
|
||||
[SYSCALL_NR_STAT] = sys_stat,
|
||||
|
||||
@@ -23,15 +23,17 @@ static struct chrdev _dev_tty0 = {
|
||||
.read = tty_read
|
||||
};
|
||||
|
||||
static struct ring tty_ring = {0};
|
||||
|
||||
// This function receives keystrokes from keyboard drivers
|
||||
void tty_buffer_write(int tty_no, char c) {
|
||||
ring_putc(NULL, &tty_ring, c);
|
||||
switch (tty_no) {
|
||||
case 0:
|
||||
ring_putc(NULL, &_dev_tty0.buffer, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tty_init(void) {
|
||||
ring_init(&tty_ring, 16);
|
||||
ring_init(&_dev_tty0.buffer, 16);
|
||||
|
||||
dev_add(DEV_CLASS_CHAR, DEV_CHAR_TTY, &_dev_tty0, "tty0");
|
||||
}
|
||||
@@ -67,7 +69,7 @@ static ssize_t tty_read(struct chrdev *tty, void *buf, size_t pos, size_t lim) {
|
||||
size_t p = 0;
|
||||
|
||||
while (rem) {
|
||||
ssize_t rd = ring_read(get_cpu()->thread, &tty_ring, ibuf, MIN(16, rem));
|
||||
ssize_t rd = ring_read(get_cpu()->thread, &tty->buffer, ibuf, MIN(16, rem));
|
||||
if (rd < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user