#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, np;
reg Sfio_t* f;
reg int *status, *check;
if(n <= 0 || !fa)
return -1;
if(!(status = (int*)malloc(2*n*sizeof(int))) )
return -1;
check = status+n;
#define RDREADY(f) (((f->mode&SF_READ) && f->next < f->endb) || \
((f->mode&SF_WRITE) && f->proc && f->proc->ndata > 0) )
#define WRREADY(f) (!(f->mode&SF_WRITE) || f->next == f->data)
#define HASAUXFD(f) (f->proc && f->proc->file >= 0 && f->proc->file != f->file)
for(r = c = 0; r < n; ++r)
{ f = fa[r];
status[r] = 0;
m = f->mode&SF_RDWR;
if((int)f->mode != m && _sfmode(f,m,0) < 0)
continue;
if((f->flags&SF_READ) && RDREADY(f))
status[r] |= SF_READ;
if((f->flags&SF_WRITE) && WRREADY(f))
status[r] |= SF_WRITE;
if((f->flags&SF_RDWR) == status[r])
continue;
if(f->disc && f->disc->exceptf)
{ if((m = (*f->disc->exceptf)(f,SF_DPOLL,&tm,f->disc)) < 0)
continue;
else if(m > 0)
{ status[r] = m&SF_RDWR;
continue;
}
}
if(f->extent < 0)
check[c++] = r;
else
{ if(f->flags&SF_READ)
status[r] |= SF_READ;
if(f->flags&SF_WRITE)
status[r] |= SF_WRITE;
}
}
np = -1;
#if _lib_poll
if(c > 0)
{ struct pollfd* fds;
for(m = 0, r = 0; r < c; ++r, ++m)
{ f = fa[check[r]];
if(HASAUXFD(f))
m += 1;
}
if(!(fds = (struct pollfd*)malloc(m*sizeof(struct pollfd))) )
return -1;
for(m = 0, r = 0; r < c; ++r, ++m)
{ f = fa[check[r]];
fds[m].fd = f->file;
fds[m].events = fds[m].revents = 0;
if((f->flags&SF_WRITE) && !WRREADY(f) )
fds[m].events |= POLLOUT;
if((f->flags&SF_READ) && !RDREADY(f) )
{
if((f->mode&SF_WRITE) && HASAUXFD(f))
{ m += 1;
fds[m].fd = f->proc->file;
fds[m].revents = 0;
}
fds[m].events |= POLLIN;
}
}
while((np = SFPOLL(fds,m,tm)) < 0 )
{ if(errno == EINTR || errno == EAGAIN)
errno = 0;
else break;
}
if(np > 0)
np = c;
for(m = 0, r = 0; r < np; ++r, ++m)
{ f = fa[check[r]];
if((f->flags&SF_WRITE) && !WRREADY(f) )
{ if(fds[m].revents&POLLOUT)
status[check[r]] |= SF_WRITE;
}
if((f->flags&SF_READ) && !RDREADY(f))
{ if((f->mode&SF_WRITE) && HASAUXFD(f))
m += 1;
if(fds[m].revents&POLLIN)
status[check[r]] |= SF_READ;
}
}
free((Void_t*)fds);
}
#endif
#if _lib_select
if(np < 0 && 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->flags&SF_WRITE) && !WRREADY(f))
FD_SET(f->file,&wr);
if((f->flags&SF_READ) && !RDREADY(f))
{ if((f->mode&SF_WRITE) && HASAUXFD(f))
{ if(f->proc->file > m)
m = f->proc->file;
FD_SET(f->proc->file, &rd);
}
else FD_SET(f->file,&rd);
}
}
if(tm < 0)
tmp = NIL(struct timeval*);
else
{ tmp = &tmb;
tmb.tv_sec = tm/SECOND;
tmb.tv_usec = (tm%SECOND)*SECOND;
}
while((np = select(m+1,&rd,&wr,NIL(fd_set*),tmp)) < 0 )
{ if(errno == EINTR)
errno = 0;
else break;
}
if(np > 0)
np = c;
for(r = 0; r < np; ++r)
{ f = fa[check[r]];
if((f->flags&SF_WRITE) && !WRREADY(f) )
{ if(FD_ISSET(f->file,&wr) )
status[check[r]] |= SF_WRITE;
}
if((f->flags&SF_READ) && !RDREADY(f) )
{ if((f->mode&SF_WRITE) && HASAUXFD(f) )
{ if(FD_ISSET(f->proc->file, &rd) )
status[check[r]] |= SF_READ;
}
else
{ if(FD_ISSET(f->file,&rd) )
status[check[r]] |= SF_READ;
}
}
}
}
#endif
for(r = c = 0; c < n; ++c)
{ if(status[c] == 0)
continue;
f = fa[c];
f->val = (ssize_t)status[c];
if(f->disc && f->disc->exceptf)
(*f->disc->exceptf)(f,SF_READY,(Void_t*)(long)status[c],f->disc);
if(c > r)
{ fa[c] = fa[r];
fa[r] = f;
}
r += 1;
}
free((Void_t*)status);
return r;
}