sleepy_penguin 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 */