kqueue: modernize Struct usage for Ruby 2.5.0dev
[sleepy_penguin.git] / ext / sleepy_penguin / kqueue.c
blobe6c133f27c22ac7cc6346e7f1efcf99b926c14df
1 #include "sleepy_penguin.h"
2 #ifdef HAVE_SYS_EVENT_H
3 #include <sys/types.h>
4 #include <sys/event.h>
5 #include <sys/time.h>
6 #include <unistd.h>
7 #include <time.h>
8 #include "missing_clock_gettime.h"
9 #include "missing_rb_thread_fd_close.h"
10 #include "missing_rb_update_max_fd.h"
11 #include "value2timespec.h"
13 #ifdef HAVE_SYS_MOUNT_H /* for VQ_* flags on FreeBSD */
14 # include <sys/mount.h>
15 #endif
17 /* not bothering with overflow checking for backwards compat */
18 #ifndef RARRAY_LENINT
19 # define RARRAY_LENINT(ary) (int)RARRAY_LEN(ary)
20 #endif
21 #ifndef RARRAY_CONST_PTR
22 # define RARRAY_CONST_PTR(ary) RARRAY_PTR(ary)
23 #endif
24 #ifndef NUM2SHORT
25 # define NUM2SHORT(n) (short)NUM2INT(n)
26 #endif
27 #ifndef NUM2USHORT
28 # define NUM2USHORT(n) (short)NUM2UINT(n)
29 #endif
32 * Rubinius does not support RSTRUCT_* in the C API:
33 * ref: https://github.com/rubinius/rubinius/issues/494
35 #if defined(RUBINIUS)
36 # define RBX_STRUCT (1)
37 # define RSTRUCT_LEN(s) 0, rb_bug("RSTRUCT_LEN attempted in Rubinius")
38 # define RSTRUCT_PTR(s) NULL, rb_bug("RSTRUCT_PTR attempted in Rubinius")
39 #else
40 # define RBX_STRUCT (0)
41 #endif
43 static const long NANO_PER_SEC = 1000000000;
44 static ID id_for_fd;
45 static VALUE mEv, mEvFilt, mNote, mVQ;
47 struct kq_per_thread {
48 VALUE io;
49 VALUE changelist;
50 int fd;
51 int nchanges;
52 int nevents;
53 int capa;
54 struct timespec *ts;
55 struct kevent events[FLEX_ARRAY];
58 static void tssub(struct timespec *a, struct timespec *b, struct timespec *res)
60 res->tv_sec = a->tv_sec - b->tv_sec;
61 res->tv_nsec = a->tv_nsec - b->tv_nsec;
62 if (res->tv_nsec < 0) {
63 res->tv_sec--;
64 res->tv_nsec += NANO_PER_SEC;
68 /* this will raise if the IO is closed */
69 static int kq_fd_check(struct kq_per_thread *kpt)
71 int save_errno = errno;
73 kpt->fd = rb_sp_fileno(kpt->io);
74 errno = save_errno;
76 return 1;
79 static struct kq_per_thread *kpt_get(int nchanges, int nevents)
81 struct kq_per_thread *kpt;
82 size_t size;
83 int max = nchanges > nevents ? nchanges : nevents;
85 /* error check here to prevent OOM from posix_memalign */
86 if (max < 0) {
87 errno = EINVAL;
88 rb_sys_fail("kevent got negative events < 0");
91 size = sizeof(struct kq_per_thread) + sizeof(struct kevent) * max;
92 kpt = rb_sp_gettlsbuf(&size);
93 kpt->capa = max;
94 kpt->nchanges = nchanges;
95 kpt->nevents = nevents;
97 return kpt;
101 * call-seq:
102 * SleepyPenguin::Kqueue::IO.new -> Kqueue::IO object
104 * Creates a new Kqueue::IO object. This is a wrapper around the kqueue(2)
105 * system call which creates a Ruby IO object around the kqueue descriptor.
107 * kqueue descriptors are automatically invalidated by the OS across fork,
108 * so care must be taken when forking.
109 * Setting IO#autoclose=false is recommended for applications which fork
110 * after kqueue creation.
112 static VALUE s_new(VALUE klass)
114 VALUE rv;
115 int fd = kqueue();
116 int flags;
118 if (fd < 0) {
120 * ENOMEM/EMFILE/ENFILE are the only documented errors
121 * for kqueue(), hope GC can give us some space to retry:
123 rb_gc();
124 fd = kqueue();
125 if (fd < 0)
126 rb_sys_fail("kqueue");
129 flags = fcntl(fd, F_GETFD);
130 if (flags != -1)
131 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
133 rv = INT2FIX(fd);
135 return rb_call_super(1, &rv);
138 static void yield_kevent(struct kevent *event)
140 VALUE ident = ULONG2NUM((unsigned long)event->ident); /* uintptr_t */
141 VALUE filter = INT2NUM((int)event->filter); /* short */
142 VALUE flags = UINT2NUM((unsigned)event->flags); /* u_short */
143 VALUE fflags = UINT2NUM((unsigned)event->fflags); /* u_int */
144 VALUE data = LONG2NUM((long)event->data); /* intptr_t */
145 VALUE udata = (VALUE)event->udata; /* void * */
147 rb_yield_values(6, ident, filter, flags, fflags, data, udata);
150 static VALUE kevent_result(struct kq_per_thread *kpt, int nevents)
152 int i;
153 struct kevent *event = kpt->events;
155 if (nevents < 0) {
156 if (errno == EINTR)
157 nevents = 0;
158 else
159 rb_sys_fail("kevent");
162 for (i = nevents; --i >= 0; event++)
163 yield_kevent(event);
165 return INT2NUM(nevents);
169 * returns true if we were interrupted by a signal and resumable,
170 * updating the timeout timespec with the remaining time if needed.
172 static int
173 kevent_resume_p(struct timespec *expire_at, struct kq_per_thread *kpt)
175 struct timespec now;
177 kq_fd_check(kpt); /* may raise IOError */
179 if (errno != EINTR)
180 return 0;
183 * kevent is not interruptible until changes are sent,
184 * so if we got here, we already got our changes in
186 kpt->nchanges = 0;
188 /* we're waiting forever */
189 if (kpt->ts == NULL)
190 return 1;
192 clock_gettime(CLOCK_MONOTONIC, &now);
193 if (now.tv_sec > expire_at->tv_sec)
194 return 0;
195 if (now.tv_sec == expire_at->tv_sec && now.tv_nsec > expire_at->tv_nsec)
196 return 0;
198 tssub(expire_at, &now, kpt->ts);
199 return 1;
202 static VALUE nogvl_kevent(void *args)
204 struct kq_per_thread *kpt = args;
205 int nevents = kevent(kpt->fd, kpt->events, kpt->nchanges,
206 kpt->events, kpt->nevents, kpt->ts);
208 return (VALUE)nevents;
211 static void changelist_prepare(struct kevent *, VALUE);
213 static VALUE do_kevent(struct kq_per_thread *kpt)
215 long nevents;
216 struct timespec expire_at;
218 if (kpt->nchanges)
219 changelist_prepare(kpt->events, kpt->changelist);
221 if (kpt->ts) {
222 clock_gettime(CLOCK_MONOTONIC, &expire_at);
224 expire_at.tv_sec += kpt->ts->tv_sec;
225 expire_at.tv_nsec += kpt->ts->tv_nsec;
226 if (expire_at.tv_nsec > NANO_PER_SEC) {
227 expire_at.tv_sec++;
228 expire_at.tv_nsec -= NANO_PER_SEC;
232 do {
233 nevents = (long)rb_sp_fd_region(nogvl_kevent, kpt, kpt->fd);
234 } while (nevents < 0 && kevent_resume_p(&expire_at, kpt));
236 return kevent_result(kpt, (int)nevents);
239 #if defined(HAVE_RB_STRUCT_SIZE) && defined(RSTRUCT_GET)
240 static void ev_set_struct(struct kevent *ev, VALUE event)
242 if (rb_struct_size(event) == INT2NUM(6)) {
243 uintptr_t ident = (uintptr_t)NUM2ULONG(RSTRUCT_GET(event, 0));
244 short filter = NUM2SHORT(RSTRUCT_GET(event, 1));
245 unsigned short flags = NUM2USHORT(RSTRUCT_GET(event, 2));
246 unsigned fflags = (unsigned)NUM2UINT(RSTRUCT_GET(event, 3));
247 intptr_t data = (intptr_t)NUM2LONG(RSTRUCT_GET(event, 4));
248 void *udata = (void *)RSTRUCT_GET(event, 5);
250 EV_SET(ev, ident, filter, flags, fflags, data, udata);
251 } else {
252 rb_raise(rb_eTypeError, "unsupported struct in changelist");
255 #elif RBX_STRUCT == 0 && defined(RSTRUCT_LEN) && defined(RSTRUCT_PTR)
256 /* legacy MRI */
257 static void ev_set_struct(struct kevent *ev, VALUE event)
259 long len = RSTRUCT_LEN(*event);
260 if (len == 6) {
261 const VALUE *ptr = RSTRUCT_PTR(*event);
262 uintptr_t ident = (uintptr_t)NUM2ULONG(ptr[0]);
263 short filter = NUM2SHORT(ptr[1]);
264 unsigned short flags = NUM2USHORT(ptr[2]);
265 unsigned fflags = (unsigned)NUM2UINT(ptr[3]);
266 intptr_t data = (intptr_t)NUM2LONG(ptr[4]);
267 void *udata = (void *)ptr[5];
269 EV_SET(event, ident, filter, flags, fflags, data, udata);
270 } else {
271 rb_raise(rb_eTypeError, "unsupported struct in changelist");
274 #else
275 static void ev_set_struct(struct kevent *ev, VALUE event)
277 rb_raise(rb_eTypeError, "unsupported struct in changelist");
279 #endif
281 static void ev_set_ary(struct kevent *ev, VALUE event)
283 long len = RARRAY_LEN(event);
284 const VALUE *ptr = RARRAY_CONST_PTR(event);
286 if (len == 6) {
287 uintptr_t ident = (uintptr_t)NUM2ULONG(ptr[0]);
288 short filter = NUM2SHORT(ptr[1]);
289 unsigned short flags = NUM2USHORT(ptr[2]);
290 unsigned fflags = (unsigned)NUM2UINT(ptr[3]);
291 intptr_t data = (intptr_t)NUM2LONG(ptr[4]);
292 void *udata = (void *)ptr[5];
294 EV_SET(ev, ident, filter, flags, fflags, data, udata);
295 return;
297 rb_raise(rb_eTypeError,
298 "changelist must be an array of 6-element arrays or structs");
301 /* sets ptr and len */
302 static void unpack_event(struct kevent *ev, VALUE event)
304 switch (TYPE(event)) {
305 case T_STRUCT:
306 if (RBX_STRUCT) {
307 event = rb_funcall(event, rb_intern("to_a"), 0, 0);
308 /* fall-through to T_ARRAY */
309 } else {
310 ev_set_struct(ev, event);
311 return;
313 case T_ARRAY:
314 ev_set_ary(ev, event);
315 default:
316 rb_raise(rb_eTypeError, "unsupported type in changelist");
320 static void ary2eventlist(struct kevent *events, VALUE changelist)
322 const VALUE *chg = RARRAY_CONST_PTR(changelist);
323 long i = RARRAY_LEN(changelist);
325 for (; --i >= 0; chg++)
326 unpack_event(events++, *chg);
330 * Convert an Ruby representation of the changelist to "struct kevent"
332 static void changelist_prepare(struct kevent *events, VALUE changelist)
334 switch (TYPE(changelist)) {
335 case T_ARRAY:
336 ary2eventlist(events, changelist);
337 return;
338 case T_STRUCT: /* single event */
339 unpack_event(events, changelist);
340 return;
341 default:
342 rb_bug("changelist_prepare not type filtered by sp_kevent");
347 * call-seq:
348 * kq_io.kevent([changelist[, nevents[, timeout]]]) { |ident,filter,flags,fflags,data,udata| ... }
350 * This is a wrapper around the kevent(2) system call to change and/or
351 * retrieve events from the underlying kqueue descriptor.
353 * +changelist+ may be nil, a single Kevent struct or an array of Kevent
354 * structs. If +changelist+ is nil, no changes will be made to the
355 * underlying kqueue object.
357 * +nevents+ may be non-negative integer or nil. If +nevents+ is zero or
358 * nil, no events are retrieved. If +nevents+ is positive, a block must
359 * be passed to kevent for each event.
361 * +timeout+ is the numeric timeout in seconds to wait for +nevents+.
362 * If nil and +nevents+ is positive, kevent will sleep forever.
363 * +timeout+ may be in a floating point number if subsecond resolution
364 * is required. If +nevents+ is nil or zero and +timeout+ is not specified,
365 * +timeout+ is implied to be zero.
367 * If event retrieval is desired, a block taking 6-elements (one for each
368 * field of the kevent struct) must be passed.
370 static VALUE sp_kevent(int argc, VALUE *argv, VALUE self)
372 struct timespec ts, *t;
373 VALUE changelist, events, timeout;
374 struct kq_per_thread *kpt;
375 int nchanges, nevents;
377 rb_scan_args(argc, argv, "03", &changelist, &events, &timeout);
379 switch (TYPE(changelist)) {
380 case T_NIL: nchanges = 0; break;
381 case T_STRUCT: nchanges = 1; break;
382 case T_ARRAY: nchanges = RARRAY_LENINT(changelist); break;
383 default:
384 rb_raise(rb_eTypeError, "unhandled type for kevent changelist");
387 if (rb_block_given_p()) {
388 if (NIL_P(events))
389 rb_raise(rb_eArgError,
390 "block given but nevents not specified");
391 nevents = NUM2INT(events);
392 if (nevents < 0)
393 rb_raise(rb_eArgError, "nevents must be non-negative");
394 } else {
395 if (!NIL_P(events))
396 rb_raise(rb_eArgError,
397 "nevents specified but block not given");
398 nevents = 0;
401 t = NIL_P(timeout) ? NULL : value2timespec(&ts, timeout);
402 kpt = kpt_get(nchanges, nevents);
403 kpt->ts = t;
404 kpt->changelist = changelist;
405 kpt->io = self;
406 kpt->fd = rb_sp_fileno(kpt->io);
408 return rb_ensure(do_kevent, (VALUE)kpt, rb_sp_puttlsbuf, (VALUE)kpt);
411 /* initialize constants in the SleepyPenguin::Ev namespace */
412 static void init_ev(VALUE mSleepyPenguin)
415 * Document-module: SleepyPenguin::Ev
417 * Constants in the SleepyPenguin::Ev namespace are for the +flags+
418 * field in Kevent structs.
420 mEv = rb_define_module_under(mSleepyPenguin, "Ev");
422 /* See EV_ADD in the kevent(2) man page */
423 rb_define_const(mEv, "ADD", UINT2NUM(EV_ADD));
425 /* See EV_ENABLE in the kevent(2) man page */
426 rb_define_const(mEv, "ENABLE", UINT2NUM(EV_ENABLE));
428 /* See EV_DISABLE in the kevent(2) man page */
429 rb_define_const(mEv, "DISABLE", UINT2NUM(EV_DISABLE));
431 /* See EV_DISPATCH in the kevent(2) man page */
432 rb_define_const(mEv, "DISPATCH", UINT2NUM(EV_DISPATCH));
434 /* See EV_DELETE in the kevent(2) man page */
435 rb_define_const(mEv, "DELETE", UINT2NUM(EV_DELETE));
437 /* See EV_RECEIPT in the kevent(2) man page */
438 rb_define_const(mEv, "RECEIPT", UINT2NUM(EV_RECEIPT));
440 /* See EV_ONESHOT in the kevent(2) man page */
441 rb_define_const(mEv, "ONESHOT", UINT2NUM(EV_ONESHOT));
443 /* See EV_CLEAR in the kevent(2) man page */
444 rb_define_const(mEv, "CLEAR", UINT2NUM(EV_CLEAR));
446 /* See EV_EOF in the kevent(2) man page */
447 rb_define_const(mEv, "EOF", UINT2NUM(EV_EOF));
449 /* This is a return value in the proc passed to kevent */
450 rb_define_const(mEv, "ERROR", UINT2NUM(EV_ERROR));
453 /* initialize constants in the SleepyPenguin::EvFilt namespace */
454 static void init_evfilt(VALUE mSleepyPenguin)
457 * Document-module: SleepyPenguin::EvFilt
459 * Pre-defined system filters for Kqueue events. Not all filters
460 * are supported on all platforms. Consult the kevent(2) man page
461 * and source code for your operating system for more information.
463 mEvFilt = rb_define_module_under(mSleepyPenguin, "EvFilt");
465 /* See EVFILT_READ in the kevent(2) man page */
466 rb_define_const(mEvFilt, "READ", INT2NUM(EVFILT_READ));
468 /* See EVFILT_WRITE in the kevent(2) man page */
469 rb_define_const(mEvFilt, "WRITE", INT2NUM(EVFILT_WRITE));
472 * See EVFILT_AIO in the kevent(2) man page, not supported by libkqueue
474 rb_define_const(mEvFilt, "AIO", INT2NUM(EVFILT_AIO));
476 /* See EVFILT_VNODE in the kevent(2) man page */
477 rb_define_const(mEvFilt, "VNODE", INT2NUM(EVFILT_VNODE));
479 #ifdef EVFILT_PROC
480 /* Monitor process IDs, not supported by libkqueue */
481 rb_define_const(mEvFilt, "PROC", INT2NUM(EVFILT_PROC));
482 #endif
485 * Note: the use of EvFilt::SIGNAL is NOT supported in Ruby
486 * Ruby runtimes already manage all signal handling in the process,
487 * so attempting to manage them with a kqueue causes conflicts.
488 * We disable the Linux SignalFD interface for the same reason.
490 rb_define_const(mEvFilt, "SIGNAL", INT2NUM(EVFILT_SIGNAL));
492 /* See EVFILT_TIMER in the kevent(2) man page */
493 rb_define_const(mEvFilt, "TIMER", INT2NUM(EVFILT_TIMER));
495 #ifdef EVFILT_NETDEV
496 /* network devices, no longer supported */
497 rb_define_const(mEvFilt, "NETDEV", INT2NUM(EVFILT_NETDEV));
498 #endif
500 #ifdef EVFILT_FS
502 * See EVFILT_FS in the kevent(2) man page,
503 * not supported by libkqueue
505 rb_define_const(mEvFilt, "FS", INT2NUM(EVFILT_FS));
506 #endif
508 #ifdef EVFILT_LIO
509 /* attached to lio requests, not supported by libkqueue */
510 rb_define_const(mEvFilt, "LIO", INT2NUM(EVFILT_LIO));
511 #endif
513 /* see EVFILT_USER in the kevent(2) man page */
514 rb_define_const(mEvFilt, "USER", INT2NUM(EVFILT_USER));
517 /* initialize constants in the SleepyPenguin::Note namespace */
518 static void init_note(VALUE mSleepyPenguin)
521 * Document-module: SleepyPenguin::Note
523 * Data/hint flags/masks for EVFILT_USER and friends in Kqueue
524 * On input, the top two bits of fflags specifies how the lower
525 * twenty four bits should be applied to the stored value of fflags.
527 * On output, the top two bits will always be set to Note::FFNOP
528 * and the remaining twenty four bits will contain the stored
529 * fflags value.
531 mNote = rb_define_module_under(mSleepyPenguin, "Note");
533 /* ignore input fflags */
534 rb_define_const(mNote, "FFNOP", UINT2NUM(NOTE_FFNOP));
536 /* bitwise AND fflags */
537 rb_define_const(mNote, "FFAND", UINT2NUM(NOTE_FFAND));
539 /* bitwise OR fflags */
540 rb_define_const(mNote, "FFOR", UINT2NUM(NOTE_FFOR));
542 /* copy fflags */
543 rb_define_const(mNote, "FFCOPY", UINT2NUM(NOTE_FFCOPY));
545 /* control mask for fflags */
546 rb_define_const(mNote, "FFCTRLMASK", UINT2NUM(NOTE_FFCTRLMASK));
548 /* user-defined flag mask for fflags */
549 rb_define_const(mNote, "FFLAGSMASK", UINT2NUM(NOTE_FFLAGSMASK));
551 /* Cause the event to be triggered for output */
552 rb_define_const(mNote, "TRIGGER", UINT2NUM(NOTE_TRIGGER));
554 #ifdef NOTE_LOWAT
556 * data/hint flags for EVFILT_{READ|WRITE}, shared with userspace
557 * Not supported by libkqueue in Linux
559 rb_define_const(mNote, "LOWAT", UINT2NUM(NOTE_LOWAT));
560 #endif
562 #ifdef EVFILT_VNODE
563 /* vnode was removed */
564 rb_define_const(mNote, "DELETE", UINT2NUM(NOTE_DELETE));
566 /* vnode data contents changed */
567 rb_define_const(mNote, "WRITE", UINT2NUM(NOTE_WRITE));
569 /* vnode size increased */
570 rb_define_const(mNote, "EXTEND", UINT2NUM(NOTE_EXTEND));
572 /* vnode attributes changes */
573 rb_define_const(mNote, "ATTRIB", UINT2NUM(NOTE_ATTRIB));
575 /* vnode link count changed */
576 rb_define_const(mNote, "LINK", UINT2NUM(NOTE_LINK));
578 /* vnode was renamed */
579 rb_define_const(mNote, "RENAME", UINT2NUM(NOTE_RENAME));
581 # ifdef NOTE_REVOKE
582 /* vnode access was revoked, not supported on Linux */
583 rb_define_const(mNote, "REVOKE", UINT2NUM(NOTE_REVOKE));
584 # endif
585 #endif /* EVFILT_VNODE */
587 #ifdef EVFILT_PROC
588 /* process exited */
589 rb_define_const(mNote, "EXIT", UINT2NUM(NOTE_EXIT));
591 /* process forked */
592 rb_define_const(mNote, "FORK", UINT2NUM(NOTE_FORK));
594 /* process exec'd */
595 rb_define_const(mNote, "EXEC", UINT2NUM(NOTE_EXEC));
597 /* mask for hint bits */
598 rb_define_const(mNote, "PCTRLMASK", UINT2NUM(NOTE_PCTRLMASK));
600 /* mask for pid */
601 rb_define_const(mNote, "PDATAMASK", UINT2NUM(NOTE_PDATAMASK));
603 /* follow across forks */
604 rb_define_const(mNote, "TRACK", UINT2NUM(NOTE_TRACK));
606 /* could not track child */
607 rb_define_const(mNote, "TRACKERR", UINT2NUM(NOTE_TRACKERR));
609 /* am a child process */
610 rb_define_const(mNote, "CHILD", UINT2NUM(NOTE_CHILD));
611 #endif /* EVFILT_PROC */
613 #ifdef EVFILT_NETDEV
614 /* link is up */
615 rb_define_const(mNote, "LINKUP", UINT2NUM(NOTE_LINKUP));
617 /* link is down */
618 rb_define_const(mNote, "LINKDOWN", UINT2NUM(NOTE_LINKDOWN));
620 /* link state is valid */
621 rb_define_const(mNote, "LINKINV", UINT2NUM(NOTE_LINKINV));
622 #endif /* EVFILT_NETDEV */
625 static void init_vq(VALUE mSleepyPenguin)
627 #ifdef VQ_NOTRESP
629 * Document-module: SleepyPenguin::VQ
631 * Constants used by the EvFilt::FS filter in the Kqueue interfaces
633 mVQ = rb_define_module_under(mSleepyPenguin, "VQ");
635 /* server down */
636 rb_define_const(mVQ, "NOTRESP", UINT2NUM(VQ_NOTRESP));
638 /* server bad auth */
639 rb_define_const(mVQ, "NEEDAUTH", UINT2NUM(VQ_NEEDAUTH));
641 /* low on space */
642 rb_define_const(mVQ, "LOWDISK", UINT2NUM(VQ_LOWDISK));
644 /* new filesystem mounted */
645 rb_define_const(mVQ, "MOUNT", UINT2NUM(VQ_MOUNT));
647 /* filesystem unmounted */
648 rb_define_const(mVQ, "UNMOUNT", UINT2NUM(VQ_UNMOUNT));
650 /* filesystem dead, needs force unmount */
651 rb_define_const(mVQ, "DEAD", UINT2NUM(VQ_DEAD));
653 /* filesystem needs assistance from external program */
654 rb_define_const(mVQ, "ASSIST", UINT2NUM(VQ_ASSIST));
656 /* server lockd down */
657 rb_define_const(mVQ, "NOTRESPLOCK", UINT2NUM(VQ_NOTRESPLOCK));
658 #endif /* VQ_NOTRESP */
661 void sleepy_penguin_init_kqueue(void)
663 VALUE mSleepyPenguin, cKqueue, cKqueue_IO;
665 mSleepyPenguin = rb_define_module("SleepyPenguin");
666 init_ev(mSleepyPenguin);
667 init_evfilt(mSleepyPenguin);
668 init_note(mSleepyPenguin);
669 init_vq(mSleepyPenguin);
671 cKqueue = rb_define_class_under(mSleepyPenguin, "Kqueue", rb_cObject);
674 * Document-class: SleepyPenguin::Kqueue::IO
676 * Kqueue::IO is a low-level class. It does not provide fork nor
677 * GC-safety, so Ruby IO objects added via kevent must be retained
678 * by the application until IO#close is called.
680 * Warning: this class is easy to misuse, be careful as failure
681 * to preserve references objects passed as Kevent#udata may lead
682 * to crashes in Ruby. The high-level Kqueue class prevents these
683 * crashes (but may still return invalid objects).
685 cKqueue_IO = rb_define_class_under(cKqueue, "IO", rb_cIO);
686 rb_define_singleton_method(cKqueue_IO, "new", s_new, 0);
688 rb_define_method(cKqueue_IO, "kevent", sp_kevent, -1);
690 id_for_fd = rb_intern("for_fd");
693 * the high-level interface is implemented in Ruby
694 * see lib/sleepy_penguin/kevent.rb
697 #endif /* HAVE_SYS_EVENT_H */