Set timeout for kevent call
[god.git] / ext / god / kqueue_handler.c
blob6211f90ff05de63f5550cf26d4391e849da63590
1 #if defined(__FreeBSD__) || defined(__APPLE__)
3 #include <ruby.h>
4 #include <sys/event.h>
5 #include <sys/time.h>
6 #include <errno.h>
8 static VALUE cKQueueHandler;
9 static VALUE cEventHandler;
10 static VALUE mGod;
12 static ID proc_exit;
13 static ID proc_fork;
14 static ID m_call;
15 static ID m_size;
16 static ID m_deregister;
18 static int kq;
20 #define NUM_EVENTS FIX2INT(rb_funcall(rb_cv_get(cEventHandler, "@@actions"), m_size, 0))
22 VALUE
23 kqh_event_mask(VALUE klass, VALUE sym)
25 ID id = SYM2ID(sym);
26 if (proc_exit == id) {
27 return UINT2NUM(NOTE_EXIT);
28 } else if (proc_fork == id) {
29 return UINT2NUM(NOTE_FORK);
30 } else {
31 rb_raise(rb_eNotImpError, "Event `%s` not implemented", rb_id2name(id));
33 return Qnil;
37 VALUE
38 kqh_monitor_process(VALUE klass, VALUE pid, VALUE mask)
40 struct kevent new_event;
41 ID event;
43 u_int fflags = NUM2UINT(mask);
45 EV_SET(&new_event, FIX2UINT(pid), EVFILT_PROC,
46 EV_ADD | EV_ENABLE, fflags, 0, 0);
48 if (-1 == kevent(kq, &new_event, 1, NULL, 0, NULL)) {
49 rb_raise(rb_eStandardError, strerror(errno));
52 return Qnil;
55 VALUE
56 kqh_handle_events()
58 int nevents, i, num_to_fetch = NUM_EVENTS;
59 struct kevent *events = (struct kevent*)malloc(num_to_fetch * sizeof(struct kevent));
60 struct timespec ts;
61 ts.tv_sec = 0;
62 ts.tv_nsec = 10000;
64 if (NULL == events) {
65 rb_raise(rb_eStandardError, strerror(errno));
68 nevents = kevent(kq, NULL, 0, events, num_to_fetch, &ts);
70 if (-1 == nevents) {
71 rb_raise(rb_eStandardError, strerror(errno));
72 } else {
73 for (i = 0; i < nevents; i++) {
74 if (events[i].fflags & NOTE_EXIT) {
75 rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_exit));
76 rb_funcall(cEventHandler, m_deregister, 1, INT2NUM(events[i].ident));
77 } else if (events[i].fflags & NOTE_FORK) {
78 rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_fork));
83 free(events);
85 return INT2FIX(nevents);
88 void
89 Init_kqueue_handler_ext()
91 kq = kqueue();
93 if (kq == -1) {
94 rb_raise(rb_eStandardError, "kqueue initilization failed");
97 proc_exit = rb_intern("proc_exit");
98 proc_fork = rb_intern("proc_fork");
99 m_call = rb_intern("call");
100 m_size = rb_intern("size");
101 m_deregister = rb_intern("deregister");
103 mGod = rb_const_get(rb_cObject, rb_intern("God"));
104 cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
105 cKQueueHandler = rb_define_class_under(mGod, "KQueueHandler", rb_cObject);
106 rb_define_singleton_method(cKQueueHandler, "monitor_process", kqh_monitor_process, 2);
107 rb_define_singleton_method(cKQueueHandler, "handle_events", kqh_handle_events, 0);
108 rb_define_singleton_method(cKQueueHandler, "event_mask", kqh_event_mask, 1);
111 #endif