implement epoll (Jamie Turner)

This commit is contained in:
David du Colombier 2012-08-01 05:00:00 +02:00
parent f5ea2e72ba
commit ef218ac4d8
2 changed files with 129 additions and 1 deletions

123
fd.c
View File

@ -1,7 +1,14 @@
#include "taskimpl.h" #include "taskimpl.h"
#if USE_EPOLL
#include <sys/epoll.h>
#else
#include <sys/poll.h> #include <sys/poll.h>
#endif
#include <fcntl.h> #include <fcntl.h>
#if USE_EPOLL
static int epfd;
#else
enum enum
{ {
MAXFD = 1024 MAXFD = 1024
@ -10,11 +17,69 @@ enum
static struct pollfd pollfd[MAXFD]; static struct pollfd pollfd[MAXFD];
static Task *polltask[MAXFD]; static Task *polltask[MAXFD];
static int npollfd; static int npollfd;
#endif
static int startedfdtask; static int startedfdtask;
static Tasklist sleeping; static Tasklist sleeping;
static int sleepingcounted; static int sleepingcounted;
static uvlong nsec(void); static uvlong nsec(void);
#if USE_EPOLL
void
fdtask(void *v)
{
struct epoll_event events[1000];
int i, ms, nevents;
Task *t;
uvlong now;
USED(v);
tasksystem();
taskname("fdtask");
for(;;){
/* let everyone else run */
while(taskyield() > 0)
;
/* we're the only one runnable - poll for i/o */
errno = 0;
taskstate("epoll");
if((t=sleeping.head) == nil)
ms = -1;
else{
/* sleep at most 5s */
now = nsec();
if(now >= t->alarmtime)
ms = 0;
else if(now+5*1000*1000*1000LL >= t->alarmtime)
ms = (t->alarmtime - now)/1000000;
else
ms = 5000;
}
if((nevents = epoll_wait(epfd, events, 1000, ms)) < 0){
if(errno == EINTR)
continue;
fprint(2, "epoll: %s\n", strerror(errno));
taskexitall(0);
}
/* wake up the guys who deserve it */
for(i=0; i<nevents; i++){
taskready((Task *)events[i].data.ptr);
}
now = nsec();
while((t=sleeping.head) && now >= t->alarmtime){
deltask(&sleeping, t);
if(!t->system && --sleepingcounted == 0)
taskcount--;
taskready(t);
}
}
}
#else
void void
fdtask(void *v) fdtask(void *v)
{ {
@ -60,7 +125,7 @@ fdtask(void *v)
polltask[i] = polltask[npollfd]; polltask[i] = polltask[npollfd];
} }
} }
now = nsec(); now = nsec();
while((t=sleeping.head) && now >= t->alarmtime){ while((t=sleeping.head) && now >= t->alarmtime){
deltask(&sleeping, t); deltask(&sleeping, t);
@ -71,6 +136,8 @@ fdtask(void *v)
} }
} }
#endif
uint uint
taskdelay(uint ms) taskdelay(uint ms)
{ {
@ -79,6 +146,11 @@ taskdelay(uint ms)
if(!startedfdtask){ if(!startedfdtask){
startedfdtask = 1; startedfdtask = 1;
#if USE_EPOLL
epfd = epoll_create(1);
if(epfd < 0)
abort();
#endif
taskcreate(fdtask, 0, 32768); taskcreate(fdtask, 0, 32768);
} }
@ -113,6 +185,53 @@ taskdelay(uint ms)
return (nsec() - now)/1000000; return (nsec() - now)/1000000;
} }
#if USE_EPOLL
void
fdwait(int fd, int rw)
{
struct epoll_event ev;
int bits, duped, r;
if(!startedfdtask){
startedfdtask = 1;
epfd = epoll_create(1);
if(epfd < 0)
abort();
taskcreate(fdtask, 0, 32768);
}
taskstate("fdwait for %s", rw=='r' ? "read" : rw=='w' ? "write" : "error");
bits = 0;
switch(rw){
case 'r':
bits |= EPOLLIN | EPOLLPRI;
break;
case 'w':
bits |= EPOLLOUT;
break;
}
memset(&ev, 0, sizeof(ev));
ev.events = bits;
ev.data.ptr = taskrunning;
r = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
duped = 0;
if(r < 0 || errno == EEXIST){
duped = 1;
fd = dup(fd);
r = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
if(r != 0)
abort();
}
taskswitch();
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev);
if(duped)
close(fd);
}
#else
void void
fdwait(int fd, int rw) fdwait(int fd, int rw)
{ {
@ -147,6 +266,8 @@ fdwait(int fd, int rw)
taskswitch(); taskswitch();
} }
#endif
/* Like fdread but always calls fdwait before reading. */ /* Like fdread but always calls fdwait before reading. */
int int
fdread1(int fd, void *buf, int n) fdread1(int fd, void *buf, int n)

View File

@ -26,6 +26,13 @@
#endif #endif
#endif #endif
#define USE_EPOLL 1
#if !defined(__linux)
#undef USE_EPOLL
#define USE_EPOLL 0
#endif
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>