sleepy_penguin 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.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