#include <u.h>
#include <libc.h>
#include <ureg.h>
#include "linuxsys.h"
#include "linux.h"
SYSCALL(sys_epoll_create)
{
int size;
size = ARG1;
RETURN(epoll_create(size));
}
SYSCALL(sys_epoll_ctl)
{
int epfd;
int op;
int fd;
epoll_event *event;
epfd = ARG1;
op = ARG2;
fd = ARG3;
event = (epoll_event*)ARG4;
RETURN(epoll_ctl(epfd, op, fd, event));
}
SYSCALL(sys_epoll_wait)
{
int epfd;
epoll_event *events;
int maxevents;
int timeout;
epfd = ARG1;
events = (epoll_event*)ARG2;
maxevents = ARG3;
timeout = ARG4;
RETURN(epoll_wait(epfd, events, maxevents, timeout));
}
IOCTL(ioctl_FIONREAD)
{
int *p;
int r;
USED(cmd);
p = (int*)arg;
if(p==nil)
return -EINVAL;
r = buffdionread(fd);
if(r < 0){
*p = 0;
return r;
}
*p = r;
return 0;
}
struct pollfd
{
int fd;
short events;
short revents;
};
SYSCALL(sys_poll)
{
struct pollfd *fds;
int nfds;
long timeout;
int epfd;
int i, n;
epoll_event *rev;
fds = (struct pollfd*)ARG1;
nfds = ARG2;
timeout = ARG3;
if(nfds <= 0)
RETURN(-EINVAL);
epfd = epoll_create(nfds);
if(epfd < 0)
RETURN(-EINVAL);
for(i=0; i<nfds; i++){
epoll_event ev;
fds[i].revents = 0;
ev.events = fds[i].events;
ev.data = i;
epoll_ctl(epfd, EPOLL_CTL_ADD, fds[i].fd, &ev);
}
rev = malloc(sizeof(epoll_event)*nfds);
if(rev == nil){
_close(epfd);
RETURN(-ENOMEM);
}
n = epoll_wait(epfd, rev, nfds, timeout);
_close(epfd);
for(i=0; i<n; i++)
fds[rev[i].data].revents = rev[i].events;
free(rev);
RETURN(n);
}
typedef ulong fdsetel;
enum
{
FDSETBITS = 1024,
FDSETELBYTES = sizeof(fdsetel),
FDSETELBITS = 8*FDSETELBYTES,
FDSETELMAX = FDSETBITS/FDSETELBITS,
};
struct fd_set
{
fdsetel el[FDSETELMAX];
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
SYSCALL(sys_select)
{
int nfds;
struct fd_set *rfds;
struct fd_set *wfds;
struct fd_set *efds;
struct timeval *tv;
int i, n;
int timeout;
int epfd;
vlong t;
epoll_event *rev;
nfds = ARG1;
rfds = (struct fd_set*)ARG2;
wfds = (struct fd_set*)ARG3;
efds = (struct fd_set*)ARG4;
tv = (struct timeval*)ARG5;
DPRINT("select(%d, 0x%p, 0x%p, 0x%p, 0x%p)...", nfds, rfds, wfds, efds, tv);
epfd = epoll_create(nfds);
if(epfd < 0)
RETURN(-EINVAL);
n = 0;
for(i=0; i<FDSETELMAX; i++){
int j;
if(!((rfds && rfds->el[i]) || (wfds && wfds->el[i]) || (efds && efds->el[i])))
continue;
for(j=0; j<FDSETELBITS; j++){
epoll_event ev;
fdsetel bit;
int fd;
bit = (fdsetel)1<<j;
fd = (i * FDSETELBITS) + j;
if(fd >= nfds)
goto start;
ev.events = 0;
if(rfds && (rfds->el[i] & bit)){
ev.events |= POLLIN;
rfds->el[i] &= ~bit;
}
if(wfds && (wfds->el[i] & bit)){
ev.events |= POLLOUT;
wfds->el[i] &= ~bit;
}
if(efds && (efds->el[i] & bit)){
ev.events |= POLLERR | POLLHUP | POLLRDHUP;
efds->el[i] &= ~bit;
}
// no events selected, skip this fd
if(ev.events == 0)
continue;
ev.data = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
n++;
}
}
start:
// clear result fdsets
if(n == 0){
_close(epfd);
RETURN(0);
}
rev = malloc(sizeof(epoll_event) * n);
if(rev == nil){
_close(epfd);
RETURN(-ENOMEM);
}
if(tv==nil){
timeout = -1;
} else {
t = nsec();
timeout = (tv->tv_sec*1000) + (tv->tv_usec/1000);
if(timeout < 0)
timeout = 0;
}
n = epoll_wait(epfd, rev, n, timeout);
_close(epfd);
DPRINT("select ->\n");
nfds = 0;
for(i=0; i<n; i++){
int j;
fdsetel bit;
int fd;
fd = rev[i].data;
j = fd / FDSETELBITS;
bit = (fdsetel)1 << (fd % FDSETELBITS);
DPRINT("%d=[", fd);
if(rfds && (rev[i].events&POLLIN)){
DPRINT("I");
rfds->el[j] |= bit;
nfds++;
}
if(wfds && (rev[i].events&POLLOUT)){
DPRINT("O");
wfds->el[j] |= bit;
nfds++;
}
if(efds && (rev[i].events&(POLLERR|POLLHUP|POLLRDHUP))){
DPRINT("E");
efds->el[j] |= bit;
nfds++;
}
DPRINT("]\n");
}
free(rev);
DPRINT("got %d ready pollevents in total...", n);
if(tv && timeout>=0){
t = timeout*1000000 - (nsec() - t);
if(t < 0)
t = 0;
tv->tv_sec = (long)(t/1000000000LL);
tv->tv_usec = (long)((t%1000000000LL)/1000LL);
}
DPRINT("select returns %d\n", n);
RETURN(nfds);
}
|