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 CHANGED
@@ -19,3 +19,4 @@ pkg/
19
19
  tags
20
20
  TAGS
21
21
  /LATEST
22
+ /tmp
data/.wrongdoc.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- cgit_url: http://git.bogomips.org/cgit/sleepy_penguin.git
3
- git_url: git://git.bogomips.org/sleepy_penguin.git
2
+ cgit_url: http://bogomips.org/sleepy_penguin.git
3
+ git_url: git://bogomips.org/sleepy_penguin.git
4
4
  rdoc_url: http://bogomips.org/sleepy_penguin/
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v1.2.0.GIT
4
+ DEF_VER=v1.3.0.GIT
5
5
 
6
6
  LF='
7
7
  '
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
- RUBY = ruby
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
- pkggem := pkg/$(rfpackage)-$(VERSION).gem
56
- pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
57
- release_notes := release_notes-$(VERSION)
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://git.bogomips.org/sleepy_penguin.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://git.bogomips.org/cgit/sleepy_penguin.git (cgit)
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
- cgit_url = "http://git.bogomips.org/cgit/sleepy_penguin.git"
3
- git_url = 'git://git.bogomips.org/sleepy_penguin.git'
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
@@ -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 = rb_ary_new();
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 +Epoll::CLOEXEC+ or 0 (or nil)
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
- if (op == EPOLL_CTL_ADD)
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
- rv = epoll_ctl(ep->fd, EPOLL_CTL_MOD, fd, &event);
229
- if (rv == -1) {
230
- if (errno == ENOENT) {
231
- rv = epoll_ctl(ep->fd, EPOLL_CTL_ADD, fd, &event);
232
- if (rv == -1)
233
- rb_sys_fail("epoll_ctl - add");
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
- rb_ary_store(ep->marks, fd, io);
236
- return INT2NUM(rv);
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
- rb_sys_fail("epoll_ctl - mod");
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
- if (errno != ENOENT)
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
- errno = 0;
262
- return Qnil;
309
+ }
263
310
  }
264
- return INT2NUM(rv);
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 NUM2INT(io);
46
+ case T_FIXNUM: return FIX2INT(io);
35
47
  case T_FILE:
36
48
  GetOpenFile(io, fptr);
37
49
  return FPTR_TO_FD(fptr);
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: binary -*-
2
2
  module SleepyPenguin
3
3
 
4
- # the version of sleepy_penguin, currently 1.2.0
5
- SLEEPY_PENGUIN_VERSION = '1.2.0'
4
+ # the version of sleepy_penguin, currently 1.3.0
5
+ SLEEPY_PENGUIN_VERSION = '1.3.0'
6
6
  end
7
7
  require 'sleepy_penguin_ext'
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)
@@ -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 = 'http://bogomips.org/sleepy_penguin/'
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 0, @ep.delete(@rd)
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: 31
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 1.2.0
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-15 00:00:00 +00:00
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://git.bogomips.org/cgit/sleepy_penguin.git/tree/%s
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