ext/sleepy_penguin/kqueue.c in sleepy_penguin-3.5.0 vs ext/sleepy_penguin/kqueue.c in sleepy_penguin-3.5.1

- old
+ new

@@ -16,10 +16,13 @@ /* not bothering with overflow checking for backwards compat */ #ifndef RARRAY_LENINT # define RARRAY_LENINT(ary) (int)RARRAY_LEN(ary) #endif +#ifndef RARRAY_CONST_PTR +# define RARRAY_CONST_PTR(ary) RARRAY_PTR(ary) +#endif #ifndef NUM2SHORT # define NUM2SHORT(n) (short)NUM2INT(n) #endif #ifndef NUM2USHORT # define NUM2USHORT(n) (short)NUM2UINT(n) @@ -108,10 +111,11 @@ */ static VALUE s_new(VALUE klass) { VALUE rv; int fd = kqueue(); + int flags; if (fd < 0) { /* * ENOMEM/EMFILE/ENFILE are the only documented errors * for kqueue(), hope GC can give us some space to retry: @@ -120,13 +124,16 @@ fd = kqueue(); if (fd < 0) rb_sys_fail("kqueue"); } + flags = fcntl(fd, F_GETFD); + if (flags != -1) + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + rv = INT2FIX(fd); - /* This will set FD_CLOEXEC on Ruby 2.0.0+: */ return rb_call_super(1, &rv); } static void yield_kevent(struct kevent *event) { @@ -227,84 +234,110 @@ } while (nevents < 0 && kevent_resume_p(&expire_at, kpt)); return kevent_result(kpt, (int)nevents); } -static void event_set(struct kevent *event, VALUE *chg) +#if defined(HAVE_RB_STRUCT_SIZE) && defined(RSTRUCT_GET) +static void ev_set_struct(struct kevent *ev, VALUE event) { - uintptr_t ident = (uintptr_t)NUM2ULONG(chg[0]); - short filter = NUM2SHORT(chg[1]); - unsigned short flags = NUM2USHORT(chg[2]); - unsigned fflags = (unsigned)NUM2UINT(chg[3]); - intptr_t data = (intptr_t)NUM2LONG(chg[4]); - void *udata = (void *)chg[5]; + if (rb_struct_size(event) == INT2NUM(6)) { + uintptr_t ident = (uintptr_t)NUM2ULONG(RSTRUCT_GET(event, 0)); + short filter = NUM2SHORT(RSTRUCT_GET(event, 1)); + unsigned short flags = NUM2USHORT(RSTRUCT_GET(event, 2)); + unsigned fflags = (unsigned)NUM2UINT(RSTRUCT_GET(event, 3)); + intptr_t data = (intptr_t)NUM2LONG(RSTRUCT_GET(event, 4)); + void *udata = (void *)RSTRUCT_GET(event, 5); - EV_SET(event, ident, filter, flags, fflags, data, udata); + EV_SET(ev, ident, filter, flags, fflags, data, udata); + } else { + rb_raise(rb_eTypeError, "unsupported struct in changelist"); + } } +#elif RBX_STRUCT == 0 && defined(RSTRUCT_LEN) && defined(RSTRUCT_PTR) +/* legacy MRI */ +static void ev_set_struct(struct kevent *ev, VALUE event) +{ + long len = RSTRUCT_LEN(*event); + if (len == 6) { + const VALUE *ptr = RSTRUCT_PTR(*event); + uintptr_t ident = (uintptr_t)NUM2ULONG(ptr[0]); + short filter = NUM2SHORT(ptr[1]); + unsigned short flags = NUM2USHORT(ptr[2]); + unsigned fflags = (unsigned)NUM2UINT(ptr[3]); + intptr_t data = (intptr_t)NUM2LONG(ptr[4]); + void *udata = (void *)ptr[5]; + EV_SET(event, ident, filter, flags, fflags, data, udata); + } else { + rb_raise(rb_eTypeError, "unsupported struct in changelist"); + } +} +#else +static void ev_set_struct(struct kevent *ev, VALUE event) +{ + rb_raise(rb_eTypeError, "unsupported struct in changelist"); +} +#endif + +static void ev_set_ary(struct kevent *ev, VALUE event) +{ + long len = RARRAY_LEN(event); + const VALUE *ptr = RARRAY_CONST_PTR(event); + + if (len == 6) { + uintptr_t ident = (uintptr_t)NUM2ULONG(ptr[0]); + short filter = NUM2SHORT(ptr[1]); + unsigned short flags = NUM2USHORT(ptr[2]); + unsigned fflags = (unsigned)NUM2UINT(ptr[3]); + intptr_t data = (intptr_t)NUM2LONG(ptr[4]); + void *udata = (void *)ptr[5]; + + EV_SET(ev, ident, filter, flags, fflags, data, udata); + return; + } + rb_raise(rb_eTypeError, + "changelist must be an array of 6-element arrays or structs"); +} + /* sets ptr and len */ -static void unpack_event(VALUE **ptr, VALUE *len, VALUE *event) +static void unpack_event(struct kevent *ev, VALUE event) { - switch (TYPE(*event)) { + switch (TYPE(event)) { case T_STRUCT: if (RBX_STRUCT) { - *event = rb_funcall(*event, rb_intern("to_a"), 0, 0); + event = rb_funcall(event, rb_intern("to_a"), 0, 0); /* fall-through to T_ARRAY */ } else { - *len = RSTRUCT_LEN(*event); - *ptr = RSTRUCT_PTR(*event); + ev_set_struct(ev, event); return; } case T_ARRAY: - *len = RARRAY_LEN(*event); - *ptr = RARRAY_PTR(*event); - return; + ev_set_ary(ev, event); default: rb_raise(rb_eTypeError, "unsupported type in changelist"); } } static void ary2eventlist(struct kevent *events, VALUE changelist) { - VALUE *chg = RARRAY_PTR(changelist); + const VALUE *chg = RARRAY_CONST_PTR(changelist); long i = RARRAY_LEN(changelist); - VALUE event; - for (; --i >= 0; chg++) { - VALUE clen; - VALUE *cptr; - - event = *chg; - unpack_event(&cptr, &clen, &event); - if (clen != 6) - goto out_list; - event_set(events++, cptr); - } - return; -out_list: - rb_raise(rb_eTypeError, - "changelist must be an array of 6-element arrays or structs"); + for (; --i >= 0; chg++) + unpack_event(events++, *chg); } /* * Convert an Ruby representation of the changelist to "struct kevent" */ static void changelist_prepare(struct kevent *events, VALUE changelist) { - VALUE *cptr; - VALUE clen; - VALUE event; - switch (TYPE(changelist)) { case T_ARRAY: ary2eventlist(events, changelist); return; - case T_STRUCT: - event = changelist; - unpack_event(&cptr, &clen, &event); - if (clen != 6) - rb_raise(rb_eTypeError, "event is not a Kevent struct"); - event_set(events, cptr); + case T_STRUCT: /* single event */ + unpack_event(events, changelist); return; default: rb_bug("changelist_prepare not type filtered by sp_kevent"); } }