libc: Implement select() on top of epoll()

This commit is contained in:
Alexander van der Grinten 2018-01-03 18:09:01 +01:00
parent a4369e4b8b
commit 8049641c65

View file

@ -1,6 +1,9 @@
#include <string.h>
#include <sys/epoll.h>
#include <sys/select.h>
#include <unistd.h>
#include <frigg/debug.hpp>
#include <mlibc/ensure.h>
@ -22,17 +25,77 @@ void FD_ZERO(fd_set *set) {
int select(int num_fds, fd_set *__restrict read_set, fd_set *__restrict write_set,
fd_set *__restrict except_set, struct timeval *__restrict timeout) {
frigg::infoLogger() << "\e[35mmlibc: Broken select() called.\e[39m" << frigg::endLog;
__ensure(!timeout);
int num_returned = 0;
for(int i = 0; i < num_fds; i++) {
if(except_set && FD_ISSET(i, except_set))
FD_CLR(i, except_set);
if(read_set && FD_ISSET(i, read_set))
num_returned++;
if(write_set && FD_ISSET(i, write_set))
num_returned++;
// TODO: Do not keep errors from epoll (?).
int fd = epoll_create1(0);
if(fd == -1)
return -1;
for(int k = 0; k < FD_SETSIZE; k++) {
struct epoll_event ev;
memset(&ev, 0, sizeof(struct epoll_event));
if(read_set && FD_ISSET(k, read_set))
ev.events |= EPOLLIN; // TODO: Additional events.
if(write_set && FD_ISSET(k, write_set))
ev.events |= EPOLLOUT; // TODO: Additional events.
if(except_set && FD_ISSET(k, except_set))
ev.events |= EPOLLPRI;
if(!ev.events)
continue;
ev.data.u32 = k;
if(epoll_ctl(fd, EPOLL_CTL_ADD, k, &ev))
return -1;
}
return num_returned;
struct epoll_event evnts[16];
int n = epoll_wait(fd, evnts, 16, -1);
if(n == -1)
return -1;
fd_set res_read_set;
fd_set res_write_set;
fd_set res_except_set;
FD_ZERO(&res_read_set);
FD_ZERO(&res_write_set);
FD_ZERO(&res_except_set);
int m = 0;
for(int i = 0; i < n; i++) {
int k = evnts[i].data.u32;
if(read_set && FD_ISSET(k, read_set)
&& evnts[i].events & EPOLLIN) {
FD_SET(k, &res_read_set);
m++;
}
if(write_set && FD_ISSET(k, write_set)
&& evnts[i].events & EPOLLOUT) {
FD_SET(k, &res_write_set);
m++;
}
if(except_set && FD_ISSET(k, except_set)
&& evnts[i].events & EPOLLPRI) {
FD_SET(k, &res_except_set);
m++;
}
}
if(close(fd))
__ensure("close() failed on epoll file");
if(read_set)
memcpy(read_set, &res_read_set, sizeof(fd_set));
if(write_set)
memcpy(write_set, &res_write_set, sizeof(fd_set));
if(except_set)
memcpy(except_set, &res_except_set, sizeof(fd_set));
return m;
}