sleepy_penguin 1.3.1 → 1.4.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.
- data/.manifest +2 -0
- data/ChangeLog +119 -0
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/LATEST +5 -4
- data/NEWS +8 -0
- data/TODO +2 -2
- data/ext/sleepy_penguin/epoll.c +8 -34
- data/ext/sleepy_penguin/extconf.rb +3 -2
- data/ext/sleepy_penguin/init.c +9 -2
- data/ext/sleepy_penguin/inotify.c +293 -0
- data/lib/sleepy_penguin.rb +2 -2
- data/pkg.mk +9 -7
- data/sleepy_penguin.gemspec +1 -1
- data/test/test_epoll.rb +6 -2
- data/test/test_epoll_optimizations.rb +2 -2
- data/test/test_inotify.rb +62 -0
- metadata +11 -8
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.
|
1
|
+
GIT_VERSION = 1.4.0
|
data/GIT-VERSION-GEN
CHANGED
data/LATEST
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
=== sleepy_penguin 1.
|
1
|
+
=== sleepy_penguin 1.4.0 - Linux I/O events for Ruby / 2011-02-04 22:27 UTC
|
2
2
|
|
3
|
-
|
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
|
-
|
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
|
-
*
|
1
|
+
* FANotify interface
|
2
2
|
|
3
|
-
*
|
3
|
+
* SignalFD interface
|
data/ext/sleepy_penguin/epoll.c
CHANGED
@@ -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
|
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 =
|
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 =
|
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
|
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')
|
data/ext/sleepy_penguin/init.c
CHANGED
@@ -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()
|
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()
|
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 */
|
data/lib/sleepy_penguin.rb
CHANGED
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
|
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
|
-
|
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
|
63
|
-
find lib
|
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
|
-
|
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
|
-
|
80
|
+
$(WRONGDOC) release_changes > $@+
|
79
81
|
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
80
82
|
$(release_notes):
|
81
|
-
|
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
|
data/sleepy_penguin.gemspec
CHANGED
@@ -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.
|
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
|
-
|
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
|
-
|
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
|
-
|
94
|
-
|
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:
|
4
|
+
hash: 7
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 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-
|
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:
|
29
|
+
hash: 5
|
30
30
|
segments:
|
31
31
|
- 1
|
32
|
-
-
|
33
|
-
version: "1.
|
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
|