Add select() on sockets

This commit is contained in:
Mark
2020-03-31 11:30:26 +03:00
parent 26bf9f60c0
commit 522a5cc9d6
8 changed files with 87 additions and 49 deletions
+1
View File
@@ -90,6 +90,7 @@ static uint32_t timer_tick(void *arg) {
list_for_each_safe(iter, b_iter, &g_sleep_head) {
struct io_notify *n = list_entry(iter, struct io_notify, link);
struct thread *t = n->owner;
if (!t) {
list_del_init(iter);
continue;
+2
View File
@@ -14,6 +14,8 @@ struct sockops {
int (*bind) (struct socket *, struct sockaddr *, size_t);
int (*setsockopt) (struct socket *, int, void *, size_t);
int (*count_pending) (struct socket *);
};
struct socket_class {
+4
View File
@@ -1,5 +1,6 @@
#pragma once
#include "sys/types.h"
#include "sys/wait.h"
struct sockaddr;
struct vfs_ioctx;
@@ -9,6 +10,7 @@ struct netdev;
struct socket {
struct sockops *op;
struct vfs_ioctx *ioctx;
struct io_notify rx_notify;
void *data;
};
@@ -28,3 +30,5 @@ ssize_t net_recvfrom(struct vfs_ioctx *ioctx,
int net_bind(struct vfs_ioctx *ioctx, struct ofile *fd, struct sockaddr *sa, size_t len);
int net_setsockopt(struct vfs_ioctx *ioctx, struct ofile *fd, int optname, void *optval, size_t optlen);
void net_close(struct vfs_ioctx *ioctx, struct ofile *fd);
int socket_has_data(struct socket *sock);
+55 -38
View File
@@ -25,6 +25,7 @@ static ssize_t raw_socket_recvfrom(struct socket *s,
struct sockaddr *sa,
size_t *salen);
static void raw_socket_close(struct socket *s);
static int raw_socket_count_pending(struct socket *s);
static struct sockops raw_socket_ops = {
.open = raw_socket_open,
.close = raw_socket_close,
@@ -34,39 +35,43 @@ static struct sockops raw_socket_ops = {
.bind = NULL,
.setsockopt = NULL,
.count_pending = raw_socket_count_pending
};
static struct socket_class raw_socket_class = {
.name = "raw-packet",
.ops = &raw_socket_ops,
.domain = AF_PACKET,
.type = SOCK_DGRAM,
.type = SOCK_RAW,
.supports = raw_class_supports,
};
////
struct raw_socket {
struct thread *wait;
spin_t lock;
struct socket *gen_sock;
struct packet_queue queue;
struct raw_socket *prev, *next;
struct list_head link;
};
static spin_t g_raw_lock = 0;
static struct raw_socket *g_raw_sockets = NULL;
static LIST_HEAD(g_raw_sockets);
void raw_packet_handle(struct packet *p) {
// Queue the packet for all the sockets
uintptr_t irq;
// TODO: too much time spent in spinlocked region?
spin_lock_irqsave(&g_raw_lock, &irq);
for (struct raw_socket *r = g_raw_sockets; r; r = r->next) {
struct raw_socket *r;
list_for_each_entry(r, &g_raw_sockets, link) {
packet_ref(p);
spin_lock(&r->lock);
packet_queue_push(&r->queue, p);
struct thread *w = r->wait;
if (w) {
r->wait = NULL;
sched_queue(w);
}
spin_release(&r->lock);
_assert(r->gen_sock);
thread_notify_io(&r->gen_sock->rx_notify);
}
spin_release_irqrestore(&g_raw_lock, &irq);
}
@@ -80,54 +85,66 @@ static __init void raw_class_register(void) {
static int raw_socket_open(struct socket *s) {
// TODO: check your privilege
uintptr_t irq;
struct raw_socket *r_sock = kmalloc(sizeof(struct raw_socket));
_assert(r_sock);
packet_queue_init(&r_sock->queue);
r_sock->prev = NULL;
r_sock->next = g_raw_sockets;
r_sock->wait = NULL;
g_raw_sockets = r_sock;
list_head_init(&r_sock->link);
r_sock->gen_sock = s;
r_sock->lock = 0;
spin_lock_irqsave(&g_raw_lock, &irq);
list_add(&r_sock->link, &g_raw_sockets);
spin_release_irqrestore(&g_raw_lock, &irq);
s->data = r_sock;
return 0;
}
static int raw_socket_count_pending(struct socket *s) {
struct raw_socket *sock = s->data;
_assert(sock);
return !!sock->queue.head;
}
static ssize_t raw_socket_recvfrom(struct socket *s,
void *buf,
size_t lim,
struct sockaddr *sa,
size_t *salen) {
return -EINVAL;
//struct raw_socket *sock = s->data;
//_assert(sock);
//struct thread *t = thread_self;
//_assert(t);
//struct packet *p;
uintptr_t irq;
int res;
struct raw_socket *sock = s->data;
_assert(sock);
struct thread *t = thread_self;
_assert(t);
struct packet *p;
//if (!sock->queue.head) {
// sock->wait = t;
if (!sock->queue.head) {
res = thread_wait_io(t, &sock->gen_sock->rx_notify);
// while (!sock->queue.head) {
// sched_unqueue(t, THREAD_WAITING_NET);
// thread_check_signal(t, 0);
// }
//}
if (res < 0) {
return res;
}
}
//// Read a single packet
//p = packet_queue_pop(&sock->queue);
//_assert(p);
spin_lock_irqsave(&sock->lock, &irq);
p = packet_queue_pop(&sock->queue);
spin_release_irqrestore(&sock->lock, &irq);
//size_t p_size = p->size;
//if (p_size > lim) {
// kerror("Packet buffer overflow\n");
// return -1;
//}
//memcpy(buf, p->data, p_size);
//packet_unref(p);
_assert(p);
//return p_size;
size_t p_size = p->size;
if (p_size > lim) {
kerror("Packet buffer overflow\n");
return -1;
}
memcpy(buf, p->data, p_size);
packet_unref(p);
return p_size;
}
static void raw_socket_close(struct socket *s) {
+7
View File
@@ -13,6 +13,11 @@ void socket_class_register(struct socket_class *cls) {
list_add(&cls->link, &g_socket_class_head);
}
int socket_has_data(struct socket *sock) {
_assert(sock->op && sock->op->count_pending);
return !!sock->op->count_pending(sock);
}
int net_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type, int proto) {
struct socket_class *cls, *iter;
@@ -29,6 +34,7 @@ int net_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type, int p
}
if (!cls) {
kinfo("Not supported: %d:%d:%d\n", dom, type, proto);
// No support for (dom:type:proto) tuple
return -EINVAL;
}
@@ -38,6 +44,7 @@ int net_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type, int p
fd->flags = OF_SOCKET;
fd->socket.ioctx = ioctx;
fd->socket.op = cls->ops;
thread_wait_io_init(&fd->socket.rx_notify);
return cls->ops->open(&fd->socket);
}
+5 -11
View File
@@ -269,7 +269,7 @@ ssize_t sys_readdir(int fd, struct dirent *ent) {
static int sys_select_get_ready(struct ofile *fd) {
if (fd->flags & OF_SOCKET) {
panic("TODO\n");
return socket_has_data(&fd->socket);
} else {
struct vnode *vn = fd->file.vnode;
_assert(vn);
@@ -292,7 +292,7 @@ static int sys_select_get_ready(struct ofile *fd) {
static struct io_notify *sys_select_get_wait(struct ofile *fd) {
if (fd->flags & OF_SOCKET) {
panic("TODO\n");
return &fd->socket.rx_notify;
} else {
struct vnode *vn = fd->file.vnode;
_assert(vn);
@@ -330,15 +330,10 @@ int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *excp, struct timeval *t
if (FD_ISSET(i, &_inp)) {
struct ofile *fd = thr->fds[i];
if (!fd || (fd->flags & OF_SOCKET)) {
if (!sys_select_get_wait(fd)) {
// Can't wait on that fd
return -EBADF;
}
_assert(fd->file.vnode);
if (fd->file.vnode->type != VN_CHR) {
kerror("Tried to select() on non-char device/file: %s\n", fd->file.vnode->name);
return -ENOSYS;
}
}
}
@@ -396,13 +391,12 @@ int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *excp, struct timeval *t
if (res < 0) {
// Likely interrupted
timer_remove_sleep(thr);
//timer_remove_sleep(thr);
break;
}
// Check if request timed out
if (result == &thr->sleep_notify) {
kdebug("Timed out\n");
res = 0;
break;
}
+12
View File
@@ -230,6 +230,7 @@ int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user) {
list_head_init(&thr->g_link);
list_head_init(&thr->shm_list);
list_head_init(&thr->wait_head);
thread_wait_io_init(&thr->sleep_notify);
thread_wait_io_init(&thr->pid_notify);
@@ -364,6 +365,7 @@ int sys_fork(struct sys_fork_frame *frame) {
list_head_init(&dst->g_link);
list_head_init(&dst->shm_list);
list_head_init(&dst->wait_head);
thread_wait_io_init(&dst->sleep_notify);
thread_wait_io_init(&dst->pid_notify);
@@ -627,6 +629,11 @@ __attribute__((noreturn)) void sys_exit(int status) {
struct thread *thr = thread_self;
kdebug("Thread %d exited with status %d\n", thr->pid, status);
// Clear pending I/O (if exiting from signal interrupting select())
if (!list_empty(&thr->wait_head)) {
thread_wait_io_clear(thr);
}
thr->exit_status = status;
if (thr->parent) {
@@ -683,6 +690,11 @@ void sys_sigreturn(void) {
}
void thread_signal(struct thread *thr, int signum) {
if (thr->sleep_notify.owner) {
thr->sleep_notify.owner = NULL;
timer_remove_sleep(thr);
}
if (thr->cpu == (int) get_cpu()->processor_id) {
if (thr == thread_self) {
kdebug("Signal will be handled now\n");
+1
View File
@@ -106,6 +106,7 @@ void thread_wait_io_clear(struct thread *t) {
while (!list_empty(&t->wait_head)) {
struct list_head *h = t->wait_head.next;
struct io_notify *n = list_entry(h, struct io_notify, own_link);
// TODO: maybe check here for sleep descriptors and cancel sleeps if needed
n->owner = NULL;
list_del_init(h);
}