#include "sfhdr.h"
#if __STD_C
int sfpoll(Sfio_t** fa, reg int n, int tm)
#else
int sfpoll(fa, n, tm)
Sfio_t** fa;
reg int n;
int tm;
#endif
{
reg int r, c, m;
reg Sfio_t* f;
reg Sfdisc_t* d;
reg int *status, *check;
if(n <= 0 || !fa)
return -1;
if(!(status = (int*)malloc(2*n*sizeof(int))) )
return -1;
else check = status+n;
retry: for(r = c = 0; r < n; ++r)
{ f = fa[r];
for(;;)
{
m = f->mode&SF_RDWR;
if((int)f->mode != m && _sfmode(f,m,0) < 0)
goto do_never;
if(f->next < f->endb)
goto do_ready;
for(d = f->disc; d; d = d->disc)
if(d->exceptf)
break;
if(d)
{ if((m = (*d->exceptf)(f,SF_DPOLL,&tm,d)) < 0)
goto do_never;
else if(m > 0)
goto do_ready;
}
if(f->extent < 0)
goto do_check;
if(!f->push)
goto do_ready;
if(!(f->flags&SF_STRING) &&
((f->mode&SF_WRITE) || f->here < f->extent) )
goto do_ready;
SETLOCAL(f);
switch(_sfexcept(f,f->mode&SF_RDWR,0,f->disc))
{
case SF_EDONE:
if(f->flags&SF_STRING)
goto do_never;
else goto do_ready;
case SF_EDISC:
if(f->flags&SF_STRING)
goto do_ready;
case SF_ESTACK:
case SF_ECONT:
continue;
}
}
do_check:
{ status[r] = 0;
check[c] = r;
c += 1;
continue;
}
do_ready:
{ status[r] = 1;
continue;
}
do_never:
{ status[r] = -1;
continue;
}
}
#if _lib_poll
if(c > 0)
{ struct pollfd* fds;
if(!(fds = (struct pollfd*)malloc(c*sizeof(struct pollfd))) )
return -1;
for(r = 0; r < c; r++)
{ fds[r].fd = fa[check[r]]->file;
fds[r].events = (fa[check[r]]->mode&SF_READ) ? POLLIN : POLLOUT;
fds[r].revents = 0;
}
for(;;)
{ if((r = SFPOLL(fds,c,tm)) == 0)
break;
else if(r < 0)
{ if(errno == EINTR || errno == EAGAIN)
{ errno = 0;
continue;
}
else break;
}
for(r = 0; r < c; ++r)
{ f = fa[check[r]];
if(((f->mode&SF_READ) && (fds[r].revents&POLLIN)) ||
((f->mode&SF_WRITE) && (fds[r].revents&POLLOUT)) )
status[check[r]] = 1;
}
break;
}
free((Void_t*)fds);
}
#endif
#if _lib_select
if(c > 0)
{ fd_set rd, wr;
struct timeval tmb, *tmp;
FD_ZERO(&rd);
FD_ZERO(&wr);
m = 0;
for(r = 0; r < c; ++r)
{ f = fa[check[r]];
if(f->file > m)
m = f->file;
if(f->mode&SF_READ)
FD_SET(f->file,&rd);
else FD_SET(f->file,&wr);
}
if(tm < 0)
tmp = NIL(struct timeval*);
else
{ tmp = &tmb;
tmb.tv_sec = tm/SECOND;
tmb.tv_usec = (tm%SECOND)*SECOND;
}
for(;;)
{ if((r = select(m+1,&rd,&wr,NIL(fd_set*),tmp)) == 0)
break;
else if(r < 0)
{ if(errno == EINTR)
continue;
else break;
}
for(r = 0; r < c; ++r)
{ f = fa[check[r]];
if(((f->mode&SF_READ) && FD_ISSET(f->file,&rd)) ||
((f->mode&SF_WRITE) && FD_ISSET(f->file,&wr)) )
status[check[r]] = 1;
}
break;
}
}
#endif
for(c = 0; c < n; ++c)
{ if(status[c] <= 0)
continue;
if((d = fa[c]->disc) && d->exceptf)
{ if((r = (*d->exceptf)(fa[c],SF_READY,(Void_t*)0,d)) < 0)
goto done;
else if(r > 0)
goto retry;
}
}
for(r = c = 0; c < n; ++c)
{ if(status[c] > 0)
{ if(c > r)
{ f = fa[r];
fa[r] = fa[c];
fa[c] = f;
}
r += 1;
}
}
done:
free((Void_t*)status);
return r;
}