/*
* call-seq:
* IO.select(read_array
* [, write_array
* [, error_array
* [, timeout]]] ) => array or nil
*
* See <code>Kernel#select</code>.
*/
static VALUE
rb_f_select(argc, argv, obj)
int argc;
VALUE *argv;
VALUE obj;
{
VALUE read, write, except, timeout, res, list;
fd_set rset, wset, eset, pset;
fd_set *rp, *wp, *ep;
struct timeval *tp, timerec;
rb_io_t *fptr;
long i;
int max = 0, n;
int interrupt_flag = 0;
int pending = 0;
rb_scan_args(argc, argv, "13", &read, &write, &except, &timeout);
if (NIL_P(timeout)) {
tp = 0;
}
else {
timerec = rb_time_interval(timeout);
tp = &timerec;
}
FD_ZERO(&pset);
if (!NIL_P(read)) {
Check_Type(read, T_ARRAY);
rp = &rset;
FD_ZERO(rp);
for (i=0; i<RARRAY(read)->len; i++) {
GetOpenFile(rb_io_get_io(RARRAY(read)->ptr[i]), fptr);
FD_SET(fileno(fptr->f), rp);
if (READ_DATA_PENDING(fptr->f)) { /* check for buffered data */
pending++;
FD_SET(fileno(fptr->f), &pset);
}
if (max < fileno(fptr->f)) max = fileno(fptr->f);
}
if (pending) { /* no blocking if there's buffered data */
timerec.tv_sec = timerec.tv_usec = 0;
tp = &timerec;
}
}
else
rp = 0;
if (!NIL_P(write)) {
Check_Type(write, T_ARRAY);
wp = &wset;
FD_ZERO(wp);
for (i=0; i<RARRAY(write)->len; i++) {
GetOpenFile(rb_io_get_io(RARRAY(write)->ptr[i]), fptr);
FD_SET(fileno(fptr->f), wp);
if (max < fileno(fptr->f)) max = fileno(fptr->f);
if (fptr->f2) {
FD_SET(fileno(fptr->f2), wp);
if (max < fileno(fptr->f2)) max = fileno(fptr->f2);
}
}
}
else
wp = 0;
if (!NIL_P(except)) {
Check_Type(except, T_ARRAY);
ep = &eset;
FD_ZERO(ep);
for (i=0; i<RARRAY(except)->len; i++) {
GetOpenFile(rb_io_get_io(RARRAY(except)->ptr[i]), fptr);
FD_SET(fileno(fptr->f), ep);
if (max < fileno(fptr->f)) max = fileno(fptr->f);
if (fptr->f2) {
FD_SET(fileno(fptr->f2), ep);
if (max < fileno(fptr->f2)) max = fileno(fptr->f2);
}
}
}
else {
ep = 0;
}
max++;
n = rb_thread_select(max, rp, wp, ep, tp);
if (n < 0) {
rb_sys_fail(0);
}
if (!pending && n == 0) return Qnil; /* returns nil on timeout */
res = rb_ary_new2(3);
rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
if (interrupt_flag == 0) {
if (rp) {
list = RARRAY(res)->ptr[0];
for (i=0; i< RARRAY(read)->len; i++) {
GetOpenFile(rb_io_get_io(RARRAY(read)->ptr[i]), fptr);
if (FD_ISSET(fileno(fptr->f), rp)
|| FD_ISSET(fileno(fptr->f), &pset)) {
rb_ary_push(list, rb_ary_entry(read, i));
}
}
}
if (wp) {
list = RARRAY(res)->ptr[1];
for (i=0; i< RARRAY(write)->len; i++) {
GetOpenFile(rb_io_get_io(RARRAY(write)->ptr[i]), fptr);
if (FD_ISSET(fileno(fptr->f), wp)) {
rb_ary_push(list, rb_ary_entry(write, i));
}
else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), wp)) {
rb_ary_push(list, rb_ary_entry(write, i));
}
}
}
if (ep) {
list = RARRAY(res)->ptr[2];
for (i=0; i< RARRAY(except)->len; i++) {
GetOpenFile(rb_io_get_io(RARRAY(except)->ptr[i]), fptr);
if (FD_ISSET(fileno(fptr->f), ep)) {
rb_ary_push(list, rb_ary_entry(except, i));
}
else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), ep)) {
rb_ary_push(list, rb_ary_entry(except, i));
}
}
}
}
return res; /* returns an empty array on interrupt */
}