sleepy_penguin 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.wrongdoc.yml +2 -2
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +5 -149
- data/README +2 -2
- data/Rakefile +3 -2
- data/ext/sleepy_penguin/epoll.c +138 -16
- data/ext/sleepy_penguin/extconf.rb +1 -0
- data/ext/sleepy_penguin/sleepy_penguin.h +13 -1
- data/lib/sleepy_penguin.rb +2 -2
- data/pkg.mk +166 -0
- data/script/isolate_for_tests +30 -0
- data/sleepy_penguin.gemspec +2 -1
- data/test/test_epoll.rb +31 -1
- data/test/test_epoll_optimizations.rb +127 -0
- metadata +24 -5
data/.gitignore
CHANGED
data/.wrongdoc.yml
CHANGED
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -1,155 +1,11 @@
|
|
1
|
-
# use GNU Make to run tests in parallel, and without depending on RubyGems
|
2
1
|
all::
|
3
|
-
|
4
|
-
RAKE = rake
|
5
|
-
RSYNC = rsync
|
6
|
-
|
7
|
-
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
8
|
-
@./GIT-VERSION-GEN
|
9
|
-
-include GIT-VERSION-FILE
|
10
|
-
-include local.mk
|
11
|
-
ifeq ($(DLEXT),) # "so" for Linux
|
12
|
-
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
|
13
|
-
endif
|
14
|
-
ifeq ($(RUBY_VERSION),)
|
15
|
-
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
16
|
-
endif
|
17
|
-
|
18
|
-
install:
|
19
|
-
$(prep_setup_rb)
|
20
|
-
$(RM) -r .install-tmp
|
21
|
-
mkdir .install-tmp
|
22
|
-
$(RUBY) setup.rb all
|
23
|
-
$(RM) $^
|
24
|
-
$(RM) -r .install-tmp
|
25
|
-
$(prep_setup_rb)
|
26
|
-
|
27
|
-
setup_rb_files := .config InstalledFiles
|
28
|
-
prep_setup_rb := @-$(RM) $(setup_rb_files);$(MAKE) -C $(ext) clean
|
29
|
-
|
30
|
-
extdir := ext/sleepy_penguin
|
31
|
-
clean:
|
32
|
-
-$(MAKE) -C $(extdir) clean
|
33
|
-
$(RM) $(setup_rb_files) $(extdir)/Makefile
|
34
|
-
|
35
|
-
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog LATEST
|
36
|
-
ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
|
37
|
-
wrongdoc prepare
|
38
|
-
|
39
|
-
.manifest: ChangeLog
|
40
|
-
(git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
|
41
|
-
LC_ALL=C sort > $@+
|
42
|
-
cmp $@+ $@ || mv $@+ $@
|
43
|
-
$(RM) $@+
|
44
|
-
|
45
|
-
doc: .document .wrongdoc.yml
|
46
|
-
find lib ext -type f -name '*.rbc' -exec rm -f '{}' ';'
|
47
|
-
$(RM) -r doc
|
48
|
-
wrongdoc all
|
49
|
-
install -m644 COPYING doc/COPYING
|
50
|
-
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
51
|
-
|
52
|
-
ifneq ($(VERSION),)
|
2
|
+
RSYNC_DEST := bogomips.org:/srv/bogomips/sleepy_penguin
|
53
3
|
rfproject := rainbows
|
54
4
|
rfpackage := sleepy_penguin
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
release_changes := release_changes-$(VERSION)
|
59
|
-
|
60
|
-
release-notes: $(release_notes)
|
61
|
-
release-changes: $(release_changes)
|
62
|
-
$(release_changes):
|
63
|
-
wrongdoc release_changes > $@+
|
64
|
-
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
65
|
-
$(release_notes):
|
66
|
-
wrongdoc release_notes > $@+
|
67
|
-
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
68
|
-
|
69
|
-
# ensures we're actually on the tagged $(VERSION), only used for release
|
70
|
-
verify:
|
71
|
-
test x"$(shell umask)" = x0022
|
72
|
-
git rev-parse --verify refs/tags/v$(VERSION)^{}
|
73
|
-
git diff-index --quiet HEAD^0
|
74
|
-
test `git rev-parse --verify HEAD^0` = \
|
75
|
-
`git rev-parse --verify refs/tags/v$(VERSION)^{}`
|
76
|
-
|
77
|
-
fix-perms:
|
78
|
-
-git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
|
79
|
-
-git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
|
80
|
-
|
81
|
-
gem: $(pkggem)
|
82
|
-
|
83
|
-
install-gem: $(pkggem)
|
84
|
-
gem install $(CURDIR)/$<
|
85
|
-
|
86
|
-
$(pkggem): .manifest fix-perms
|
87
|
-
gem build $(rfpackage).gemspec
|
88
|
-
mkdir -p pkg
|
89
|
-
mv $(@F) $@
|
90
|
-
|
91
|
-
$(pkgtgz): distdir = $(basename $@)
|
92
|
-
$(pkgtgz): HEAD = v$(VERSION)
|
93
|
-
$(pkgtgz): .manifest fix-perms
|
94
|
-
@test -n "$(distdir)"
|
95
|
-
$(RM) -r $(distdir)
|
96
|
-
mkdir -p $(distdir)
|
97
|
-
tar cf - `cat .manifest` | (cd $(distdir) && tar xf -)
|
98
|
-
cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
|
99
|
-
mv $@+ $@
|
100
|
-
|
101
|
-
package: $(pkgtgz) $(pkggem)
|
102
|
-
|
103
|
-
test-release: verify package $(release_notes) $(release_changes)
|
104
|
-
release: verify package $(release_notes) $(release_changes)
|
105
|
-
# make tgz release on RubyForge
|
106
|
-
rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
|
107
|
-
$(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
|
108
|
-
# push gem to RubyGems.org
|
109
|
-
gem push $(pkggem)
|
110
|
-
# in case of gem downloads from RubyForge releases page
|
111
|
-
-rubyforge add_file \
|
112
|
-
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
5
|
+
include pkg.mk
|
6
|
+
ifneq ($(VERSION),)
|
7
|
+
release::
|
113
8
|
$(RAKE) raa_update VERSION=$(VERSION)
|
114
9
|
$(RAKE) publish_news VERSION=$(VERSION)
|
115
|
-
else
|
116
|
-
gem install-gem: GIT-VERSION-FILE
|
117
|
-
$(MAKE) $@ VERSION=$(GIT_VERSION)
|
118
10
|
endif
|
119
|
-
|
120
|
-
ext := $(extdir)/sleepy_penguin_ext.$(DLEXT)
|
121
|
-
$(extdir)/Makefile: $(extdir)/extconf.rb
|
122
|
-
cd $(@D) && $(RUBY) extconf.rb
|
123
|
-
|
124
|
-
c_files := $(wildcard $(extdir)/*.[ch] $(extdir)/*/*.h)
|
125
|
-
$(ext): $(c_files) $(extdir)/Makefile
|
126
|
-
$(MAKE) -C $(@D)
|
127
|
-
|
128
|
-
all:: test
|
129
|
-
|
130
|
-
build: $(ext)
|
131
|
-
test_units := $(wildcard test/test_*.rb)
|
132
|
-
test: test-unit
|
133
|
-
test-unit: $(test_units)
|
134
|
-
$(test_units): build
|
135
|
-
$(RUBY) -I lib:$(extdir) $@
|
136
|
-
|
137
|
-
# this requires GNU coreutils variants
|
138
|
-
publish_doc:
|
139
|
-
-git set-file-times
|
140
|
-
$(MAKE) doc
|
141
|
-
find doc/images -type f | \
|
142
|
-
TZ=UTC xargs touch -d '1970-01-01 00:00:06' doc/rdoc.css
|
143
|
-
$(MAKE) doc_gz
|
144
|
-
chmod 644 $$(find doc -type f)
|
145
|
-
$(RSYNC) -av doc/ bogomips.org:/srv/bogomips/sleepy_penguin/
|
146
|
-
git ls-files | xargs touch
|
147
|
-
|
148
|
-
# Create gzip variants of the same timestamp as the original so nginx
|
149
|
-
# "gzip_static on" can serve the gzipped versions directly.
|
150
|
-
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
151
|
-
doc_gz:
|
152
|
-
for i in $(docs); do \
|
153
|
-
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
154
|
-
|
155
|
-
.PHONY: .FORCE-GIT-VERSION-FILE doc test $(test_units)
|
11
|
+
.PHONY: .FORCE-GIT-VERSION-FILE doc test $(test_units) manifest
|
data/README
CHANGED
@@ -36,13 +36,13 @@ Unpack it, and run "ruby setup.rb"
|
|
36
36
|
|
37
37
|
You can get the latest source via git from the following locations:
|
38
38
|
|
39
|
-
git://
|
39
|
+
git://bogomips.org/sleepy_penguin.git
|
40
40
|
git://repo.or.cz/sleepy_penguin.git (mirror)
|
41
41
|
|
42
42
|
You may browse the code from the web and download the latest snapshot
|
43
43
|
tarballs here:
|
44
44
|
|
45
|
-
* http://
|
45
|
+
* http://bogomips.org/sleepy_penguin.git (cgit)
|
46
46
|
* http://repo.or.cz/w/sleepy_penguin.git (gitweb)
|
47
47
|
|
48
48
|
Inline patches (from "git format-patch") to the mailing list are
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
|
3
|
-
|
2
|
+
require 'wrongdoc'
|
3
|
+
cgit_url = Wrongdoc.config[:cgit_url]
|
4
|
+
git_url = Wrongdoc.config[:git_url]
|
4
5
|
|
5
6
|
desc "post news article to rubyforge"
|
6
7
|
task :publish_news do
|
data/ext/sleepy_penguin/epoll.c
CHANGED
@@ -51,6 +51,7 @@ struct rb_epoll {
|
|
51
51
|
struct epoll_event *events;
|
52
52
|
VALUE io;
|
53
53
|
VALUE marks;
|
54
|
+
VALUE flag_cache;
|
54
55
|
int flags;
|
55
56
|
};
|
56
57
|
|
@@ -95,6 +96,7 @@ static void gcmark(void *ptr)
|
|
95
96
|
|
96
97
|
rb_gc_mark(ep->io);
|
97
98
|
rb_gc_mark(ep->marks);
|
99
|
+
rb_gc_mark(ep->flag_cache);
|
98
100
|
}
|
99
101
|
|
100
102
|
static void gcfree(void *ptr)
|
@@ -124,7 +126,8 @@ static VALUE alloc(VALUE klass)
|
|
124
126
|
self = Data_Make_Struct(klass, struct rb_epoll, gcmark, gcfree, ep);
|
125
127
|
ep->fd = -1;
|
126
128
|
ep->io = Qnil;
|
127
|
-
ep->marks =
|
129
|
+
ep->marks = Qnil;
|
130
|
+
ep->flag_cache = Qnil;
|
128
131
|
ep->capa = step;
|
129
132
|
ep->flags = EPOLL_CLOEXEC;
|
130
133
|
ep->events = xmalloc(sizeof(struct epoll_event) * ep->capa);
|
@@ -145,6 +148,8 @@ static void my_epoll_create(struct rb_epoll *ep)
|
|
145
148
|
rb_sys_fail("epoll_create1");
|
146
149
|
}
|
147
150
|
st_insert(active, (st_data_t)ep->fd, (st_data_t)ep);
|
151
|
+
ep->marks = rb_ary_new();
|
152
|
+
ep->flag_cache = rb_ary_new();
|
148
153
|
}
|
149
154
|
|
150
155
|
static void ep_check(struct rb_epoll *ep)
|
@@ -153,11 +158,15 @@ static void ep_check(struct rb_epoll *ep)
|
|
153
158
|
my_epoll_create(ep);
|
154
159
|
if (ep->fd == -1)
|
155
160
|
rb_raise(rb_eIOError, "closed");
|
161
|
+
assert(TYPE(ep->marks) == T_ARRAY && "marks not initialized");
|
162
|
+
assert(TYPE(ep->flag_cache) == T_ARRAY && "flag_cache not initialized");
|
156
163
|
}
|
157
164
|
|
158
165
|
/*
|
159
166
|
* creates a new Epoll object with an optional +flags+ argument.
|
160
|
-
* +flags+ may currently be
|
167
|
+
* +flags+ may currently be Epoll::CLOEXEC or +0+ (or +nil+)
|
168
|
+
* Epoll::CLOEXEC will be set by default if +nil+ or no
|
169
|
+
* argument is passed.
|
161
170
|
*/
|
162
171
|
static VALUE init(int argc, VALUE *argv, VALUE self)
|
163
172
|
{
|
@@ -204,8 +213,17 @@ static VALUE ctl(VALUE self, VALUE io, VALUE flags, int op)
|
|
204
213
|
if (rv == -1)
|
205
214
|
rb_sys_fail("epoll_ctl");
|
206
215
|
}
|
207
|
-
|
216
|
+
switch (op) {
|
217
|
+
case EPOLL_CTL_ADD:
|
208
218
|
rb_ary_store(ep->marks, fd, io);
|
219
|
+
/* fall-through */
|
220
|
+
case EPOLL_CTL_MOD:
|
221
|
+
rb_ary_store(ep->flag_cache, fd, flags);
|
222
|
+
break;
|
223
|
+
case EPOLL_CTL_DEL:
|
224
|
+
rb_ary_store(ep->marks, fd, Qnil);
|
225
|
+
rb_ary_store(ep->flag_cache, fd, Qnil);
|
226
|
+
}
|
209
227
|
|
210
228
|
return INT2NUM(rv);
|
211
229
|
}
|
@@ -220,23 +238,44 @@ static VALUE set(VALUE self, VALUE io, VALUE flags)
|
|
220
238
|
struct rb_epoll *ep = ep_get(self);
|
221
239
|
int fd = my_fileno(io);
|
222
240
|
int rv;
|
241
|
+
VALUE cur_io = rb_ary_entry(ep->marks, fd);
|
223
242
|
|
224
243
|
ep_check(ep);
|
225
244
|
event.events = NUM2UINT(flags);
|
226
245
|
pack_event_data(&event, io);
|
227
246
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
247
|
+
if (cur_io == io) {
|
248
|
+
VALUE cur_flags = rb_ary_entry(ep->flag_cache, fd);
|
249
|
+
uint32_t cur_events;
|
250
|
+
|
251
|
+
assert(!NIL_P(cur_flags) && "cur_flags nil but cur_io is not");
|
252
|
+
cur_events = NUM2UINT(cur_flags);
|
253
|
+
|
254
|
+
if (!(cur_events & EPOLLONESHOT) && cur_events == event.events)
|
255
|
+
return Qnil;
|
234
256
|
|
235
|
-
|
236
|
-
|
257
|
+
fallback_mod:
|
258
|
+
rv = epoll_ctl(ep->fd, EPOLL_CTL_MOD, fd, &event);
|
259
|
+
if (rv == -1) {
|
260
|
+
if (errno != ENOENT)
|
261
|
+
rb_sys_fail("epoll_ctl - mod");
|
262
|
+
errno = 0;
|
263
|
+
rb_warn("epoll flag_cache failed (mod -> add)");
|
264
|
+
goto fallback_add;
|
237
265
|
}
|
238
|
-
|
266
|
+
} else {
|
267
|
+
fallback_add:
|
268
|
+
rv = epoll_ctl(ep->fd, EPOLL_CTL_ADD, fd, &event);
|
269
|
+
if (rv == -1) {
|
270
|
+
if (errno != EEXIST)
|
271
|
+
rb_sys_fail("epoll_ctl - add");
|
272
|
+
errno = 0;
|
273
|
+
rb_warn("epoll flag_cache failed (add -> mod)");
|
274
|
+
goto fallback_mod;
|
275
|
+
}
|
276
|
+
rb_ary_store(ep->marks, fd, io);
|
239
277
|
}
|
278
|
+
rb_ary_store(ep->flag_cache, fd, flags);
|
240
279
|
|
241
280
|
return INT2NUM(rv);
|
242
281
|
}
|
@@ -252,16 +291,27 @@ static VALUE delete(VALUE self, VALUE io)
|
|
252
291
|
struct rb_epoll *ep = ep_get(self);
|
253
292
|
int fd = my_fileno(io);
|
254
293
|
int rv;
|
294
|
+
VALUE cur_io;
|
255
295
|
|
256
296
|
ep_check(ep);
|
297
|
+
cur_io = rb_ary_entry(ep->marks, fd);
|
298
|
+
if (NIL_P(cur_io) || my_io_closed(cur_io))
|
299
|
+
return Qnil;
|
300
|
+
|
257
301
|
rv = epoll_ctl(ep->fd, EPOLL_CTL_DEL, fd, NULL);
|
258
302
|
if (rv == -1) {
|
259
|
-
|
303
|
+
/* beware of IO.for_fd-created descriptors */
|
304
|
+
if (errno == ENOENT || errno == EBADF) {
|
305
|
+
errno = 0;
|
306
|
+
io = Qnil;
|
307
|
+
} else {
|
260
308
|
rb_sys_fail("epoll_ctl - del");
|
261
|
-
|
262
|
-
return Qnil;
|
309
|
+
}
|
263
310
|
}
|
264
|
-
|
311
|
+
rb_ary_store(ep->marks, fd, Qnil);
|
312
|
+
rb_ary_store(ep->flag_cache, fd, Qnil);
|
313
|
+
|
314
|
+
return io;
|
265
315
|
}
|
266
316
|
|
267
317
|
static VALUE epwait_result(struct rb_epoll *ep, int n)
|
@@ -380,6 +430,7 @@ static int epwait_timed(struct rb_epoll *ep)
|
|
380
430
|
if (n > 0 || (n == -1 && errno != EINTR))
|
381
431
|
return n;
|
382
432
|
|
433
|
+
/* XXX use CLOCK_MONOTONIC if people care about 1.8... */
|
383
434
|
gettimeofday(&now, NULL);
|
384
435
|
timersub(&now, &t0, &diff);
|
385
436
|
timersub(&tv, &diff, &tv);
|
@@ -521,7 +572,12 @@ static VALUE init_copy(VALUE copy, VALUE orig)
|
|
521
572
|
NIL_P(b->io) && "Ruby broken?");
|
522
573
|
|
523
574
|
ep_check(a);
|
575
|
+
assert(NIL_P(b->marks) && "mark array not nil");
|
576
|
+
assert(NIL_P(b->flag_cache) && "flag_cache not nil");
|
524
577
|
b->marks = a->marks;
|
578
|
+
b->flag_cache = a->flag_cache;
|
579
|
+
assert(TYPE(b->marks) == T_ARRAY && "mark array not initialized");
|
580
|
+
assert(TYPE(b->flag_cache) == T_ARRAY && "flag_cache not initialized");
|
525
581
|
b->flags = a->flags;
|
526
582
|
b->fd = cloexec_dup(a);
|
527
583
|
if (b->fd == -1) {
|
@@ -537,6 +593,43 @@ static VALUE init_copy(VALUE copy, VALUE orig)
|
|
537
593
|
return copy;
|
538
594
|
}
|
539
595
|
|
596
|
+
static VALUE io_for(VALUE self, VALUE obj)
|
597
|
+
{
|
598
|
+
struct rb_epoll *ep = ep_get(self);
|
599
|
+
|
600
|
+
return rb_ary_entry(ep->marks, my_fileno(obj));
|
601
|
+
}
|
602
|
+
|
603
|
+
/*
|
604
|
+
* :call-seq:
|
605
|
+
*
|
606
|
+
* epoll.flags_for(io) => Integer
|
607
|
+
*
|
608
|
+
* Returns the flags currently watched for in current Epoll object.
|
609
|
+
*/
|
610
|
+
static VALUE flags_for(VALUE self, VALUE obj)
|
611
|
+
{
|
612
|
+
struct rb_epoll *ep = ep_get(self);
|
613
|
+
|
614
|
+
return rb_ary_entry(ep->flag_cache, my_fileno(obj));
|
615
|
+
}
|
616
|
+
|
617
|
+
/*
|
618
|
+
* :call-seq:
|
619
|
+
*
|
620
|
+
* epoll.include?(io) => true or false
|
621
|
+
*
|
622
|
+
* Returns whether or not a given IO is watched and prevented from being
|
623
|
+
* garbage-collected by the current Epoll object. This may include
|
624
|
+
* closed IO objects.
|
625
|
+
*/
|
626
|
+
static VALUE include_p(VALUE self, VALUE obj)
|
627
|
+
{
|
628
|
+
struct rb_epoll *ep = ep_get(self);
|
629
|
+
|
630
|
+
return NIL_P(rb_ary_entry(ep->marks, my_fileno(obj))) ? Qfalse : Qtrue;
|
631
|
+
}
|
632
|
+
|
540
633
|
/*
|
541
634
|
* we close (or lose to GC) epoll descriptors at fork to avoid leakage
|
542
635
|
* and invalid objects being referenced later in the child
|
@@ -582,17 +675,46 @@ void sleepy_penguin_init_epoll(void)
|
|
582
675
|
rb_define_method(cEpoll, "mod", mod, 2);
|
583
676
|
rb_define_method(cEpoll, "del", del, 1);
|
584
677
|
rb_define_method(cEpoll, "delete", delete, 1);
|
678
|
+
rb_define_method(cEpoll, "io_for", io_for, 1);
|
679
|
+
rb_define_method(cEpoll, "flags_for", flags_for, 1);
|
680
|
+
rb_define_method(cEpoll, "include?", include_p, 1);
|
585
681
|
rb_define_method(cEpoll, "set", set, 2);
|
586
682
|
rb_define_method(cEpoll, "wait", epwait, -1);
|
683
|
+
|
684
|
+
/* specifies wheter close-on-exec flag is set for Epoll.new */
|
587
685
|
rb_define_const(cEpoll, "CLOEXEC", INT2NUM(EPOLL_CLOEXEC));
|
686
|
+
|
687
|
+
/* watch for read/recv operations */
|
588
688
|
rb_define_const(cEpoll, "IN", INT2NUM(EPOLLIN));
|
689
|
+
|
690
|
+
/* watch for write/send operations */
|
589
691
|
rb_define_const(cEpoll, "OUT", INT2NUM(EPOLLOUT));
|
692
|
+
|
693
|
+
#ifdef EPOLLRDHUP
|
694
|
+
/* watch a specified IO for shutdown(SHUT_WR) on the remote-end */
|
590
695
|
rb_define_const(cEpoll, "RDHUP", INT2NUM(EPOLLRDHUP));
|
696
|
+
#endif
|
697
|
+
/* watch for urgent read(2) data */
|
591
698
|
rb_define_const(cEpoll, "PRI", INT2NUM(EPOLLPRI));
|
699
|
+
|
700
|
+
/*
|
701
|
+
* watch for errors, there is no need to specify this,
|
702
|
+
* it is always monitored when an IO is watched
|
703
|
+
*/
|
592
704
|
rb_define_const(cEpoll, "ERR", INT2NUM(EPOLLERR));
|
705
|
+
|
706
|
+
/*
|
707
|
+
* watch for hangups, there is no need to specify this,
|
708
|
+
* it is always monitored when an IO is watched
|
709
|
+
*/
|
593
710
|
rb_define_const(cEpoll, "HUP", INT2NUM(EPOLLHUP));
|
711
|
+
|
712
|
+
/* notifications are only Edge Triggered, see epoll(7) */
|
594
713
|
rb_define_const(cEpoll, "ET", INT2NUM(EPOLLET));
|
714
|
+
|
715
|
+
/* unwatch the descriptor once any event has fired */
|
595
716
|
rb_define_const(cEpoll, "ONESHOT", INT2NUM(EPOLLONESHOT));
|
717
|
+
|
596
718
|
id_for_fd = rb_intern("for_fd");
|
597
719
|
active = st_init_numtable();
|
598
720
|
|
@@ -4,6 +4,7 @@ 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('ruby/io.h') and have_struct_member('rb_io_t', 'fd', 'ruby/io.h')
|
7
8
|
have_func('rb_memerror')
|
8
9
|
have_func('rb_io_close')
|
9
10
|
have_func('epoll_create1', %w(sys/epoll.h))
|
@@ -26,12 +26,24 @@
|
|
26
26
|
# endif
|
27
27
|
#endif
|
28
28
|
|
29
|
+
#if defined(RFILE) && defined(HAVE_ST_FD)
|
30
|
+
static int my_io_closed(VALUE io)
|
31
|
+
{
|
32
|
+
return RFILE(io)->fptr->fd < 0;
|
33
|
+
}
|
34
|
+
#else
|
35
|
+
static int my_io_closed(VALUE io)
|
36
|
+
{
|
37
|
+
return rb_funcall(io, rb_intern("closed?"), 0) == Qtrue;
|
38
|
+
}
|
39
|
+
#endif
|
40
|
+
|
29
41
|
static int my_fileno(VALUE io)
|
30
42
|
{
|
31
43
|
rb_io_t *fptr;
|
32
44
|
|
33
45
|
switch (TYPE(io)) {
|
34
|
-
case T_FIXNUM: return
|
46
|
+
case T_FIXNUM: return FIX2INT(io);
|
35
47
|
case T_FILE:
|
36
48
|
GetOpenFile(io, fptr);
|
37
49
|
return FPTR_TO_FD(fptr);
|
data/lib/sleepy_penguin.rb
CHANGED
data/pkg.mk
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
RUBY = ruby
|
2
|
+
RAKE = rake
|
3
|
+
RSYNC = rsync
|
4
|
+
|
5
|
+
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
6
|
+
@./GIT-VERSION-GEN
|
7
|
+
-include GIT-VERSION-FILE
|
8
|
+
-include local.mk
|
9
|
+
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
|
10
|
+
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
11
|
+
RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
|
12
|
+
lib := lib
|
13
|
+
|
14
|
+
ifeq ($(shell test -f script/isolate_for_tests && echo t),t)
|
15
|
+
isolate_libs := tmp/isolate/$(RUBY_ENGINE)-$(RUBY_VERSION)/isolate.mk
|
16
|
+
$(isolate_libs): script/isolate_for_tests
|
17
|
+
@$(RUBY) script/isolate_for_tests
|
18
|
+
-include $(isolate_libs)
|
19
|
+
lib := $(lib):$(ISOLATE_LIBS)
|
20
|
+
endif
|
21
|
+
|
22
|
+
ext := $(firstword $(wildcard ext/*))
|
23
|
+
ifneq ($(ext),)
|
24
|
+
ext_pfx := tmp/ext/$(RUBY_ENGINE)-$(RUBY_VERSION)
|
25
|
+
ext_h := $(wildcard $(ext)/*/*.h $(ext)/*.h)
|
26
|
+
ext_src := $(wildcard $(ext)/*.c $(ext_h))
|
27
|
+
ext_pfx_src := $(addprefix $(ext_pfx)/,$(ext_src))
|
28
|
+
ext_d := $(ext_pfx)/$(ext)/.d
|
29
|
+
$(ext)/extconf.rb: $(wildcard $(ext)/*.h)
|
30
|
+
@>> $@
|
31
|
+
$(ext_d):
|
32
|
+
@mkdir -p $(@D)
|
33
|
+
@> $@
|
34
|
+
$(ext_pfx)/$(ext)/%: $(ext)/% $(ext_d)
|
35
|
+
install -m 644 $< $@
|
36
|
+
$(ext_pfx)/$(ext)/Makefile: $(ext)/extconf.rb $(ext_d) $(ext_h)
|
37
|
+
$(RM) -f $(@D)/*.o
|
38
|
+
cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb
|
39
|
+
ext_sfx := _ext.$(DLEXT)
|
40
|
+
ext_dl := $(ext_pfx)/$(ext)/$(notdir $(ext)_ext.$(DLEXT))
|
41
|
+
$(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
|
42
|
+
@echo $^ == $@
|
43
|
+
$(MAKE) -C $(@D)
|
44
|
+
lib := $(lib):$(ext_pfx)/$(ext)
|
45
|
+
build: $(ext_dl)
|
46
|
+
endif
|
47
|
+
|
48
|
+
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog LATEST
|
49
|
+
ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
|
50
|
+
wrongdoc prepare
|
51
|
+
|
52
|
+
manifest:
|
53
|
+
$(RM) .manifest
|
54
|
+
$(MAKE) .manifest
|
55
|
+
|
56
|
+
.manifest: ChangeLog
|
57
|
+
(git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
|
58
|
+
LC_ALL=C sort > $@+
|
59
|
+
cmp $@+ $@ || mv $@+ $@
|
60
|
+
$(RM) $@+
|
61
|
+
|
62
|
+
doc: .document .wrongdoc.yml
|
63
|
+
find lib ext -type f -name '*.rbc' -exec rm -f '{}' ';'
|
64
|
+
$(RM) -r doc
|
65
|
+
wrongdoc all
|
66
|
+
install -m644 COPYING doc/COPYING
|
67
|
+
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
68
|
+
|
69
|
+
ifneq ($(VERSION),)
|
70
|
+
pkggem := pkg/$(rfpackage)-$(VERSION).gem
|
71
|
+
pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
|
72
|
+
release_notes := release_notes-$(VERSION)
|
73
|
+
release_changes := release_changes-$(VERSION)
|
74
|
+
|
75
|
+
release-notes: $(release_notes)
|
76
|
+
release-changes: $(release_changes)
|
77
|
+
$(release_changes):
|
78
|
+
wrongdoc release_changes > $@+
|
79
|
+
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
80
|
+
$(release_notes):
|
81
|
+
wrongdoc release_notes > $@+
|
82
|
+
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
83
|
+
|
84
|
+
# ensures we're actually on the tagged $(VERSION), only used for release
|
85
|
+
verify:
|
86
|
+
test x"$(shell umask)" = x0022
|
87
|
+
git rev-parse --verify refs/tags/v$(VERSION)^{}
|
88
|
+
git diff-index --quiet HEAD^0
|
89
|
+
test $$(git rev-parse --verify HEAD^0) = \
|
90
|
+
$$(git rev-parse --verify refs/tags/v$(VERSION)^{})
|
91
|
+
|
92
|
+
fix-perms:
|
93
|
+
-git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
|
94
|
+
-git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
|
95
|
+
|
96
|
+
gem: $(pkggem)
|
97
|
+
|
98
|
+
install-gem: $(pkggem)
|
99
|
+
gem install $(CURDIR)/$<
|
100
|
+
|
101
|
+
$(pkggem): manifest fix-perms
|
102
|
+
gem build $(rfpackage).gemspec
|
103
|
+
mkdir -p pkg
|
104
|
+
mv $(@F) $@
|
105
|
+
|
106
|
+
$(pkgtgz): distdir = $(basename $@)
|
107
|
+
$(pkgtgz): HEAD = v$(VERSION)
|
108
|
+
$(pkgtgz): manifest fix-perms
|
109
|
+
@test -n "$(distdir)"
|
110
|
+
$(RM) -r $(distdir)
|
111
|
+
mkdir -p $(distdir)
|
112
|
+
tar cf - $$(cat .manifest) | (cd $(distdir) && tar xf -)
|
113
|
+
cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
|
114
|
+
mv $@+ $@
|
115
|
+
|
116
|
+
package: $(pkgtgz) $(pkggem)
|
117
|
+
|
118
|
+
test-release:: verify package $(release_notes) $(release_changes)
|
119
|
+
# make tgz release on RubyForge
|
120
|
+
@echo rubyforge add_release -f \
|
121
|
+
-n $(release_notes) -a $(release_changes) \
|
122
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
|
123
|
+
@echo gem push $(pkggem)
|
124
|
+
@echo rubyforge add_file \
|
125
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
126
|
+
release:: verify package $(release_notes) $(release_changes)
|
127
|
+
# make tgz release on RubyForge
|
128
|
+
rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
|
129
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
|
130
|
+
# push gem to RubyGems.org
|
131
|
+
gem push $(pkggem)
|
132
|
+
# in case of gem downloads from RubyForge releases page
|
133
|
+
rubyforge add_file \
|
134
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
135
|
+
else
|
136
|
+
gem install-gem: GIT-VERSION-FILE
|
137
|
+
$(MAKE) $@ VERSION=$(GIT_VERSION)
|
138
|
+
endif
|
139
|
+
|
140
|
+
all:: test
|
141
|
+
test_units := $(wildcard test/test_*.rb)
|
142
|
+
test: test-unit
|
143
|
+
test-unit: $(test_units)
|
144
|
+
$(test_units): build
|
145
|
+
$(RUBY) -I $(lib) $@
|
146
|
+
|
147
|
+
# this requires GNU coreutils variants
|
148
|
+
ifneq ($(RSYNC_DEST),)
|
149
|
+
publish_doc:
|
150
|
+
-git set-file-times
|
151
|
+
$(MAKE) doc
|
152
|
+
find doc/images -type f | \
|
153
|
+
TZ=UTC xargs touch -d '1970-01-01 00:00:06' doc/rdoc.css
|
154
|
+
$(MAKE) doc_gz
|
155
|
+
$(RSYNC) -av doc/ $(RSYNC_DEST)/
|
156
|
+
git ls-files | xargs touch
|
157
|
+
endif
|
158
|
+
|
159
|
+
# Create gzip variants of the same timestamp as the original so nginx
|
160
|
+
# "gzip_static on" can serve the gzipped versions directly.
|
161
|
+
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
162
|
+
doc_gz:
|
163
|
+
for i in $(docs); do \
|
164
|
+
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
165
|
+
|
166
|
+
.PHONY: all .FORCE-GIT-VERSION-FILE doc test $(test_units) manifest
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# scripts/Makefiles can read and eval the output of this script and
|
3
|
+
# use it as RUBYLIB
|
4
|
+
require 'rubygems'
|
5
|
+
require 'isolate'
|
6
|
+
fp = File.open(__FILE__, "rb")
|
7
|
+
fp.flock(File::LOCK_EX)
|
8
|
+
|
9
|
+
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
10
|
+
opts = {
|
11
|
+
:system => false,
|
12
|
+
# we want "ruby-1.8.7" and not "ruby-1.8", so disable :multiruby
|
13
|
+
:multiruby => false,
|
14
|
+
:path => "tmp/isolate/#{ruby_engine}-#{RUBY_VERSION}",
|
15
|
+
}
|
16
|
+
|
17
|
+
pid = fork do
|
18
|
+
Isolate.now!(opts) do
|
19
|
+
gem 'strace_me', '1.0.0'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
_, status = Process.waitpid2(pid)
|
23
|
+
status.success? or abort status.inspect
|
24
|
+
lib_paths = Dir["#{opts[:path]}/gems/*-*/{lib,ext}"]
|
25
|
+
lib_paths.map! { |x| File.expand_path(x) }
|
26
|
+
dst = "tmp/isolate/#{ruby_engine}-#{RUBY_VERSION}/isolate.mk"
|
27
|
+
File.open("#{dst}.#$$", "w") do |fp|
|
28
|
+
fp.puts "ISOLATE_LIBS=#{lib_paths.join(':')}"
|
29
|
+
end
|
30
|
+
File.rename("#{dst}.#$$", dst)
|
data/sleepy_penguin.gemspec
CHANGED
@@ -7,7 +7,7 @@ name, summary, title = readme_metadata
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = %q{sleepy_penguin}
|
9
9
|
s.version = ENV["VERSION"].dup
|
10
|
-
s.homepage =
|
10
|
+
s.homepage = Wrongdoc.config[:rdoc_url]
|
11
11
|
s.authors = ["#{name} hackers"]
|
12
12
|
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
13
13
|
s.description = readme_description
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.test_files = Dir['test/test_*.rb']
|
22
22
|
s.extensions = %w(ext/sleepy_penguin/extconf.rb)
|
23
23
|
s.add_development_dependency('wrongdoc', '~> 1.3')
|
24
|
+
s.add_development_dependency('strace_me', '~> 1.0')
|
24
25
|
|
25
26
|
# s.license = %w(LGPL) # disabled for compatibility with older RubyGems
|
26
27
|
end
|
data/test/test_epoll.rb
CHANGED
@@ -154,6 +154,8 @@ class TestEpoll < Test::Unit::TestCase
|
|
154
154
|
end
|
155
155
|
|
156
156
|
def test_rdhup
|
157
|
+
defined?(Epoll::RDHUP) or
|
158
|
+
return warn "skipping test, EPOLLRDHUP not available"
|
157
159
|
rd, wr = UNIXSocket.pair
|
158
160
|
@ep.add rd, Epoll::RDHUP
|
159
161
|
tmp = []
|
@@ -318,7 +320,35 @@ class TestEpoll < Test::Unit::TestCase
|
|
318
320
|
assert_nil @ep.delete(@rd)
|
319
321
|
assert_nil @ep.delete(@wr)
|
320
322
|
assert_nothing_raised { @ep.add @rd, Epoll::IN }
|
321
|
-
assert_equal
|
323
|
+
assert_equal @rd, @ep.delete(@rd)
|
322
324
|
assert_nil @ep.delete(@rd)
|
323
325
|
end
|
326
|
+
|
327
|
+
def test_io_for
|
328
|
+
@ep.add @rd, Epoll::IN
|
329
|
+
assert_equal @rd, @ep.io_for(@rd.fileno)
|
330
|
+
assert_equal @rd, @ep.io_for(@rd)
|
331
|
+
@ep.del @rd
|
332
|
+
assert_nil @ep.io_for(@rd.fileno)
|
333
|
+
assert_nil @ep.io_for(@rd)
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_flags_for
|
337
|
+
@ep.add @rd, Epoll::IN
|
338
|
+
assert_equal Epoll::IN, @ep.flags_for(@rd.fileno)
|
339
|
+
assert_equal Epoll::IN, @ep.flags_for(@rd)
|
340
|
+
|
341
|
+
@ep.del @rd
|
342
|
+
assert_nil @ep.flags_for(@rd.fileno)
|
343
|
+
assert_nil @ep.flags_for(@rd)
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_include?
|
347
|
+
assert ! @ep.include?(@rd)
|
348
|
+
@ep.add @rd, Epoll::IN
|
349
|
+
assert @ep.include?(@rd)
|
350
|
+
assert @ep.include?(@rd.fileno)
|
351
|
+
assert ! @ep.include?(@wr)
|
352
|
+
assert ! @ep.include?(@wr.fileno)
|
353
|
+
end
|
324
354
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'strace'
|
3
|
+
$-w = true
|
4
|
+
|
5
|
+
require 'sleepy_penguin'
|
6
|
+
|
7
|
+
class TestEpollOptimizations < Test::Unit::TestCase
|
8
|
+
include SleepyPenguin
|
9
|
+
RBX = defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'rbx')
|
10
|
+
IO_PURGATORY = []
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@rd, @wr = IO.pipe
|
14
|
+
@ep = Epoll.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
[ @ep, @rd, @wr ].each { |io| io.close unless io.closed? }
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_set
|
22
|
+
io, err = Strace.me do
|
23
|
+
@ep.set(@wr, Epoll::OUT)
|
24
|
+
@ep.set(@wr, Epoll::OUT)
|
25
|
+
end
|
26
|
+
assert_nil err
|
27
|
+
lines = io.readlines; io.close
|
28
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
29
|
+
assert_match /EPOLL_CTL_ADD/, lines.grep(/^epoll_ctl/)[0]
|
30
|
+
|
31
|
+
io, err = Strace.me { @ep.set(@wr, Epoll::OUT | Epoll::ONESHOT) }
|
32
|
+
assert_nil err
|
33
|
+
lines = io.readlines; io.close
|
34
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
35
|
+
assert_match /EPOLL_CTL_MOD/, lines.grep(/^epoll_ctl/)[0]
|
36
|
+
|
37
|
+
io, err = Strace.me { @ep.set(@wr, Epoll::OUT) }
|
38
|
+
assert_nil err
|
39
|
+
lines = io.readlines; io.close
|
40
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
41
|
+
assert_match /EPOLL_CTL_MOD/, lines.grep(/^epoll_ctl/)[0]
|
42
|
+
@wr.close
|
43
|
+
@rd.close
|
44
|
+
|
45
|
+
@rd, @wr = IO.pipe
|
46
|
+
io, err = Strace.me { @ep.set(@wr, Epoll::OUT) }
|
47
|
+
assert_nil err
|
48
|
+
lines = io.readlines; io.close
|
49
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
50
|
+
assert_match /EPOLL_CTL_ADD/, lines.grep(/^epoll_ctl/)[0]
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_delete
|
54
|
+
@ep.set(@wr, Epoll::OUT)
|
55
|
+
rv = true
|
56
|
+
io, err = Strace.me { rv = @ep.delete(@wr) }
|
57
|
+
assert_equal @wr, rv
|
58
|
+
assert_nil err
|
59
|
+
lines = io.readlines; io.close
|
60
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
61
|
+
assert_match %r{=\s+0$}, lines.grep(/^epoll_ctl/)[0]
|
62
|
+
|
63
|
+
rv = true
|
64
|
+
io, err = Strace.me { rv = @ep.delete(@wr) }
|
65
|
+
assert_nil rv
|
66
|
+
assert_nil err
|
67
|
+
lines = io.readlines; io.close
|
68
|
+
assert_equal 0, lines.grep(/^epoll_ctl/).size
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_delete_closed
|
72
|
+
a = @wr.fileno
|
73
|
+
@ep.set(@wr, Epoll::OUT)
|
74
|
+
@rd.close
|
75
|
+
@wr.close
|
76
|
+
@rd, @wr = IO.pipe
|
77
|
+
assert_equal a, @wr.fileno
|
78
|
+
rv = true
|
79
|
+
io, err = Strace.me { rv = @ep.delete(@wr) }
|
80
|
+
lines = io.readlines; io.close
|
81
|
+
assert_nil err
|
82
|
+
assert_nil rv
|
83
|
+
assert_equal 0, lines.grep(/^epoll_ctl/).size
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_delete_aliased_a
|
87
|
+
tmp = IO.for_fd @wr.fileno
|
88
|
+
IO_PURGATORY << tmp
|
89
|
+
@ep.set(tmp, Epoll::OUT)
|
90
|
+
rv = nil
|
91
|
+
io, err = Strace.me { rv = @ep.delete(@wr) }
|
92
|
+
lines = io.readlines; io.close
|
93
|
+
assert_equal @wr, rv
|
94
|
+
assert_nil err
|
95
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
96
|
+
assert_match %r{=\s+0$}, lines.grep(/^epoll_ctl/)[0]
|
97
|
+
assert_equal 0, lines.grep(/ENOENT/).size
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_delete_aliased_b
|
101
|
+
tmp = IO.for_fd @wr.fileno
|
102
|
+
IO_PURGATORY << tmp
|
103
|
+
@ep.set(@wr, Epoll::OUT)
|
104
|
+
rv = nil
|
105
|
+
io, err = Strace.me { rv = @ep.delete(tmp) }
|
106
|
+
lines = io.readlines; io.close
|
107
|
+
assert_equal tmp, rv
|
108
|
+
assert_nil err
|
109
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
110
|
+
assert_match %r{=\s+0$}, lines.grep(/^epoll_ctl/)[0]
|
111
|
+
assert_equal 0, lines.grep(/ENOENT/).size
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_delete_aliased_closed
|
115
|
+
tmp = IO.for_fd @wr.fileno
|
116
|
+
IO_PURGATORY << tmp
|
117
|
+
@ep.set(tmp, Epoll::OUT)
|
118
|
+
@wr.close
|
119
|
+
rv = nil
|
120
|
+
io, err = Strace.me { rv = @ep.delete(tmp) }
|
121
|
+
lines = io.readlines; io.close
|
122
|
+
assert_nil rv
|
123
|
+
assert_nil err
|
124
|
+
assert_equal 1, lines.grep(/^epoll_ctl/).size
|
125
|
+
assert_equal 1, lines.grep(/EBADF/).size
|
126
|
+
end
|
127
|
+
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: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 1.
|
10
|
+
version: 1.3.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-
|
18
|
+
date: 2011-01-21 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -33,6 +33,21 @@ dependencies:
|
|
33
33
|
version: "1.3"
|
34
34
|
type: :development
|
35
35
|
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: strace_me
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 15
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
version: "1.0"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
36
51
|
description: |-
|
37
52
|
sleepy_penguin provides access to newer, Linux-only system calls to wait
|
38
53
|
on events from traditionally non-I/O sources. Bindings to the eventfd,
|
@@ -78,10 +93,13 @@ files:
|
|
78
93
|
- ext/sleepy_penguin/timerfd.c
|
79
94
|
- ext/sleepy_penguin/value2timespec.h
|
80
95
|
- lib/sleepy_penguin.rb
|
96
|
+
- pkg.mk
|
97
|
+
- script/isolate_for_tests
|
81
98
|
- setup.rb
|
82
99
|
- sleepy_penguin.gemspec
|
83
100
|
- test/test_epoll.rb
|
84
101
|
- test/test_epoll_gc.rb
|
102
|
+
- test/test_epoll_optimizations.rb
|
85
103
|
- test/test_eventfd.rb
|
86
104
|
- test/test_timerfd.rb
|
87
105
|
has_rdoc: true
|
@@ -93,7 +111,7 @@ rdoc_options:
|
|
93
111
|
- -t
|
94
112
|
- sleepy_penguin - Linux I/O events for Ruby
|
95
113
|
- -W
|
96
|
-
- http://
|
114
|
+
- http://bogomips.org/sleepy_penguin.git/tree/%s
|
97
115
|
require_paths:
|
98
116
|
- lib
|
99
117
|
- ext
|
@@ -123,6 +141,7 @@ signing_key:
|
|
123
141
|
specification_version: 3
|
124
142
|
summary: Linux I/O events for Ruby
|
125
143
|
test_files:
|
144
|
+
- test/test_epoll_optimizations.rb
|
126
145
|
- test/test_epoll.rb
|
127
146
|
- test/test_eventfd.rb
|
128
147
|
- test/test_epoll_gc.rb
|