sleepy_penguin 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.manifest CHANGED
@@ -17,6 +17,7 @@ ext/sleepy_penguin/epoll.c
17
17
  ext/sleepy_penguin/eventfd.c
18
18
  ext/sleepy_penguin/extconf.rb
19
19
  ext/sleepy_penguin/init.c
20
+ ext/sleepy_penguin/inotify.c
20
21
  ext/sleepy_penguin/nonblock.h
21
22
  ext/sleepy_penguin/sleepy_penguin.h
22
23
  ext/sleepy_penguin/timerfd.c
@@ -30,4 +31,5 @@ test/test_epoll.rb
30
31
  test/test_epoll_gc.rb
31
32
  test/test_epoll_optimizations.rb
32
33
  test/test_eventfd.rb
34
+ test/test_inotify.rb
33
35
  test/test_timerfd.rb
data/ChangeLog CHANGED
@@ -1,5 +1,124 @@
1
1
  ChangeLog from http://bogomips.org/sleepy_penguin.git
2
2
 
3
+ commit bba86c017d101c365c5a22b8e2b734ff7216ce56
4
+ Author: Eric Wong <normalperson@yhbt.net>
5
+ Date: Fri Feb 4 22:24:59 2011 +0000
6
+
7
+ sleepy_penguin 1.4.0 - Linux I/O events for Ruby
8
+
9
+ * Epoll#wait: do not automatically retry on EINTR
10
+ * preliminary Inotify support
11
+ * Epoll.new no longer defaults to close-on-exec
12
+
13
+ TODO: FANotify + SignalFD
14
+
15
+ commit 4465548dd80cf779af53bbfee133f0be5f8f2791
16
+ Author: Eric Wong <normalperson@yhbt.net>
17
+ Date: Fri Feb 4 22:23:12 2011 +0000
18
+
19
+ TODO: update with fanotify item
20
+
21
+ The fscking all notification system!
22
+
23
+ commit 6b54faf7d855b7d9eb45bf437b022e2774f39826
24
+ Author: Eric Wong <normalperson@yhbt.net>
25
+ Date: Fri Feb 4 22:19:23 2011 +0000
26
+
27
+ bump wrongdoc dependency
28
+
29
+ wrongdoc 1.5 is nicer
30
+
31
+ commit 67fa5292823f4c38a35dd83c4948441ce8438d40
32
+ Author: Eric Wong <normalperson@yhbt.net>
33
+ Date: Fri Feb 4 22:16:07 2011 +0000
34
+
35
+ safety fix for Inotify#dup
36
+
37
+ We do not want to share buffers between inotify descriptors.
38
+
39
+ commit 92a666f3ff27539655e9130db16bd1587db061de
40
+ Author: Eric Wong <normalperson@yhbt.net>
41
+ Date: Fri Feb 4 22:02:25 2011 +0000
42
+
43
+ Epoll.new does not default to close-on-exec
44
+
45
+ No need to differ from other file descriptors, even though
46
+ it would be better if *all* file descriptors would default to
47
+ O_CLOEXEC.
48
+
49
+ commit 6540be80d8dca8cf93e74273d04211c1a73a674e
50
+ Author: Eric Wong <normalperson@yhbt.net>
51
+ Date: Fri Feb 4 22:00:29 2011 +0000
52
+
53
+ require rb_memerror and rb_io_close
54
+
55
+ The latest Rubinius supports both of these as do all MRI
56
+
57
+ commit 9f51099a6651d314d1ff5a435b6bc349d3472486
58
+ Author: Eric Wong <normalperson@yhbt.net>
59
+ Date: Fri Feb 4 21:57:45 2011 +0000
60
+
61
+ epoll.c: safer replacement function naming
62
+
63
+ This can avoid confusion/conflicts in case we link with newer
64
+ versions that have the missing symbols.
65
+
66
+ commit 2cc41c38dc270ff764a5cc58fd81fbdacde9ff4b
67
+ Author: Eric Wong <e@yhbt.net>
68
+ Date: Fri Feb 4 10:58:40 2011 +0000
69
+
70
+ preliminary inotify support
71
+
72
+ It seems to basically work...
73
+
74
+ commit 7812324579b430fa604905410b506e9e88fdda55
75
+ Author: Eric Wong <e@yhbt.net>
76
+ Date: Fri Feb 4 06:24:20 2011 +0000
77
+
78
+ quiet build warnings for older systems
79
+
80
+ Harmless, but still
81
+
82
+ commit 7fbb141402974a91ff925e3f303b1bc2c698b0d4
83
+ Author: Eric Wong <e@yhbt.net>
84
+ Date: Fri Feb 4 06:21:07 2011 +0000
85
+
86
+ epoll.c: fix uninitialized fd variable
87
+
88
+ Oops :x This changes/fixes some minor misbehavior.
89
+
90
+ commit c02141cbfa965a19b236e4f9a09856bd2fcacca0
91
+ Author: Eric Wong <e@yhbt.net>
92
+ Date: Fri Feb 4 06:00:20 2011 +0000
93
+
94
+ Epoll#wait: do not automatically retry on EINTR
95
+
96
+ It's often used to drive event loops and EINTR should be
97
+ retried by the user (like IO.select and not like
98
+ IO#read_nonblock).
99
+
100
+ commit 9dda070b66753e04a179e0cd36d1eff29195a7cb
101
+ Author: Eric Wong <normalperson@yhbt.net>
102
+ Date: Wed Feb 2 18:29:09 2011 -0800
103
+
104
+ pkg.mk: use RbConfig instead of Config
105
+
106
+ Config is deprecated
107
+
108
+ commit fecdb9a57523cd2d38fc76fa8609388712aa075e
109
+ Author: Eric Wong <e@yhbt.net>
110
+ Date: Thu Jan 27 21:45:06 2011 +0000
111
+
112
+ pkg.mk: allow WRONGDOC variable to be overriden
113
+
114
+ This makes life easier for the wrongdoc package itself
115
+
116
+ commit 01e7012f27109295f7cc158f561091b07b831762
117
+ Author: Eric Wong <e@yhbt.net>
118
+ Date: Thu Jan 27 06:18:35 2011 +0000
119
+
120
+ pkg.mk: update in case we get rid of C ext
121
+
3
122
  commit 2c3c2b788c89b1ede5445bc930dd9dbb9a658c50
4
123
  Author: Eric Wong <normalperson@yhbt.net>
5
124
  Date: Fri Jan 21 16:51:23 2011 -0800
data/GIT-VERSION-FILE CHANGED
@@ -1 +1 @@
1
- GIT_VERSION = 1.3.1
1
+ GIT_VERSION = 1.4.0
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v1.3.1.GIT
4
+ DEF_VER=v1.4.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/LATEST CHANGED
@@ -1,7 +1,8 @@
1
- === sleepy_penguin 1.3.1 - safety checks for delete / 2011-01-22 00:52 UTC
1
+ === sleepy_penguin 1.4.0 - Linux I/O events for Ruby / 2011-02-04 22:27 UTC
2
2
 
3
- One bugfix for Epoll#delete:
3
+ * Epoll#wait: do not automatically retry on EINTR
4
+ * preliminary Inotify support
5
+ * Epoll.new no longer defaults to close-on-exec
4
6
 
5
- Eric Wong (1):
6
- safer closed checks for proxied objects
7
+ TODO: FANotify + SignalFD
7
8
 
data/NEWS CHANGED
@@ -1,3 +1,11 @@
1
+ === sleepy_penguin 1.4.0 - Linux I/O events for Ruby / 2011-02-04 22:27 UTC
2
+
3
+ * Epoll#wait: do not automatically retry on EINTR
4
+ * preliminary Inotify support
5
+ * Epoll.new no longer defaults to close-on-exec
6
+
7
+ TODO: FANotify + SignalFD
8
+
1
9
  === sleepy_penguin 1.3.1 - safety checks for delete / 2011-01-22 00:52 UTC
2
10
 
3
11
  One bugfix for Epoll#delete:
data/TODO CHANGED
@@ -1,3 +1,3 @@
1
- * SignalFD interface
1
+ * FANotify interface
2
2
 
3
- * Inotify? Several libraries already support it, but it fits this project, too
3
+ * SignalFD interface
@@ -13,21 +13,6 @@
13
13
 
14
14
  #define EP_RECREATE (-2)
15
15
 
16
- #ifndef HAVE_RB_MEMERROR
17
- static void rb_memerror(void)
18
- {
19
- static const char e[] = "[FATAL] failed to allocate memory\n";
20
- write(2, e, sizeof(e) - 1);
21
- abort();
22
- }
23
- #endif
24
- #ifndef HAVE_RB_IO_CLOSE
25
- static VALUE rb_io_close(VALUE io)
26
- {
27
- return rb_funcall(io, rb_intern("close"), 0);
28
- }
29
- #endif
30
-
31
16
  static st_table *active;
32
17
  static const int step = 64; /* unlikely to grow unless you're huge */
33
18
  static VALUE cEpoll_IO;
@@ -70,7 +55,7 @@ static struct rb_epoll *ep_get(VALUE self)
70
55
  * Don't worry about thread-safety since current Ruby 1.9 won't
71
56
  * call this without GVL.
72
57
  */
73
- static int epoll_create1(int flags)
58
+ static int my_epoll_create1(int flags)
74
59
  {
75
60
  int fd = epoll_create(1024); /* size ignored since 2.6.8 */
76
61
 
@@ -88,6 +73,7 @@ err:
88
73
  return -1;
89
74
  }
90
75
  }
