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 +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
|