sleepy_penguin 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,30 @@
1
+ #ifndef EPOLL_CLOEXEC
2
+ # define EPOLL_CLOEXEC (int)(02000000)
3
+ #endif
4
+
5
+ #ifndef HAVE_EPOLL_CREATE1
6
+ /*
7
+ * fake epoll_create1() since some systems don't have it.
8
+ * Don't worry about thread-safety since current Ruby 1.9 won't
9
+ * call this without GVL.
10
+ */
11
+ static int my_epoll_create1(int flags)
12
+ {
13
+ int fd = epoll_create(1024); /* size ignored since 2.6.8 */
14
+
15
+ if (fd < 0 || flags == 0)
16
+ return fd;
17
+
18
+ if ((flags & EPOLL_CLOEXEC) && (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1))
19
+ goto err;
20
+ return fd;
21
+ err:
22
+ {
23
+ int saved_errno = errno;
24
+ close(fd);
25
+ errno = saved_errno;
26
+ return -1;
27
+ }
28
+ }
29
+ # define epoll_create1 my_epoll_create1
30
+ #endif
@@ -0,0 +1,57 @@
1
+ #ifndef IN_CLOEXEC
2
+ # define IN_CLOEXEC 02000000
3
+ #endif
4
+ #ifndef IN_NONBLOCK
5
+ # define IN_NONBLOCK O_NONBLOCK
6
+ #endif
7
+ #ifndef IN_ATTRIB
8
+ # define IN_ATTRIB 0x00000004
9
+ #endif
10
+ #ifndef IN_ONLYDIR
11
+ # define IN_ONLYDIR 0x01000000
12
+ #endif
13
+ #ifndef IN_DONT_FOLLOW
14
+ # define IN_DONT_FOLLOW 0x02000000
15
+ #endif
16
+ #ifndef IN_EXCL_UNLINK
17
+ # define IN_EXCL_UNLINK 0x04000000
18
+ #endif
19
+ #ifndef IN_MASK_ADD
20
+ # define IN_MASK_ADD 0x20000000
21
+ #endif
22
+ #ifndef IN_ONESHOT
23
+ # define IN_ONESHOT 0x80000000
24
+ #endif
25
+
26
+ #ifndef HAVE_INOTIFY_INIT1
27
+ /*
28
+ * fake inotify_init1() since some systems don't have it
29
+ * Don't worry about thread-safety since current Ruby 1.9 won't
30
+ * call this without GVL.
31
+ */
32
+ static int my_inotify_init1(int flags)
33
+ {
34
+ int fd = inotify_init();
35
+ int tmp;
36
+
37
+ if (fd < 0)
38
+ return fd;
39
+ if ((flags & IN_CLOEXEC) && (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1))
40
+ goto fcntl_err;
41
+ if (flags & IN_NONBLOCK) {
42
+ tmp = fcntl(fd, F_GETFL);
43
+ if (tmp == -1)
44
+ goto fcntl_err;
45
+ if ((fcntl(fd, F_SETFL, tmp | O_NONBLOCK) != 0))
46
+ goto fcntl_err;
47
+ }
48
+
49
+ return fd;
50
+ fcntl_err:
51
+ tmp = errno;
52
+ close(fd);
53
+ errno = tmp;
54
+ rb_sys_fail("fcntl");
55
+ }
56
+ # define inotify_init1 my_inotify_init1
57
+ #endif /* HAVE_INOTIFY_INIT1 */
@@ -0,0 +1,335 @@
1
+ #ifdef HAVE_SYS_SIGNALFD_H
2
+ #include "sleepy_penguin.h"
3
+ #include <signal.h>
4
+ #include <sys/signalfd.h>
5
+ static ID id_for_fd, id_list;
6
+ static VALUE ssi_members;
7
+ static VALUE cSigInfo;
8
+
9
+ /* converts a Symbol, String, or Fixnum to an integer signal */
10
+ static int sig2int(VALUE sig)
11
+ {
12
+ static VALUE list;
13
+ const char *ptr;
14
+ long len;
15
+
16
+ if (TYPE(sig) == T_FIXNUM)
17
+ return FIX2INT(sig);
18
+
19
+ sig = rb_obj_as_string(sig);
20
+ len = RSTRING_LEN(sig);
21
+ ptr = RSTRING_PTR(sig);
22
+
23
+ if (len > 3 && !memcmp("SIG", ptr, 3))
24
+ sig = rb_str_new(ptr + 3, len - 3);
25
+
26
+ if (!list) {
27
+ VALUE tmp = rb_const_get(rb_cObject, rb_intern("Signal"));
28
+
29
+ list = rb_funcall(tmp, rb_intern("list"), 0, 0);
30
+ rb_global_variable(&list);
31
+ }
32
+
33
+ sig = rb_hash_aref(list, sig);
34
+ if (NIL_P(sig))
35
+ rb_raise(rb_eArgError, "invalid signal: %s", ptr);
36
+
37
+ return NUM2INT(sig);
38
+ }
39
+
40
+ /* fills sigset_t with an Array of signals */
41
+ static void value2sigset(sigset_t *mask, VALUE set)
42
+ {
43
+ sigemptyset(mask);
44
+
45
+ switch (TYPE(set)) {
46
+ case T_NIL: return;
47
+ case T_ARRAY: {
48
+ VALUE *ptr = RARRAY_PTR(set);
49
+ long len = RARRAY_LEN(set);
50
+
51
+ while (--len >= 0)
52
+ sigaddset(mask, sig2int(*ptr++));
53
+ }
54
+ break;
55
+ default:
56
+ sigaddset(mask, sig2int(set));
57
+ }
58
+ }
59
+
60
+ static int cur_flags(int fd)
61
+ {
62
+ int rv = 0;
63
+ #ifdef SFD_CLOEXEC
64
+ {
65
+ int flags = fcntl(fd, F_GETFD);
66
+ if (flags == -1) rb_sys_fail("fcntl(F_GETFD)");
67
+ if (flags & FD_CLOEXEC) rv |= SFD_CLOEXEC;
68
+ }
69
+ #endif
70
+ #ifdef SFD_NONBLOCK
71
+ {
72
+ int flags = fcntl(fd, F_GETFL);
73
+ if (flags == -1) rb_sys_fail("fcntl(F_GETFL)");
74
+ if (flags & O_NONBLOCK) rv |= SFD_NONBLOCK;
75
+ }
76
+ #endif
77
+ return rv;
78
+ }
79
+
80
+ /*
81
+ * call-seq:
82
+ * sfd.update!(signals[, flags]) -> sfd
83
+ *
84
+ * Updates the signal mask watched for by the given +sfd+.
85
+ * Takes the same arguments as SignalFD.new.
86
+ */
87
+ static VALUE update_bang(int argc, VALUE *argv, VALUE self)
88
+ {
89
+ VALUE vmask, vflags;
90
+ sigset_t mask;
91
+ int flags;
92
+ int fd = rb_sp_fileno(self);
93
+ int rc;
94
+
95
+ rb_scan_args(argc, argv, "02", &vmask, &vflags);
96
+ flags = NIL_P(vflags) ? cur_flags(fd) : rb_sp_get_flags(self, vflags);
97
+ value2sigset(&mask, vmask);
98
+
99
+ rc = signalfd(fd, &mask, flags);
100
+ if (rc == -1)
101
+ rb_sys_fail("signalfd");
102
+ return self;
103
+ }
104
+
105
+ /*
106
+ * call-seq:
107
+ * SignalFD.new(signals[, flags]) -> SignalFD IO object
108
+ *
109
+ * Creates a new SignalFD object to watch given +signals+ with +flags+.
110
+ *
111
+ * +signals+ is an Array of signal names or a single signal name that
112
+ * Signal.trap understands:
113
+ *
114
+ * signals = [ :USR1, "USR2" ]
115
+ * signals = :USR1
116
+ * signals = 15
117
+ *
118
+ * Starting with Linux 2.6.27, +flags+ may be a mask that consists of any
119
+ * of the following:
120
+ *
121
+ * - :CLOEXEC - set the close-on-exec flag on the new object
122
+ * - :NONBLOCK - set the non-blocking I/O flag on the new object
123
+ */
124
+ static VALUE s_new(int argc, VALUE *argv, VALUE klass)
125
+ {
126
+ VALUE vmask, vflags;
127
+ sigset_t mask;
128
+ int flags;
129
+ int fd;
130
+
131
+ rb_scan_args(argc, argv, "02", &vmask, &vflags);
132
+ flags = rb_sp_get_flags(klass, vflags);
133
+ value2sigset(&mask, vmask);
134
+
135
+ fd = signalfd(-1, &mask, flags);
136
+ if (fd == -1) {
137
+ if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
138
+ rb_gc();
139
+ fd = signalfd(-1, &mask, flags);
140
+ }
141
+ if (fd == -1)
142
+ rb_sys_fail("signalfd");
143
+ }
144
+
145
+ return rb_funcall(klass, id_for_fd, 1, INT2NUM(fd));
146
+ }
147
+
148
+ static VALUE ssi_alloc(VALUE klass)
149
+ {
150
+ struct signalfd_siginfo *ssi = ALLOC(struct signalfd_siginfo);
151
+
152
+ return Data_Wrap_Struct(klass, NULL, -1, ssi);
153
+ }
154
+
155
+ /* :nodoc: */
156
+ static VALUE ssi_init(VALUE self)
157
+ {
158
+ struct signalfd_siginfo *ssi = DATA_PTR(self);
159
+
160
+ memset(ssi, 0, sizeof(struct signalfd_siginfo));
161
+ return self;
162
+ }
163
+
164
+ static VALUE sfd_read(void *args)
165
+ {
166
+ struct signalfd_siginfo *ssi = args;
167
+ int fd = ssi->ssi_fd;
168
+ ssize_t r = read(fd, ssi, sizeof(struct signalfd_siginfo));
169
+
170
+ return (VALUE)r;
171
+ }
172
+
173
+ /*
174
+ * call-seq:
175
+ * sfd.take([nonblock]) -> SignalFD::SigInfo object or +nil+
176
+ *
177
+ * Returns the next SigInfo object representing a received signal.
178
+ * If +nonblock+ is specified and true, this may return +nil+
179
+ */
180
+ static VALUE sfd_take(int argc, VALUE *argv, VALUE self)
181
+ {
182
+ VALUE rv = ssi_alloc(cSigInfo);
183
+ struct signalfd_siginfo *ssi = DATA_PTR(rv);
184
+ ssize_t r;
185
+ int fd;
186
+ VALUE nonblock;
187
+
188
+ rb_scan_args(argc, argv, "01", &nonblock);
189
+ fd = rb_sp_fileno(self);
190
+ if (RTEST(nonblock))
191
+ rb_sp_set_nonblock(fd);
192
+ else
193
+ blocking_io_prepare(fd);
194
+ retry:
195
+ ssi->ssi_fd = fd;
196
+ r = (ssize_t)rb_sp_io_region(sfd_read, ssi);
197
+ if (r == -1) {
198
+ if (errno == EAGAIN && RTEST(nonblock))
199
+ return Qnil;
200
+ if (rb_io_wait_readable(fd))
201
+ goto retry;
202
+ rb_sys_fail("read(signalfd)");
203
+ }
204
+ if (r == 0)
205
+ rb_eof_error(); /* does this ever happen? */
206
+ return rv;
207
+ }
208
+
209
+ #define SSI_READER_FUNC(FN, FIELD) \
210
+ static VALUE ssi_##FIELD(VALUE self) { \
211
+ struct signalfd_siginfo *ssi = DATA_PTR(self); \
212
+ return FN(ssi->ssi_##FIELD); \
213
+ }
214
+
215
+ SSI_READER_FUNC(UINT2NUM,signo)
216
+ SSI_READER_FUNC(INT2NUM,errno)
217
+ SSI_READER_FUNC(INT2NUM,code)
218
+ SSI_READER_FUNC(UINT2NUM,pid)
219
+ SSI_READER_FUNC(UINT2NUM,uid)
220
+ SSI_READER_FUNC(INT2NUM,fd)
221
+ SSI_READER_FUNC(UINT2NUM,tid)
222
+ SSI_READER_FUNC(UINT2NUM,band)
223
+ SSI_READER_FUNC(UINT2NUM,overrun)
224
+ SSI_READER_FUNC(UINT2NUM,trapno)
225
+ SSI_READER_FUNC(INT2NUM,status)
226
+ SSI_READER_FUNC(INT2NUM,int)
227
+ SSI_READER_FUNC(ULL2NUM,ptr)
228
+ SSI_READER_FUNC(ULL2NUM,utime)
229
+ SSI_READER_FUNC(ULL2NUM,stime)
230
+ SSI_READER_FUNC(ULL2NUM,addr)
231
+
232
+ void sleepy_penguin_init_signalfd(void)
233
+ {
234
+ VALUE mSleepyPenguin, cSignalFD;
235
+
236
+ mSleepyPenguin = rb_define_module("SleepyPenguin");
237
+
238
+ /*
239
+ * Document-class: SleepyPenguin::SignalFD
240
+ *
241
+ * A SignalFD is an IO object for accepting signals. It provides
242
+ * an alternative to Signal.trap that may be monitored using
243
+ * IO.select or Epoll.
244
+ *
245
+ * SignalFD appears interact unpredictably with YARV (Ruby 1.9) signal
246
+ * handling and has been unreliable in our testing. Since Ruby has a
247
+ * decent signal handling interface anyways, this class is less useful
248
+ * than signalfd() in a C-only environment.
249
+ *
250
+ * It is not supported at all under (Matz) Ruby 1.8.
251
+ */
252
+ cSignalFD = rb_define_class_under(mSleepyPenguin, "SignalFD", rb_cIO);
253
+
254
+ /*
255
+ * Document-class: SleepyPenguin::SignalFD::SigInfo
256
+ *
257
+ * This class is returned by SignalFD#take. It consists of the
258
+ * following read-only members:
259
+ *
260
+ * - signo - signal number
261
+ * - errno - error number
262
+ * - code - signal code
263
+ * - pid - PID of sender
264
+ * - uid - real UID of sender
265
+ * - fd - file descriptor (SIGIO)
266
+ * - tid - kernel timer ID (POSIX timers)
267
+ * - band - band event (SIGIO)
268
+ * - overrun - POSIX timer overrun count
269
+ * - trapno - trap number that caused hardware-generated signal
270
+ * - exit status or signal (SIGCHLD)
271
+ * - int - integer sent by sigqueue(2)
272
+ * - ptr - Pointer sent by sigqueue(2)
273
+ * - utime - User CPU time consumed (SIGCHLD)
274
+ * - stime - System CPU time consumed (SIGCHLD)
275
+ * - addr - address that generated a hardware-generated signal
276
+ */
277
+ cSigInfo = rb_define_class_under(cSignalFD, "SigInfo", rb_cObject);
278
+ rb_define_alloc_func(cSigInfo, ssi_alloc);
279
+ rb_define_private_method(cSigInfo, "initialize", ssi_init, 0);
280
+
281
+ /* TODO: si_code values */
282
+
283
+ rb_define_singleton_method(cSignalFD, "new", s_new, -1);
284
+ #ifdef SFD_NONBLOCK
285
+ NODOC_CONST(cSignalFD, "NONBLOCK", INT2NUM(SFD_NONBLOCK));
286
+ #endif
287
+ #ifdef SFD_CLOEXEC
288
+ NODOC_CONST(cSignalFD, "CLOEXEC", INT2NUM(SFD_CLOEXEC));
289
+ #endif
290
+
291
+ rb_define_method(cSignalFD, "take", sfd_take, -1);
292
+ rb_define_method(cSignalFD, "update!", update_bang, -1);
293
+ id_for_fd = rb_intern("for_fd");
294
+ ssi_members = rb_ary_new();
295
+
296
+ NODOC_CONST(cSigInfo, "MEMBERS", ssi_members);
297
+
298
+ /*
299
+ * the minimum signal number for real-time signals,
300
+ * 34 on NPTL-based systems
301
+ */
302
+ rb_define_const(cSignalFD, "RTMIN", INT2NUM(SIGRTMIN));
303
+
304
+ /*
305
+ * the maximum signal number for real-time signals,
306
+ * 64 on NPTL-based systems
307
+ */
308
+ rb_define_const(cSignalFD, "RTMAX", INT2NUM(SIGRTMAX));
309
+
310
+ #define SSI_READER(FIELD) do { \
311
+ rb_define_method(cSigInfo, #FIELD, ssi_##FIELD, 0); \
312
+ rb_ary_push(ssi_members, ID2SYM(rb_intern(#FIELD))); \
313
+ } while (0)
314
+
315
+ SSI_READER(signo);
316
+ SSI_READER(errno);
317
+ SSI_READER(code);
318
+ SSI_READER(pid);
319
+ SSI_READER(uid);
320
+ SSI_READER(fd);
321
+ SSI_READER(tid);
322
+ SSI_READER(band);
323
+ SSI_READER(overrun);
324
+ SSI_READER(trapno);
325
+ SSI_READER(status);
326
+ SSI_READER(int);
327
+ SSI_READER(ptr);
328
+ SSI_READER(utime);
329
+ SSI_READER(stime);
330
+ SSI_READER(addr);
331
+ rb_obj_freeze(ssi_members);
332
+
333
+ rb_require("sleepy_penguin/signalfd/sig_info");
334
+ }
335
+ #endif /* HAVE_SYS_SIGNALFD_H */
@@ -12,64 +12,24 @@
12
12
  #include <assert.h>
13
13
  #include <unistd.h>
14
14
 
15
- #if ! HAVE_RB_IO_T
16
- # define rb_io_t OpenFile
17
- #endif
18
-
19
- #ifdef GetReadFile
20
- # define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
21
- #else
22
- # if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
23
- # define FPTR_TO_FD(fptr) fileno(fptr->f)
24
- # else
25
- # define FPTR_TO_FD(fptr) fptr->fd
26
- # endif
27
- #endif
28
-
29
- static int fixint_closed_p(VALUE io)
15
+ unsigned rb_sp_get_uflags(VALUE klass, VALUE flags);
16
+ int rb_sp_get_flags(VALUE klass, VALUE flags);
17
+ int rb_sp_io_closed(VALUE io);
18
+ int rb_sp_fileno(VALUE io);
19
+ void rb_sp_set_nonblock(int fd);
20
+
21
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
22
+ static inline VALUE rb_sp_io_region(rb_blocking_function_t *func, void *data)
30
23
  {
31
- return (fcntl(FIX2INT(io), F_GETFD) == -1 && errno == EBADF);
32
- }
33
-
34
- #if defined(RFILE) && defined(HAVE_ST_FD)
35
- static int my_rb_io_closed(VALUE io)
36
- {
37
- return RFILE(io)->fptr->fd < 0;
24
+ return rb_thread_blocking_region(func, data, RUBY_UBF_IO, 0);
38
25
  }
26
+ # define blocking_io_prepare(fd) ((void)(fd))
39
27
  #else
40
- static int my_rb_io_closed(VALUE io)
41
- {
42
- return rb_funcall(io, rb_intern("closed?"), 0) == Qtrue;
43
- }
28
+ typedef VALUE rb_blocking_function_t(void *);
29
+ VALUE rb_sp_io_region(rb_blocking_function_t *func, void *data);
30
+ # define blocking_io_prepare(fd) rb_sp_set_nonblock((fd))
44
31
  #endif
45
32
 
46
- static int my_io_closed(VALUE io)
47
- {
48
- switch (TYPE(io)) {
49
- case T_FIXNUM:
50
- return fixint_closed_p(io);
51
- case T_FILE:
52
- break;
53
- default:
54
- io = rb_convert_type(io, T_FILE, "IO", "to_io");
55
- }
56
-
57
- return my_rb_io_closed(io);
58
- }
59
-
60
- static int my_fileno(VALUE io)
61
- {
62
- rb_io_t *fptr;
63
-
64
- switch (TYPE(io)) {
65
- case T_FIXNUM: return FIX2INT(io);
66
- case T_FILE:
67
- GetOpenFile(io, fptr);
68
- return FPTR_TO_FD(fptr);
69
- }
70
- io = rb_convert_type(io, T_FILE, "IO", "to_io");
71
- GetOpenFile(io, fptr);
72
- return FPTR_TO_FD(fptr);
73
- }
74
-
33
+ #define NODOC_CONST(klass,name,value) \
34
+ rb_define_const((klass),(name),(value))
75
35
  #endif /* SLEEPY_PENGUIN_H */