76
+ #define epoll_create1 my_epoll_create1
91
77
  #endif
92
78
 
93
79
  static void gcmark(void *ptr)
@@ -129,7 +115,7 @@ static VALUE alloc(VALUE klass)
129
115
  ep->marks = Qnil;
130
116
  ep->flag_cache = Qnil;
131
117
  ep->capa = step;
132
- ep->flags = EPOLL_CLOEXEC;
118
+ ep->flags = 0;
133
119
  ep->events = xmalloc(sizeof(struct epoll_event) * ep->capa);
134
120
 
135
121
  return self;
@@ -176,7 +162,7 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
176
162
 
177
163
  rb_scan_args(argc, argv, "01", &fl);
178
164
  if (NIL_P(fl)) {
179
- flags = EPOLL_CLOEXEC;
165
+ flags = 0;
180
166
  } else {
181
167
  switch (TYPE(fl)) {
182
168
  case T_FIXNUM:
@@ -289,7 +275,7 @@ fallback_add:
289
275
  static VALUE delete(VALUE self, VALUE io)
290
276
  {
291
277
  struct rb_epoll *ep = ep_get(self);
292
- int fd;
278
+ int fd = my_fileno(io);
293
279
  int rv;
294
280
  VALUE cur_io;
295
281
 
@@ -297,7 +283,6 @@ static VALUE delete(VALUE self, VALUE io)
297
283
  if (my_io_closed(io))
298
284
  goto out;
299
285
 
300
- fd = my_fileno(io);
301
286
  cur_io = rb_ary_entry(ep->marks, fd);
302
287
  if (NIL_P(cur_io) || my_io_closed(cur_io))
303
288
  return Qnil;
@@ -355,12 +340,7 @@ static VALUE nogvl_wait(void *args)
355
340
 
356
341
  static VALUE real_epwait(struct rb_epoll *ep)
357
342
  {
358
- int n;
359
-
360
- do {
361
- n = (int)rb_thread_blocking_region(nogvl_wait, ep,
362
- RUBY_UBF_IO, 0);
363
- } while (n == -1 && errno == EINTR);
343
+ int n = (int)rb_thread_blocking_region(nogvl_wait, ep, RUBY_UBF_IO, 0);
364
344
 
365
345
  return epwait_result(ep, n);
366
346
  }
@@ -403,7 +383,7 @@ static int epwait_forever(struct rb_epoll *ep)
403
383
  do {
404
384
  (void)rb_io_wait_readable(ep->fd);
405
385
  n = safe_epoll_wait(ep);
406
- } while (n == 0 || (n == -1 && errno == EINTR));
386
+ } while (n == 0);
407
387
 
408
388
  return n;
409
389
  }
@@ -426,13 +406,7 @@ static int epwait_timed(struct rb_epoll *ep)
426
406
  gettimeofday(&t0, NULL);
427
407
  (void)rb_thread_select(ep->fd + 1, &rfds, NULL, NULL, &tv);
428
408
  n = safe_epoll_wait(ep);
429
-
430
- /*
431
- * if we got EINTR from epoll_wait /and/ timed out
432
- * just consider it a timeout and don't raise an error
433
- */
434
-
435
- if (n > 0 || (n == -1 && errno != EINTR))
409
+ if (n != 0)
436
410
  return n;
437
411
 
438
412
  /* XXX use CLOCK_MONOTONIC if people care about 1.8... */
@@ -4,9 +4,10 @@ have_header("pthread.h") or abort 'pthread.h not found'
4
4
  have_header('sys/eventfd.h')
5
5
  have_header('sys/signalfd.h')
6
6
  have_header('sys/timerfd.h')
7
+ have_header('sys/inotify.h')
7
8
  have_header('ruby/io.h') and have_struct_member('rb_io_t', 'fd', 'ruby/io.h')
8
- have_func('rb_memerror')
9
- have_func('rb_io_close')
9
+ have_func('rb_memerror') or abort 'need rb_memerror()'
10
+ have_func('rb_io_close') or abort 'need rb_io_close()'
10
11
  have_func('epoll_create1', %w(sys/epoll.h))
11
12
  have_func('rb_thread_blocking_region')
12
13
  have_library('pthread')
@@ -3,13 +3,19 @@ void sleepy_penguin_init_epoll(void);
3
3
  #ifdef HAVE_SYS_TIMERFD_H
4
4
  void sleepy_penguin_init_timerfd(void);
5
5
  #else
6
- # define sleepy_penguin_init_timerfd() if(0)
6
+ # define sleepy_penguin_init_timerfd() for(;0;)
7
7
  #endif
8
8
 
9
9
  #ifdef HAVE_SYS_EVENTFD_H
10
10
  void sleepy_penguin_init_eventfd(void);
11
11
  #else
12
- # define sleepy_penguin_init_eventfd() if(0)
12
+ # define sleepy_penguin_init_eventfd() for(;0;)
13
+ #endif
14
+
15
+ #ifdef HAVE_SYS_INOTIFY_H
16
+ void sleepy_penguin_init_inotify(void);
17
+ #else
18
+ # define sleepy_penguin_init_inotify() for(;0;)
13
19
  #endif
14
20
 
15
21
  void Init_sleepy_penguin_ext(void)
@@ -17,4 +23,5 @@ void Init_sleepy_penguin_ext(void)
17
23
  sleepy_penguin_init_epoll();
18
24
  sleepy_penguin_init_timerfd();
19
25
  sleepy_penguin_init_eventfd();
26
+ sleepy_penguin_init_inotify();
20
27
  }
