class Kqueue

Public Class Methods

new() click to toggle source
static VALUE
rb_kqueue_initialize(VALUE self)
{
  rb_io_t *fp;
  int fd;

  fd = kqueue();
  if (fd == -1)
    rb_sys_fail("kqueue");
  rb_update_max_fd(fd);

  MakeOpenFile(self, fp);
  fp->fd = fd;
  fp->mode = FMODE_READABLE|FMODE_BINMODE;
  rb_io_ascii8bit_binmode(self);

  IVAR_SET(self, rb_hash_new());

  return self;
}

Public Instance Methods

kevent(p1, p2, p3 = v3) click to toggle source
static VALUE
rb_kqueue_kevent(int argc, VALUE *argv, VALUE self)
{
  VALUE ch_list, max_events, timeout, ev, ready_evlist;
  struct kqueue_kevent_args args;
  struct timespec ts;
  struct timespec *pts = NULL;
  struct timeval tv;
  int i;
  int ev_len = 0, ch_len = 0;
  int ready;
  struct kevent *chl = NULL, *evl = NULL;
  rb_io_t *fptr, *fptr_io;

  fptr = RFILE(self)->fptr;
  rb_io_check_initialized(fptr);

  rb_scan_args(argc, argv, "21", &ch_list, &max_events, &timeout);
  if (!NIL_P(max_events)) {
    ev_len = FIX2INT(max_events);
  }

  if (!NIL_P(timeout)) {
    tv = rb_time_timeval(timeout);
    ts.tv_sec = (time_t)tv.tv_sec;
    ts.tv_nsec = (long)tv.tv_usec * 1000;
    pts = &ts;
  }

  if (!NIL_P(ch_list)) {
    Check_Type(ch_list, T_ARRAY);
    ch_len = RARRAY_LEN(ch_list);

    chl = alloca(sizeof(struct kevent) * ch_len);
    for (i = 0; i < ch_len; i++) {
      ev = RARRAY_AREF(ch_list, i);
      if (!rb_obj_is_kind_of(ev, cKqueue_Event)) {
        rb_raise(rb_eTypeError, "must be set Array of Event object");
      }

      chl[i].ident = FIX2INT(RSTRUCT_GET(ev, IDENT));
      chl[i].filter = FIX2INT(RSTRUCT_GET(ev, FILTER));
      chl[i].flags = FIX2UINT(RSTRUCT_GET(ev, FLAGS));
      chl[i].fflags = FIX2UINT(RSTRUCT_GET(ev, FFLAGS));
      chl[i].data = NUM2LONG(RSTRUCT_GET(ev, DATA));
      {
        VALUE fileno = RSTRUCT_GET(ev, IDENT);
        VALUE filter = RSTRUCT_GET(ev, FILTER);
        VALUE udata = RSTRUCT_GET(ev, UDATA);
        VALUE ivar = IVAR_GET(self);
        VALUE h = rb_hash_aref(ivar, fileno);
        if ((chl[i].flags & EV_DELETE) == EV_DELETE) {
          if (chl[i].flags & ~EV_DELETE) {
            rb_raise(rb_eArgError, "EV_DELETE cannot set with other");
          }
          if (NIL_P(h)) {
            rb_raise(rb_eArgError, "delete udata not found");
          }
          rb_hash_delete(h, filter);
          if (RHASH_EMPTY_P(h)) {
            rb_hash_delete(ivar, fileno);
          }
          udata = (VALUE)0;
        }
        else {
          if (NIL_P(h)) {
            h = rb_hash_aset(ivar, fileno, rb_hash_new());
          }
          rb_hash_aset(h, filter, udata);
        }
        IVAR_SET(self, ivar);
        chl[i].udata = (void*)udata;
      }
    }
  }

  if (0 < ev_len) {
    evl = alloca(sizeof(struct kevent) * ev_len);
  }
  else if (ev_len < 0) {
    rb_raise(rb_eArgError, "negative size");
  }

  args.fd = fptr->fd;
  args.chl = chl;
  args.ch_len = ch_len;
  args.evl = evl;
  args.ev_len = ev_len;
  args.ts = pts;

RETRY:
  ready = (int)(long)rb_thread_call_without_gvl(rb_kqueue_kevent_func, &args, RUBY_UBF_IO, 0);
  if (ready == -1) {
    if (errno == EINTR)
      goto RETRY;
    else
      rb_sys_fail("kevent");
  }

  ready_evlist = rb_ary_new_capa(ready);
  for (i = 0; i < ready; i++) {
    ev = rb_obj_alloc(cKqueue_Event);
    RSTRUCT_SET(ev, IDENT, INT2FIX(evl[i].ident));
    RSTRUCT_SET(ev, FILTER, INT2FIX(evl[i].filter));
    RSTRUCT_SET(ev, FLAGS, INT2FIX(evl[i].flags));
    RSTRUCT_SET(ev, FFLAGS, INT2FIX(evl[i].fflags));
    RSTRUCT_SET(ev, FLAGS, INT2FIX(evl[i].flags));
    RSTRUCT_SET(ev, DATA, INT2FIX(evl[i].data));
    RSTRUCT_SET(ev, UDATA, (VALUE)evl[i].udata);
    rb_ary_store(ready_evlist, i, ev);
  }
  return ready_evlist;
}