minor doc updates, use wrongdoc
[sleepy_penguin.git] / ext / sleepy_penguin / timerfd.c
blobff717cf398a3d2e8b44ba1b2c642a1ab31695852
1 #ifdef HAVE_SYS_TIMERFD_H
2 #include "sleepy_penguin.h"
3 #include <sys/timerfd.h>
4 #include "value2timespec.h"
5 static ID id_for_fd;
7 static VALUE create(int argc, VALUE *argv, VALUE klass)
9 VALUE cid, fl;
10 int clockid, flags = 0;
11 int fd;
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);
18 if (fd == -1) {
19 if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
20 rb_gc();
21 fd = timerfd_create(clockid, flags);
23 if (fd == -1)
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)
67 uint64_t *buf = args;
68 int fd = (int)(*buf);
69 ssize_t r = read(fd, buf, sizeof(uint64_t));
71 return (VALUE)r;
74 static VALUE expirations(VALUE self)
76 ssize_t r;
77 uint64_t buf = (int)my_fileno(self);
79 r = (VALUE)rb_thread_blocking_region(tfd_read, &buf, RUBY_UBF_IO, 0);
80 if (r == -1)
81 rb_sys_fail("read(timerfd)");
83 return ULL2NUM(buf);
85 #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
86 #include "nonblock.h"
87 static VALUE expirations(VALUE self)
89 int fd = my_fileno(self);
90 uint64_t buf;
91 ssize_t r;
93 set_nonblock(fd);
94 retry:
95 r = read(fd, &buf, sizeof(uint64_t));
96 if (r == -1) {
97 if (rb_io_wait_readable(fd))
98 goto retry;
99 rb_sys_fail("read(timerfd)");
102 return ULL2NUM(buf);
104 #endif
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));
117 #ifdef TFD_NONBLOCK
118 rb_define_const(cTimerFD, "NONBLOCK", UINT2NUM(TFD_NONBLOCK));
119 #endif
120 #ifdef TFD_CLOEXEC
121 rb_define_const(cTimerFD, "CLOEXEC", UINT2NUM(TFD_CLOEXEC));
122 #endif
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 */