Add extension to gem package
[god.git] / ext / kqueue_handler / kqueue_handler.c
blob0e9875ef66454d37aa1c01d659c86ed0ebb44e73
1 #include <ruby.h>
2 #include <sys/event.h>
3 #include <sys/time.h>
4 #include <errno.h>
6 VALUE cKQueueHandler;
7 VALUE cEventHandler;
8 VALUE mGod;
10 static ID proc_exit;
11 static ID call;
12 static int kq;
13 static int num_events;
15 VALUE
16 kqh_register_event(VALUE klass, VALUE pid, VALUE event)
18 struct kevent new_event;
19 VALUE rb_event;
20 u_int fflags;
22 if (proc_exit == SYM2ID(event)) {
23 fflags = NOTE_EXIT;
24 } else {
25 rb_raise(rb_eNotImpError, "Event `%s` not implemented", rb_id2name(event));
28 EV_SET(&new_event, FIX2UINT(pid), EVFILT_PROC,
29 EV_ADD | EV_ENABLE, fflags, 0, 0);
31 if (-1 == kevent(kq, &new_event, 1, NULL, 0, NULL)) {
32 rb_raise(rb_eStandardError, strerror(errno));
35 num_events++;
36 return Qnil;
39 VALUE
40 kqh_handle_events()
42 int nevents, i;
43 struct kevent *events = (struct kevent*)malloc(num_events * sizeof(struct kevent));
45 if (NULL == events)
46 rb_raise(rb_eStandardError, strerror(errno));
48 nevents = kevent(kq, NULL, 0, events, num_events, NULL);
50 if (-1 == nevents) {
51 rb_raise(rb_eStandardError, strerror(errno));
52 } else {
53 for (i = 0; i < nevents; i++) {
54 if (events[i].fflags & NOTE_EXIT) {
55 rb_funcall(cEventHandler, call, 1, INT2NUM(events[i].ident));
60 free(events);
62 return INT2FIX(nevents);
65 void Init_kqueue_handler() {
66 kq = kqueue();
68 if (kq == -1)
69 rb_raise(rb_eStandardError, "kqueue initilization failed");
71 proc_exit = rb_intern("proc_exit");
72 call = rb_intern("call");
74 mGod = rb_const_get(rb_cObject, rb_intern("God"));
75 cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
76 cKQueueHandler = rb_define_class_under(mGod, "KQueueHandler", rb_cObject);
77 rb_define_singleton_method(cKQueueHandler, "register_event", kqh_register_event, 2);
78 rb_define_singleton_method(cKQueueHandler, "handle_events", kqh_handle_events, 0);