@@ -0,0 +1,293 @@
1
+ #ifdef HAVE_SYS_INOTIFY_H
2
+ #include "sleepy_penguin.h"
3
+ #include "nonblock.h"
4
+ #include <sys/inotify.h>
5
+ #include <sys/ioctl.h>
6
+ static ID id_for_fd, id_inotify_buf, id_inotify_tmp, id_mask;
7
+ static VALUE cEvent, checks;
8
+
9
+ #ifndef IN_CLOEXEC
10
+ # define IN_CLOEXEC 02000000
11
+ #endif
12
+ #ifndef IN_NONBLOCK
13
+ # define IN_NONBLOCK O_NONBLOCK
14
+ #endif
15
+ #ifndef IN_ATTRIB
16
+ # define IN_ATTRIB 0x00000004
17
+ #endif
18
+ #ifndef IN_ONLYDIR
19
+ # define IN_ONLYDIR 0x01000000
20
+ #endif
21
+ #ifndef IN_DONT_FOLLOW
22
+ # define IN_DONT_FOLLOW 0x02000000
23
+ #endif
24
+ #ifndef IN_EXCL_UNLINK
25
+ # define IN_EXCL_UNLINK 0x04000000
26
+ #endif
27
+ #ifndef IN_MASK_ADD
28
+ # define IN_MASK_ADD 0x20000000
29
+ #endif
30
+ #ifndef IN_ONESHOT
31
+ # define IN_ONESHOT 0x80000000
32
+ #endif
33
+
34
+ #ifndef HAVE_INOTIFY_INIT1
35
+ /*
36
+ * fake inotify_init1() since some systems don't have it
37
+ * Don't worry about thread-safety since current Ruby 1.9 won't
38
+ * call this without GVL.
39
+ */
40
+ static int my_inotify_init1(int flags)
41
+ {
42
+ int fd = inotify_init();
43
+ int tmp;
44
+
45
+ if (fd < 0)
46
+ return fd;
47
+ if ((flags & IN_CLOEXEC) && (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1))
48
+ goto fcntl_err;
49
+ if (flags & IN_NONBLOCK) {
50
+ tmp = fcntl(fd, F_GETFL);
51
+ if (tmp == -1)
52
+ goto fcntl_err;
53
+ if ((fcntl(fd, F_SETFL, tmp | O_NONBLOCK) != 0))
54
+ goto fcntl_err;
55
+ }
56
+
57
+ return fd;
58
+ fcntl_err:
59
+ tmp = errno;
60
+ close(fd);
61
+ errno = tmp;
62
+ rb_sys_fail("fcntl");
63
+ }
64
+ # define inotify_init1 my_inotify_init1
65
+ #endif /* HAVE_INOTIFY_INIT1 */
66
+
67
+ static VALUE s_init(int argc, VALUE *argv, VALUE klass)
68
+ {
69
+ VALUE _flags, rv;
70
+ int flags;
71
+ int fd;
72
+
73
+ rb_scan_args(argc, argv, "01", &_flags);
74
+ flags = NIL_P(_flags) ? 0 : NUM2INT(_flags);
75
+
76
+ fd = inotify_init1(flags);
77
+ if (fd == -1) {
78
+ if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
79
+ rb_gc();
80
+ fd = inotify_init1(flags);
81
+ }
82
+ if (fd == -1)
83
+ rb_sys_fail("inotify_init1");
84
+ }
85
+
86
+ rv = rb_funcall(klass, id_for_fd, 1, INT2NUM(fd));
87
+ rb_ivar_set(rv, id_inotify_buf, rb_str_new(0, 128));
88
+ rb_ivar_set(rv, id_inotify_tmp, rb_ary_new());
89
+
90
+ return rv;
91
+ }
92
+
93
+ static VALUE add_watch(VALUE self, VALUE path, VALUE vmask)
94
+ {
95
+ int fd = my_fileno(self);
96
+ const char *pathname = StringValuePtr(path);
97
+ uint32_t mask = NUM2UINT(vmask);
98
+ int rc = inotify_add_watch(fd, pathname, mask);
99
+
100
+ if (rc == -1) {
101
+ if (errno == ENOMEM) {
102
+ rb_gc();
103
+ rc = inotify_add_watch(fd, pathname, mask);
104
+ }
105
+ if (rc == -1)
106
+ rb_sys_fail("inotify_add_watch");
107
+ }
108
+ return UINT2NUM((uint32_t)rc);
109
+ }
110
+
111
+ static VALUE rm_watch(VALUE self, VALUE vwd)
112
+ {
113
+ uint32_t wd = NUM2UINT(vwd);
114
+ int fd = my_fileno(self);
115
+ int rc = inotify_rm_watch(fd, wd);
116
+
117
+ if (rc == -1)
118
+ rb_sys_fail("inotify_rm_watch");
119
+ return INT2NUM(rc);
120
+ }
121
+
122
+ static size_t event_len(struct inotify_event *e)
123
+ {
124
+ return sizeof(struct inotify_event) + e->len;
125
+ }
126
+
127
+ static VALUE event_new(struct inotify_event *e)
128
+ {
129
+ VALUE wd = INT2NUM(e->wd);
130
+ VALUE mask = UINT2NUM(e->mask);
131
+ VALUE cookie = UINT2NUM(e->cookie);
132
+ VALUE name;
133
+
134
+ /* name may be zero-padded, so we do strlen() */
135
+ name = e->len ? rb_str_new(e->name, strlen(e->name)) : Qnil;
136
+
137
+ return rb_struct_new(cEvent, wd, mask, cookie, name);
138
+ }
139
+
140
+ static VALUE take(int argc, VALUE *argv, VALUE self)
141
+ {
142
+ int fd = my_fileno(self);
143
+ VALUE buf = rb_ivar_get(self, id_inotify_buf);
144
+ VALUE tmp = rb_ivar_get(self, id_inotify_tmp);
145
+ struct inotify_event *ptr;
146
+ struct inotify_event *e, *end;
147
+ long len;
148
+ ssize_t r;
149
+ VALUE rv = Qnil;
150
+ VALUE nonblock;
151
+
152
+ if (RARRAY_LEN(tmp) > 0)
153
+ return rb_ary_shift(tmp);
154
+
155
+ rb_scan_args(argc, argv, "01", &nonblock);
156
+
157
+ len = RSTRING_LEN(buf);
158
+ ptr = (struct inotify_event *)RSTRING_PTR(buf);
159
+ do {
160
+ set_nonblock(fd);
161
+ r = read(fd, ptr, len);
162
+ if (r == 0 || (r < 0 && errno == EINVAL)) {
163
+ int newlen;
164
+ if (len > 0x10000)
165
+ rb_raise(rb_eRuntimeError, "path too long");
166
+ if (ioctl(fd, FIONREAD, &newlen) != 0)
167
+ rb_sys_fail("ioctl(inotify,FIONREAD)");
168
+ rb_str_resize(buf, newlen);
169
+ ptr = (struct inotify_event *)RSTRING_PTR(buf);
170
+ len = newlen;
171
+ } else if (r < 0) {
172
+ if (errno == EAGAIN) {
173
+ if (RTEST(nonblock))
174
+ return Qnil;
175
+ rb_io_wait_readable(fd);
176
+ } else {
177
+ rb_sys_fail("read(inotify)");
178
+ }
179
+ } else {
180
+ end = (struct inotify_event *)((char *)ptr + r);
181
+ for (e = ptr; e < end; ) {
182
+ VALUE event = event_new(e);
183
+ if (NIL_P(rv))
184
+ rv = event;
185
+ else
186
+ rb_ary_push(tmp, event);
187
+ e = (struct inotify_event *)
188
+ ((char *)e + event_len(e));
189
+ }
190
+ }
191
+ } while (NIL_P(rv));
192
+
193
+ return rv;
194
+ }
195
+
196
+ static VALUE events(VALUE self)
197
+ {
198
+ long len = RARRAY_LEN(checks);
199
+ VALUE *ptr = RARRAY_PTR(checks);
200
+ VALUE pair;
201
+ VALUE sym;
202
+ VALUE rv = rb_ary_new();
203
+ uint32_t mask;
204
+ uint32_t event_mask = NUM2UINT(rb_funcall(self, id_mask, 0));
205
+
206
+ for (; (len -= 2) >= 0;) {
207
+ sym = *ptr++;
208
+ mask = NUM2UINT(*ptr++);
209
+ if ((event_mask & mask) == mask)
210
+ rb_ary_push(rv, sym);
211
+ }
212
+
213
+ return rv;
214
+ }
215
+
216
+ static VALUE init_copy(VALUE dest, VALUE orig)
217
+ {
218
+ VALUE tmp;
219
+
220
+ dest = rb_call_super(1, &orig);
221
+ rb_ivar_set(dest, id_inotify_buf, rb_str_new(0, 128));
222
+
223
+ return dest;
224
+ }
225
+
226
+ void sleepy_penguin_init_inotify(void)
227
+ {
228
+ VALUE mSleepyPenguin, cInotify;
229
+
230
+ mSleepyPenguin = rb_define_module("SleepyPenguin");
231
+ cInotify = rb_define_class_under(mSleepyPenguin, "Inotify", rb_cIO);
232
+ rb_define_method(cInotify, "add_watch", add_watch, 2);
233
+ rb_define_method(cInotify, "rm_watch", rm_watch, 1);
234
+ rb_define_method(cInotify, "initialize_copy", init_copy, 1);
235
+ rb_define_method(cInotify, "take", take, -1);
236
+ cEvent = rb_struct_define(NULL, "wd", "mask", "cookie", "name", NULL);
237
+ rb_define_const(cInotify, "Event", cEvent);
238
+ rb_define_method(cEvent, "events", events, 0);
239
+ rb_define_singleton_method(cInotify, "new", s_init, -1);
240
+ id_for_fd = rb_intern("for_fd");
241
+ id_inotify_buf = rb_intern("@inotify_buf");
242
+ id_inotify_tmp = rb_intern("@inotify_tmp");
243
+ id_mask = rb_intern("mask");
244
+ checks = rb_ary_new();
245
+ rb_global_variable(&checks);
246
+ #define IN(x) rb_define_const(cInotify,#x,UINT2NUM(IN_##x))
247
+ #define IN2(x) do { \
248
+ VALUE val = UINT2NUM(IN_##x); \
249
+ rb_define_const(cInotify,#x,val); \
250
+ rb_ary_push(checks, ID2SYM(rb_intern(#x))); \
251
+ rb_ary_push(checks, val); \
252
+ } while (0)
253
+
254
+ rb_define_const(cInotify, "FIONREAD", INT2NUM(FIONREAD));
255
+
256
+ IN(ALL_EVENTS);
257
+
258
+ /* events a user can watch for */
259
+ IN2(ACCESS);
260
+ IN2(MODIFY);
261
+ IN2(ATTRIB);
262
+ IN2(CLOSE_WRITE);
263
+ IN2(CLOSE_NOWRITE);
264
+ IN2(OPEN);
265
+ IN2(MOVED_FROM);
266
+ IN2(MOVED_TO);
267
+ IN2(CREATE);
268
+ IN2(DELETE);
269
+ IN2(DELETE_SELF);
270
+ IN2(MOVE_SELF);
271
+
272
+ /* sent as needed to any watch */
273
+ IN2(UNMOUNT);
274
+ IN2(Q_OVERFLOW);
275
+ IN2(IGNORED);
276
+ IN2(ISDIR);
277
+
278
+ /* helpers */
279
+ IN(CLOSE);
280
+ IN(MOVE);
281
+
282
+ /* special flags */
283
+ IN(ONLYDIR);
284
+ IN(DONT_FOLLOW);
285
+ IN(EXCL_UNLINK);
286
+ IN(MASK_ADD);
287
+ IN(ONESHOT);
288
+
289
+ /* for inotify_init1() */
290
+ IN(NONBLOCK);
291
+ IN(CLOEXEC);
292
+ }
293
+ #endif /* HAVE_SYS_INOTIFY_H */
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: binary -*-
2
2
  module SleepyPenguin
3
3
 
4
- # the version of sleepy_penguin, currently 1.3.1
5
- SLEEPY_PENGUIN_VERSION = '1.3.1'
4
+ # the version of sleepy_penguin, currently 1.4.0
5
+ SLEEPY_PENGUIN_VERSION = '1.4.0'
6
6
  end
7
7
  require 'sleepy_penguin_ext'
data/pkg.mk CHANGED
@@ -1,12 +1,13 @@
1
1
  RUBY = ruby
2
2
  RAKE = rake
3
3
  RSYNC = rsync
4
+ WRONGDOC = wrongdoc
4
5
 
5
6
  GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
6
7
  @./GIT-VERSION-GEN
7
8
  -include GIT-VERSION-FILE
8
9
  -include local.mk
9
- DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
10
+ DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts RbConfig::CONFIG["DLEXT"]')
10
11
  RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
11
12
  RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
12
13
  lib := lib
@@ -47,7 +48,7 @@ endif
47
48
 
48
49
  pkg_extra := GIT-VERSION-FILE NEWS ChangeLog LATEST
49
50
  ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
50
- wrongdoc prepare
51
+ $(WRONGDOC) prepare
51
52
 
52
53
  manifest:
53
54
  $(RM) .manifest
@@ -59,10 +60,11 @@ manifest:
59
60
  cmp $@+ $@ || mv $@+ $@
60
61
  $(RM) $@+
61
62
 
62
- doc: .document .wrongdoc.yml
63
- find lib ext -type f -name '*.rbc' -exec rm -f '{}' ';'
63
+ doc:: .document .wrongdoc.yml
64
+ find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
65
+ -find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
64
66
  $(RM) -r doc
65
- wrongdoc all
67
+ $(WRONGDOC) all
66
68
  install -m644 COPYING doc/COPYING
67
69
  install -m644 $(shell grep '^[A-Z]' .document) doc/
68
70
 
@@ -75,10 +77,10 @@ release_changes := release_changes-$(VERSION)
75
77
  release-notes: $(release_notes)
76
78
  release-changes: $(release_changes)
77
79
  $(release_changes):
78
- wrongdoc release_changes > $@+
80
+ $(WRONGDOC) release_changes > $@+
79
81
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
80
82
  $(release_notes):
81
- wrongdoc release_notes > $@+
83
+ $(WRONGDOC) release_notes > $@+
82
84
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
83
85
 
84
86
  # ensures we're actually on the tagged $(VERSION), only used for release
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.summary = summary
21
21
  s.test_files = Dir['test/test_*.rb']
22
22
  s.extensions = %w(ext/sleepy_penguin/extconf.rb)
23
- s.add_development_dependency('wrongdoc', '~> 1.3')
23
+ s.add_development_dependency('wrongdoc', '~> 1.5')
24
24
  s.add_development_dependency('strace_me', '~> 1.0')
25
25
 
26
26
  # s.license = %w(LGPL) # disabled for compatibility with older RubyGems
data/test/test_epoll.rb CHANGED
@@ -129,7 +129,11 @@ class TestEpoll < Test::Unit::TestCase
129
129
  Process.kill(:USR1, Process.ppid)
130
130
  end
131
131
  time[:START_WAIT] = Time.now
132
- @ep.wait { |flags, obj| tmp << [ flags, obj ]; time[:EP] = Time.now }
132
+ begin
133
+ @ep.wait { |flags, obj| tmp << [ flags, obj ]; time[:EP] = Time.now }
134
+ rescue Errno::EINTR
135
+ retry
136
+ end
133
137
  assert_equal([[Epoll::IN, @rd]], tmp)
134
138
  _, status = Process.waitpid2(pid)
135
139
  assert status.success?
@@ -313,7 +317,7 @@ class TestEpoll < Test::Unit::TestCase
313
317
  def test_new
314
318
  @ep.close
315
319
  io = Epoll.new.to_io
316
- assert((io.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC) == Fcntl::FD_CLOEXEC)
320
+ assert_equal 0, io.fcntl(Fcntl::F_GETFD)
317
321
  end
318
322
 
319
323
  def test_delete
@@ -90,8 +90,8 @@ class TestEpollOptimizations < Test::Unit::TestCase
90
90
  @wr.close
91
91
  io, err = Strace.me { rv = @ep.delete(obj) }
92
92
  lines = io.readlines; io.close
93
- assert_nil err
94
- assert_equal obj, rv
93
+ assert_kind_of IOError, err
94
+ assert_nil rv
95
95
  assert_equal 0, lines.grep(/^epoll_ctl/).size
96
96
  end
97
97
 
@@ -0,0 +1,62 @@
1
+ require 'test/unit'
2
+ require 'fcntl'
3
+ require 'tempfile'
4
+ $-w = true
5
+ require 'sleepy_penguin'
6
+
7
+ class TestInotify < Test::Unit::TestCase
8
+ include SleepyPenguin
9
+
10
+ def test_new
11
+ ino = Inotify.new
12
+ assert_kind_of(IO, ino)
13
+ end
14
+
15
+ def test_dup
16
+ a = Inotify.new
17
+ b = a.dup
18
+ assert a.fileno != b.fileno
19
+ abuf = a.instance_variable_get(:@inotify_buf)
20
+ bbuf = b.instance_variable_get(:@inotify_buf)
21
+ assert abuf.object_id != bbuf.object_id
22
+
23
+ atmp = a.instance_variable_get(:@inotify_tmp)
24
+ btmp = b.instance_variable_get(:@inotify_tmp)
25
+ assert_equal atmp.object_id, btmp.object_id
26
+ end
27
+
28
+ def test_new_nonblock
29
+ ino = Inotify.new Inotify::NONBLOCK
30
+ flags = ino.fcntl(Fcntl::F_GETFL) & Fcntl::O_NONBLOCK
31
+ assert_equal(Fcntl::O_NONBLOCK, flags)
32
+ end
33
+
34
+ def test_new_cloeexec
35
+ ino = Inotify.new Inotify::CLOEXEC
36
+ flags = ino.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC
37
+ assert_equal(Fcntl::FD_CLOEXEC, flags)
38
+ end
39
+
40
+ def test_add_take
41
+ ino = Inotify.new Inotify::CLOEXEC
42
+ tmp1 = Tempfile.new 'take'
43
+ tmp2 = Tempfile.new 'take'
44
+ wd = ino.add_watch File.dirname(tmp1.path), Inotify::MOVE
45
+ assert_kind_of Integer, wd
46
+ File.rename tmp1.path, tmp2.path
47
+ event = ino.take
48
+ assert_equal wd, event.wd
49
+ assert_kind_of Inotify::Event, event
50
+ assert_equal File.basename(tmp1.path), event.name
51
+ others = ino.instance_variable_get(:@inotify_tmp)
52
+ assert_kind_of Array, others
53
+ assert_equal 1, others.size
54
+ assert_equal File.basename(tmp2.path), others[0].name
55
+ assert_equal [ :MOVED_FROM ], event.events
56
+ assert_equal [ :MOVED_TO ], others[0].events
57
+ assert_equal wd, others[0].wd
58
+ second_id = others[0].object_id
59
+ assert_equal second_id, ino.take.object_id
60
+ assert_nil ino.take(true)
61
+ end
62
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sleepy_penguin
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 3
9
- - 1
10
- version: 1.3.1
8
+ - 4
9
+ - 0
10
+ version: 1.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - sleepy_penguin hackers
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-22 00:00:00 +00:00
18
+ date: 2011-02-04 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -26,11 +26,11 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- hash: 9
29
+ hash: 5
30
30
  segments:
31
31
  - 1
32
- - 3
33
- version: "1.3"
32
+ - 5
33
+ version: "1.5"
34
34
  type: :development
35
35
  version_requirements: *id001
36
36
  - !ruby/object:Gem::Dependency
@@ -88,6 +88,7 @@ files:
88
88
  - ext/sleepy_penguin/eventfd.c
89
89
  - ext/sleepy_penguin/extconf.rb
90
90
  - ext/sleepy_penguin/init.c
91
+ - ext/sleepy_penguin/inotify.c
91
92
  - ext/sleepy_penguin/nonblock.h
92
93
  - ext/sleepy_penguin/sleepy_penguin.h
93
94
  - ext/sleepy_penguin/timerfd.c
@@ -101,6 +102,7 @@ files:
101
102
  - test/test_epoll_gc.rb
102
103
  - test/test_epoll_optimizations.rb
103
104
  - test/test_eventfd.rb
105
+ - test/test_inotify.rb
104
106
  - test/test_timerfd.rb
105
107
  has_rdoc: true
106
108
  homepage: http://bogomips.org/sleepy_penguin/
@@ -143,6 +145,7 @@ summary: Linux I/O events for Ruby
143
145
  test_files:
144
146
  - test/test_epoll_optimizations.rb
145
147
  - test/test_epoll.rb
148
+ - test/test_inotify.rb
146
149
  - test/test_eventfd.rb
147
150
  - test/test_epoll_gc.rb
148
151
  - test/test_timerfd.rb