1 #ifdef HAVE_SYS_TIMERFD_H
2 #include "sleepy_penguin.h"
3 #include <sys/timerfd.h>
4 #include "value2timespec.h"
7 static VALUE
create(int argc
, VALUE
*argv
, VALUE klass
)
10 int clockid
, flags
= 0;
13 rb_scan_args(argc
, argv
, "02", &cid
, &fl
);
14 clockid
= NIL_P(cid
) ? CLOCK_MONOTONIC
: NUM2INT(cid
);
15 flags
= NIL_P(fl
) ? 0 : NUM2INT(fl
);
17 fd
= timerfd_create(clockid
, flags
);
19 if (errno
== EMFILE
|| errno
== ENFILE
|| errno
== ENOMEM
) {
21 fd
= timerfd_create(clockid
, flags
);
24 rb_sys_fail("timerfd_create");
27 return rb_funcall(klass
, id_for_fd
, 1, INT2NUM(fd
));
30 static VALUE
itimerspec2ary(struct itimerspec
*its
)
32 VALUE interval
= timespec2num(&its
->it_interval
);
33 VALUE value
= timespec2num(&its
->it_value
);
35 return rb_ary_new3(2, interval
, value
);
38 static VALUE
settime(VALUE self
, VALUE fl
, VALUE interval
, VALUE value
)
40 int fd
= my_fileno(self
);
41 int flags
= NUM2INT(fl
);
42 struct itimerspec old
, new;
44 value2timespec(&new.it_interval
, interval
);
45 value2timespec(&new.it_value
, value
);
47 if (timerfd_settime(fd
, flags
, &new, &old
) == -1)
48 rb_sys_fail("timerfd_settime");
50 return itimerspec2ary(&old
);
53 static VALUE
gettime(VALUE self
)
55 int fd
= my_fileno(self
);
56 struct itimerspec curr
;
58 if (timerfd_gettime(fd
, &curr
) == -1)
59 rb_sys_fail("timerfd_gettime");
61 return itimerspec2ary(&curr
);
64 #ifdef HAVE_RB_THREAD_BLOCKING_REGION
65 static VALUE
tfd_read(void *args
)
69 ssize_t r
= read(fd
, buf
, sizeof(uint64_t));
74 static VALUE
expirations(VALUE self
)
77 uint64_t buf
= (int)my_fileno(self
);
79 r
= (VALUE
)rb_thread_blocking_region(tfd_read
, &buf
, RUBY_UBF_IO
, 0);
81 rb_sys_fail("read(timerfd)");
85 #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
87 static VALUE
expirations(VALUE self
)
89 int fd
= my_fileno(self
);
95 r
= read(fd
, &buf
, sizeof(uint64_t));
97 if (rb_io_wait_readable(fd
))
99 rb_sys_fail("read(timerfd)");
106 void sleepy_penguin_init_timerfd(void)
108 VALUE mSleepyPenguin
, cTimerFD
;
110 mSleepyPenguin
= rb_define_module("SleepyPenguin");
111 cTimerFD
= rb_define_class_under(mSleepyPenguin
, "TimerFD", rb_cIO
);
112 rb_define_singleton_method(cTimerFD
, "create", create
, -1);
113 rb_define_singleton_method(cTimerFD
, "new", create
, -1);
114 rb_define_const(cTimerFD
, "REALTIME", UINT2NUM(CLOCK_REALTIME
));
115 rb_define_const(cTimerFD
, "MONOTONIC", UINT2NUM(CLOCK_MONOTONIC
));
116 rb_define_const(cTimerFD
, "ABSTIME", UINT2NUM(TFD_TIMER_ABSTIME
));
118 rb_define_const(cTimerFD
, "NONBLOCK", UINT2NUM(TFD_NONBLOCK
));
121 rb_define_const(cTimerFD
, "CLOEXEC", UINT2NUM(TFD_CLOEXEC
));
124 rb_define_method(cTimerFD
, "settime", settime
, 3);
125 rb_define_method(cTimerFD
, "expirations", expirations
, 0);
126 id_for_fd
= rb_intern("for_fd");
128 #endif /* HAVE_SYS_TIMERFD_H */