224 lines
6.1 KiB
C
224 lines
6.1 KiB
C
/* C support for scsh select call.
|
|
** Copyright (c) 1995 by Olin Shivers.
|
|
*/
|
|
|
|
#include "sysdep.h"
|
|
|
|
#include <sys/types.h>
|
|
#if defined(HAVE_SYS_SELECT_H)
|
|
# include <sys/select.h>
|
|
#endif
|
|
#include <sys/time.h>
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
|
|
#include "cstuff.h"
|
|
#include "fdports.h" /* Accessors for Scheme I/O port internals. */
|
|
|
|
/* Make sure our exports match up w/the implementation: */
|
|
#include "select1.h"
|
|
|
|
/* the traditional sleazy max non-function. */
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
|
|
extern int errno;
|
|
|
|
static void or2_fdset(fd_set *x, fd_set *y, int max_elt);
|
|
static int copyback_fdvec(s48_value portvec, fd_set *fdset);
|
|
|
|
/* RVEC, WVEC, and EVEC are Scheme vectors of integer file descriptors,
|
|
** I/O ports, and #f's. NSECS is an integer timeout value, or #f for
|
|
** infinite wait. Do the select() call, returning result fd_sets in the
|
|
** passed pointers. Return 0 for OK, otherwise error is in errno.
|
|
*/
|
|
|
|
int do_select(s48_value rvec, s48_value wvec,
|
|
s48_value evec, s48_value nsecs,
|
|
fd_set *rset_ans, fd_set *wset_ans, fd_set *eset_ans)
|
|
{
|
|
struct timeval timeout, *tptr;
|
|
fd_set rset_bufrdy, wset_bufrdy, eset_bufrdy; /* Buffered port hits. */
|
|
int rbuf_rdy=0, wbuf_rdy=0, bufrdy; /* Set if we find buffered I/O hits. */
|
|
int max_fd = -1; /* Max fdes in the sets. */
|
|
int nelts, i;
|
|
int nfound;
|
|
|
|
FD_ZERO(rset_ans); FD_ZERO(wset_ans); FD_ZERO(eset_ans);
|
|
FD_ZERO(&rset_bufrdy); FD_ZERO(&wset_bufrdy); FD_ZERO(&eset_bufrdy);
|
|
|
|
/* Scan the readvec elts. */
|
|
nelts = S48_VECTOR_LENGTH(rvec);
|
|
for(i=nelts; --i >= 0; ) {
|
|
s48_value elt = S48_VECTOR_REF(rvec,i);
|
|
int fd;
|
|
|
|
fd = s48_extract_fixnum(elt);
|
|
FD_SET(fd, rset_ans);
|
|
|
|
max_fd = max(max_fd, fd);
|
|
}
|
|
|
|
/* Scan the writevec elts. */
|
|
nelts = S48_VECTOR_LENGTH(wvec);
|
|
for(i=nelts; --i >= 0; ) {
|
|
s48_value elt = S48_VECTOR_REF(wvec,i);
|
|
int fd;
|
|
|
|
fd = s48_extract_fixnum(elt);
|
|
FD_SET(fd, wset_ans);
|
|
|
|
max_fd = max(max_fd, fd);
|
|
}
|
|
|
|
/* Scan the exception-vec elts. */
|
|
nelts = S48_VECTOR_LENGTH(evec);
|
|
for(i=nelts; --i >= 0; ) {
|
|
s48_value elt = S48_VECTOR_REF(evec,i);
|
|
int fd;
|
|
|
|
fd = s48_extract_fixnum(elt);
|
|
FD_SET(fd, eset_ans);
|
|
|
|
max_fd = max(max_fd, fd);
|
|
}
|
|
|
|
bufrdy = rbuf_rdy || wbuf_rdy;
|
|
if( bufrdy ) { /* Already have some hits on buffered ports, */
|
|
timeout.tv_sec = 0; /* so we only poll the others. */
|
|
timeout.tv_usec = 0;
|
|
tptr = &timeout;
|
|
}
|
|
else if ( S48_FIXNUM_P(nsecs) ) {
|
|
timeout.tv_sec = s48_extract_fixnum(nsecs); /* Wait n seconds. */
|
|
timeout.tv_usec = 0;
|
|
tptr = &timeout;
|
|
}
|
|
else tptr = NULL; /* #f => Infinite wait. */
|
|
|
|
/* select1() is defined in sysdep.h -- bogus compatibility macro. */
|
|
nfound = select(max_fd+1, rset_ans, wset_ans, eset_ans, tptr); /* Do it.*/
|
|
|
|
/* EINTR is not an error return if we have hits on buffered ports
|
|
** to report.
|
|
*/
|
|
if( nfound < 0 )
|
|
if ( errno != EINTR || !bufrdy ) return -1;
|
|
else { /* EINTR, but we have hits on buffered ports to report. */
|
|
FD_ZERO(rset_ans); /* This should never happen -- */
|
|
FD_ZERO(wset_ans); /* EINTR on a zero-sec select() */
|
|
FD_ZERO(eset_ans); /* -- but I'm paranoid. */
|
|
}
|
|
|
|
/* OR together the buffered-io ready sets and the fd ready sets. */
|
|
if( rbuf_rdy ) or2_fdset(rset_ans, &rset_bufrdy, max_fd);
|
|
if( wbuf_rdy ) or2_fdset(wset_ans, &wset_bufrdy, max_fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* x = x or y */
|
|
static void or2_fdset(fd_set *x, fd_set *y, int max_elt)
|
|
{
|
|
int i;
|
|
for(i=max_elt+1; --i >= 0;)
|
|
if( FD_ISSET(i,y) ) FD_SET(i,x);
|
|
}
|
|
|
|
|
|
|
|
/* PORTVEC is a vector of integer file descriptors and Scheme ports.
|
|
** Scan over the vector, and copy any elt whose file descriptor is in FDSET
|
|
** to the front of the vector. Return the number of elts thus copied.
|
|
*/
|
|
static int copyback_fdvec(s48_value portvec, fd_set *fdset)
|
|
{
|
|
int vlen = S48_VECTOR_LENGTH(portvec);
|
|
int i, j=0;
|
|
for( i = -1; ++i < vlen; ) {
|
|
s48_value elt = S48_VECTOR_REF(portvec, i);
|
|
int fd = s48_extract_fixnum((S48_FIXNUM_P(elt)) ? elt : (1 / 0));
|
|
/* JMG *PortFd(elt));*/
|
|
if( FD_ISSET(fd,fdset) ) {
|
|
FD_CLR(fd,fdset); /* In case luser put elt in multiple times. */
|
|
S48_VECTOR_SET(portvec, j, elt);
|
|
j++;
|
|
}
|
|
}
|
|
return j;
|
|
}
|
|
|
|
|
|
/* Overwrite every inactive element in the vector with #f;
|
|
** Return count of active elements.
|
|
*/
|
|
|
|
static int clobber_inactives(s48_value portvec, fd_set *fdset)
|
|
{
|
|
int count = 0;
|
|
int i = S48_VECTOR_LENGTH(portvec);
|
|
|
|
while( --i >= 0 ) {
|
|
s48_value elt = S48_VECTOR_REF(portvec, i);
|
|
if( elt != S48_FALSE ) {
|
|
int fd = s48_extract_fixnum((S48_FIXNUM_P(elt)) ? elt : (1/0)); /* JMG *PortFd(elt));*/
|
|
if( FD_ISSET(fd,fdset) ) {
|
|
FD_CLR(fd,fdset); /* In case luser put elt in multiple times. */
|
|
++count;
|
|
}
|
|
else S48_VECTOR_SET(portvec, i, S48_FALSE); /* Clobber. */
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
/* These two functions are the entry points to this file.
|
|
*********************************************************
|
|
*/
|
|
|
|
/* Copy active elts back to the front of their vector;
|
|
** Return error indicator & number of hits for each vector.
|
|
*/
|
|
|
|
s48_value select_copyback(s48_value rvec, s48_value wvec,
|
|
s48_value evec, s48_value nsecs,
|
|
int *r_numrdy, int *w_numrdy, int *e_numrdy)
|
|
{
|
|
fd_set rset, wset, eset;
|
|
|
|
if( do_select(rvec, wvec, evec, nsecs, &rset, &wset, &eset) ) {
|
|
*r_numrdy = *w_numrdy = *e_numrdy = 0;
|
|
return s48_enter_fixnum(errno);
|
|
}
|
|
|
|
*r_numrdy = copyback_fdvec(rvec, &rset);
|
|
*w_numrdy = copyback_fdvec(wvec, &wset);
|
|
*e_numrdy = copyback_fdvec(evec, &eset);
|
|
return S48_FALSE;
|
|
}
|
|
|
|
|
|
/* Overwrite non-active elements in the vectors with #f;
|
|
** return error indicator & number of hits for each vector.
|
|
*/
|
|
|
|
s48_value select_filter(s48_value rvec, s48_value wvec,
|
|
s48_value evec, s48_value nsecs,
|
|
int *r_numrdy, int *w_numrdy, int *e_numrdy)
|
|
{
|
|
fd_set rset, wset, eset;
|
|
|
|
if( do_select(rvec, wvec, evec, nsecs, &rset, &wset, &eset) ) {
|
|
*r_numrdy = *w_numrdy = *e_numrdy = 0;
|
|
return s48_enter_fixnum(errno);
|
|
}
|
|
|
|
*r_numrdy = clobber_inactives(rvec, &rset);
|
|
*w_numrdy = clobber_inactives(wvec, &wset);
|
|
*e_numrdy = clobber_inactives(evec, &eset);
|
|
return S48_FALSE;
|
|
}
|