sleepy_penguin 3.1.0.26.g7181 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +1 -0
- data/.gitignore +1 -0
- data/GIT-VERSION-GEN +8 -1
- data/GNUmakefile +1 -0
- data/README +6 -4
- data/ext/sleepy_penguin/epoll.c +11 -12
- data/ext/sleepy_penguin/extconf.rb +5 -1
- data/ext/sleepy_penguin/init.c +19 -0
- data/ext/sleepy_penguin/kqueue.c +675 -0
- data/ext/sleepy_penguin/sleepy_penguin.h +12 -0
- data/ext/sleepy_penguin/value2timespec.h +1 -1
- data/lib/sleepy_penguin.rb +0 -6
- data/lib/sleepy_penguin/epoll.rb +29 -24
- data/lib/sleepy_penguin/kevent.rb +7 -0
- data/lib/sleepy_penguin/kqueue.rb +122 -0
- data/lib/sleepy_penguin/kqueue/io.rb +30 -0
- data/pkg.mk +1 -1
- data/test/test_constants.rb +16 -0
- data/test/test_epoll.rb +37 -52
- data/test/test_epoll_io.rb +13 -2
- data/test/test_epoll_optimizations.rb +0 -1
- data/test/test_inotify.rb +1 -1
- data/test/test_kqueue.rb +75 -0
- data/test/test_kqueue_io.rb +114 -0
- data/test/test_timerfd.rb +2 -2
- metadata +30 -16
- data/test/test_epoll_gc_per_thread.rb +0 -23
@@ -77,4 +77,16 @@ static inline VALUE fake_blocking_region(VALUE (*fn)(void *), void *data)
|
|
77
77
|
|
78
78
|
typedef int rb_sp_waitfn(int fd);
|
79
79
|
int rb_sp_wait(rb_sp_waitfn waiter, VALUE obj, int *fd);
|
80
|
+
|
81
|
+
/* Flexible array elements are standard in C99 */
|
82
|
+
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
83
|
+
# define FLEX_ARRAY
|
84
|
+
#elif defined(__GNUC__)
|
85
|
+
# if (__GNUC__ >= 3)
|
86
|
+
# define FLEX_ARRAY
|
87
|
+
# else
|
88
|
+
# define FLEX_ARRAY 0
|
89
|
+
# endif
|
90
|
+
#endif
|
91
|
+
|
80
92
|
#endif /* SLEEPY_PENGUIN_H */
|
@@ -53,7 +53,7 @@ static struct timespec *value2timespec(struct timespec *ts, VALUE num)
|
|
53
53
|
# define TIMET2NUM(n) LONG2NUM(n)
|
54
54
|
#endif
|
55
55
|
|
56
|
-
static VALUE timespec2num(struct timespec *ts)
|
56
|
+
static inline VALUE timespec2num(struct timespec *ts)
|
57
57
|
{
|
58
58
|
if (ts->tv_nsec == 0)
|
59
59
|
return TIMET2NUM(ts->tv_sec);
|
data/lib/sleepy_penguin.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
module SleepyPenguin
|
3
|
-
|
4
|
-
# the version of sleepy_penguin, currently 3.1.0
|
5
|
-
SLEEPY_PENGUIN_VERSION = '3.1.0'
|
6
|
-
end
|
7
2
|
require 'sleepy_penguin_ext'
|
8
|
-
require 'sleepy_penguin/epoll'
|
9
3
|
|
10
4
|
# We need to serialize Inotify#take for Rubinius since that has no GVL
|
11
5
|
# to protect the internal array
|
data/lib/sleepy_penguin/epoll.rb
CHANGED
@@ -1,45 +1,50 @@
|
|
1
1
|
require 'thread'
|
2
2
|
class SleepyPenguin::Epoll
|
3
3
|
|
4
|
-
# Epoll objects may be watched by IO.select and similar methods
|
5
|
-
attr_reader :to_io
|
6
|
-
|
7
4
|
# call-seq:
|
8
5
|
# SleepyPenguin::Epoll.new([flags]) -> Epoll object
|
9
6
|
#
|
10
7
|
# Creates a new Epoll object with an optional +flags+ argument.
|
11
8
|
# +flags+ may currently be +:CLOEXEC+ or +0+ (or +nil+).
|
12
9
|
def initialize(create_flags = nil)
|
13
|
-
@
|
10
|
+
@io = SleepyPenguin::Epoll::IO.new(create_flags)
|
14
11
|
@mtx = Mutex.new
|
15
12
|
@events = []
|
16
13
|
@marks = []
|
17
14
|
@pid = $$
|
18
15
|
@create_flags = create_flags
|
19
|
-
@copies = { @
|
16
|
+
@copies = { @io => self }
|
20
17
|
end
|
21
18
|
|
22
19
|
def __ep_reinit # :nodoc:
|
23
20
|
@events.clear
|
24
21
|
@marks.clear
|
25
|
-
@
|
22
|
+
@io = SleepyPenguin::Epoll::IO.new(@create_flags)
|
26
23
|
end
|
27
24
|
|
28
25
|
# auto-reinitialize the Epoll object after forking
|
29
26
|
def __ep_check # :nodoc:
|
30
27
|
return if @pid == $$
|
31
|
-
return if @
|
28
|
+
return if @io.closed?
|
32
29
|
objects = @copies.values
|
33
30
|
@copies.each_key { |epio| epio.close }
|
34
31
|
@copies.clear
|
35
32
|
__ep_reinit
|
36
33
|
objects.each do |obj|
|
37
|
-
io_dup = @
|
34
|
+
io_dup = @io.dup
|
38
35
|
@copies[io_dup] = obj
|
39
36
|
end
|
40
37
|
@pid = $$
|
41
38
|
end
|
42
39
|
|
40
|
+
# Epoll objects may be watched by IO.select and similar methods
|
41
|
+
def to_io
|
42
|
+
@mtx.synchronize do
|
43
|
+
__ep_check
|
44
|
+
@io
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
43
48
|
# Calls epoll_wait(2) and yields Integer +events+ and IO objects watched
|
44
49
|
# for. +maxevents+ is the maximum number of events to process at once,
|
45
50
|
# lower numbers may prevent starvation when used by epoll_wait in multiple
|
@@ -59,10 +64,10 @@ class SleepyPenguin::Epoll
|
|
59
64
|
# we keep a snapshot of @marks around in case another thread closes
|
60
65
|
# the IO while it is being transferred to userspace. We release mtx
|
61
66
|
# so another thread may add events to us while we're sleeping.
|
62
|
-
@
|
67
|
+
@io.epoll_wait(maxevents, timeout) { |events, io| yield(events, io) }
|
63
68
|
ensure
|
64
69
|
# hopefully Ruby does not optimize this array away...
|
65
|
-
snapshot
|
70
|
+
snapshot.clear
|
66
71
|
end
|
67
72
|
|
68
73
|
# Starts watching a given +io+ object with +events+ which may be an Integer
|
@@ -72,7 +77,7 @@ class SleepyPenguin::Epoll
|
|
72
77
|
events = __event_flags(events)
|
73
78
|
@mtx.synchronize do
|
74
79
|
__ep_check
|
75
|
-
@
|
80
|
+
@io.epoll_ctl(CTL_ADD, io, events)
|
76
81
|
@events[fd] = events
|
77
82
|
@marks[fd] = io
|
78
83
|
end
|
@@ -87,7 +92,7 @@ class SleepyPenguin::Epoll
|
|
87
92
|
fd = io.to_io.fileno
|
88
93
|
@mtx.synchronize do
|
89
94
|
__ep_check
|
90
|
-
@
|
95
|
+
@io.epoll_ctl(CTL_DEL, io, 0)
|
91
96
|
@events[fd] = @marks[fd] = nil
|
92
97
|
end
|
93
98
|
0
|
@@ -110,7 +115,7 @@ class SleepyPenguin::Epoll
|
|
110
115
|
__ep_check
|
111
116
|
cur_io = @marks[fd]
|
112
117
|
return if nil == cur_io || cur_io.to_io.closed?
|
113
|
-
@
|
118
|
+
@io.epoll_ctl(CTL_DEL, io, 0)
|
114
119
|
@events[fd] = @marks[fd] = nil
|
115
120
|
end
|
116
121
|
io
|
@@ -127,7 +132,7 @@ class SleepyPenguin::Epoll
|
|
127
132
|
fd = io.to_io.fileno
|
128
133
|
@mtx.synchronize do
|
129
134
|
__ep_check
|
130
|
-
@
|
135
|
+
@io.epoll_ctl(CTL_MOD, io, events)
|
131
136
|
@marks[fd] = io # may be a different object with same fd/file
|
132
137
|
@events[fd] = events
|
133
138
|
end
|
@@ -159,18 +164,18 @@ class SleepyPenguin::Epoll
|
|
159
164
|
cur_events = @events[fd]
|
160
165
|
return 0 if (cur_events & ONESHOT) == 0 && cur_events == events
|
161
166
|
begin
|
162
|
-
@
|
167
|
+
@io.epoll_ctl(CTL_MOD, io, events)
|
163
168
|
rescue Errno::ENOENT
|
164
169
|
warn "epoll event cache failed (mod -> add)"
|
165
|
-
@
|
170
|
+
@io.epoll_ctl(CTL_ADD, io, events)
|
166
171
|
@marks[fd] = io
|
167
172
|
end
|
168
173
|
else
|
169
174
|
begin
|
170
|
-
@
|
175
|
+
@io.epoll_ctl(CTL_ADD, io, events)
|
171
176
|
rescue Errno::EEXIST
|
172
177
|
warn "epoll event cache failed (add -> mod)"
|
173
|
-
@
|
178
|
+
@io.epoll_ctl(CTL_MOD, io, events)
|
174
179
|
end
|
175
180
|
@marks[fd] = io
|
176
181
|
end
|
@@ -186,8 +191,8 @@ class SleepyPenguin::Epoll
|
|
186
191
|
# Raises IOError if object is already closed.
|
187
192
|
def close
|
188
193
|
@mtx.synchronize do
|
189
|
-
@copies.delete(@
|
190
|
-
@
|
194
|
+
@copies.delete(@io)
|
195
|
+
@io.close
|
191
196
|
end
|
192
197
|
end
|
193
198
|
|
@@ -197,7 +202,7 @@ class SleepyPenguin::Epoll
|
|
197
202
|
# Returns whether or not an Epoll object is closed.
|
198
203
|
def closed?
|
199
204
|
@mtx.synchronize do
|
200
|
-
@
|
205
|
+
@io.closed?
|
201
206
|
end
|
202
207
|
end
|
203
208
|
|
@@ -254,9 +259,9 @@ class SleepyPenguin::Epoll
|
|
254
259
|
@mtx.synchronize do
|
255
260
|
__ep_check
|
256
261
|
rv = super
|
257
|
-
unless @
|
258
|
-
@
|
259
|
-
@copies[@
|
262
|
+
unless @io.closed?
|
263
|
+
@io = @io.dup
|
264
|
+
@copies[@io] = self
|
260
265
|
end
|
261
266
|
rv
|
262
267
|
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# This class represents a "struct kevent" structure for Ruby.
|
2
|
+
# This may be passed to Kqueue::IO#kevent as either a single element
|
3
|
+
# or as an element inside an array to inject changes into the kevent
|
4
|
+
# list.
|
5
|
+
class SleepyPenguin::Kevent < Struct.new(:ident, :filter, :flags,
|
6
|
+
:fflags, :data, :udata)
|
7
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
# The high-level Kqueue interface. This provides fork-safety under Ruby 1.9
|
4
|
+
# and later (but not Ruby 1.8).
|
5
|
+
# This also provides memory protection from bugs due to not storing an
|
6
|
+
# external reference to an object, but still requires the user to store
|
7
|
+
# their own object references.
|
8
|
+
# Events registered to a Kqueue object cannot be shared across fork
|
9
|
+
# due to the underlying implementation of kqueue in *BSDs.
|
10
|
+
class SleepyPenguin::Kqueue
|
11
|
+
|
12
|
+
# Initialize a new Kqueue object, this allocates an underlying Kqueue::IO
|
13
|
+
# object and may fail if the system is out of file descriptors or
|
14
|
+
# kernel memory
|
15
|
+
def initialize
|
16
|
+
@io = SleepyPenguin::Kqueue::IO.new
|
17
|
+
@mtx = Mutex.new
|
18
|
+
@pid = $$
|
19
|
+
@copies = { @io => self }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Kqueue objects may be watched by IO.select and similar methods
|
23
|
+
def to_io
|
24
|
+
@mtx.synchronize do
|
25
|
+
__kq_check
|
26
|
+
@io
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def __kq_reinit # :nodoc:
|
31
|
+
@io = SleepyPenguin::Kqueue::IO.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def __kq_check # :nodoc:
|
35
|
+
return if @pid == $$ || @io.closed?
|
36
|
+
unless @io.respond_to?(:autoclose=)
|
37
|
+
raise RuntimeError,
|
38
|
+
"Kqueue is not safe to use without IO#autoclose=, upgrade to Ruby 1.9+"
|
39
|
+
end
|
40
|
+
|
41
|
+
# kqueue has (strange) close-on-fork behavior
|
42
|
+
objects = @copies.values
|
43
|
+
@copies.each_key { |kqio| kqio.autoclose = false }
|
44
|
+
@copies.clear
|
45
|
+
__kq_reinit
|
46
|
+
objects.each do |obj|
|
47
|
+
io_dup = @io.dup
|
48
|
+
@copies[io_dup] = obj
|
49
|
+
end
|
50
|
+
@pid = $$
|
51
|
+
end
|
52
|
+
|
53
|
+
# A high-level wrapper around Kqueue::IO#kevent
|
54
|
+
# Users are responsible for ensuring +udata+ objects remain visible to the
|
55
|
+
# Ruby GC, otherwise ObjectSpace._id2ref may return invalid objects.
|
56
|
+
# Unlike the low-level Kqueue::IO#kevent, the block given yields only
|
57
|
+
# a single Kevent struct, not a 6-element array.
|
58
|
+
def kevent(changelist = nil, *args)
|
59
|
+
@mtx.synchronize { __kq_check }
|
60
|
+
if changelist
|
61
|
+
changelist = [ changelist ] if Struct === changelist
|
62
|
+
|
63
|
+
# store the object_id instead of the raw VALUE itself in kqueue and
|
64
|
+
# use _id2ref to safely recover the object without the possibility of
|
65
|
+
# invalid memory acccess.
|
66
|
+
#
|
67
|
+
# We may still raise and drop events due to user error
|
68
|
+
changelist = changelist.map do |item|
|
69
|
+
item = item.dup
|
70
|
+
item[5] = item[5].object_id
|
71
|
+
item
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if block_given?
|
76
|
+
n = @io.kevent(changelist, *args) do |ident,filter,flags,
|
77
|
+
fflags,data,udata|
|
78
|
+
# This may raise and cause events to be lost,
|
79
|
+
# that's the users' fault/problem
|
80
|
+
udata = ObjectSpace._id2ref(udata)
|
81
|
+
yield SleepyPenguin::Kevent.new(ident, filter, flags,
|
82
|
+
fflags, data, udata)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
n = @io.kevent(changelist, *args)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def initialize_copy(src) # :nodoc:
|
90
|
+
@mtx.synchronize do
|
91
|
+
__kq_check
|
92
|
+
rv = super
|
93
|
+
unless @io.closed?
|
94
|
+
@io = @io.dup
|
95
|
+
@copies[@io] = self
|
96
|
+
end
|
97
|
+
rv
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# call-seq:
|
102
|
+
# kq.close -> nil
|
103
|
+
#
|
104
|
+
# Closes an existing Kqueue object and returns memory back to the kernel.
|
105
|
+
# Raises IOError if object is already closed.
|
106
|
+
def close
|
107
|
+
@mtx.synchronize do
|
108
|
+
@copies.delete(@io)
|
109
|
+
@io.close
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# call-seq:
|
114
|
+
# kq.closed? -> true or false
|
115
|
+
#
|
116
|
+
# Returns whether or not an Kqueue object is closed.
|
117
|
+
def closed?
|
118
|
+
@mtx.synchronize do
|
119
|
+
@io.closed?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class SleepyPenguin::Kqueue::IO
|
2
|
+
# :stopdoc:
|
3
|
+
# this file is only for Ruby 1.8 green threads compatibility
|
4
|
+
alias __kevent kevent
|
5
|
+
undef_method :kevent
|
6
|
+
|
7
|
+
def __update_timeout(expire_at)
|
8
|
+
now = Time.now
|
9
|
+
diff = expire_at - now
|
10
|
+
diff > 0 ? diff : 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def kevent(changelist = nil, nevents = nil, timeout = nil)
|
14
|
+
if block_given?
|
15
|
+
expire_at = timeout ? Time.now + timeout : nil
|
16
|
+
begin
|
17
|
+
IO.select([self], nil, nil, timeout)
|
18
|
+
n = __kevent(changelist, nevents, 0) do |*args|
|
19
|
+
yield(*args)
|
20
|
+
end
|
21
|
+
end while n == 0 && timeout != 0 &&
|
22
|
+
(expire_at == nil || timeout = __update_timeout(expire_at))
|
23
|
+
n
|
24
|
+
else
|
25
|
+
# nevents should be zero or nil here
|
26
|
+
__kevent(changelist, nevents, 0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# :startdoc:
|
30
|
+
end
|
data/pkg.mk
CHANGED
@@ -36,7 +36,7 @@ $(ext_pfx)/$(ext)/%: $(ext)/% $(ext_d)
|
|
36
36
|
install -m 644 $< $@
|
37
37
|
$(ext_pfx)/$(ext)/Makefile: $(ext)/extconf.rb $(ext_d) $(ext_h)
|
38
38
|
$(RM) -f $(@D)/*.o
|
39
|
-
cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb
|
39
|
+
cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb $(EXTCONF_ARGS)
|
40
40
|
ext_sfx := _ext.$(DLEXT)
|
41
41
|
ext_dl := $(ext_pfx)/$(ext)/$(notdir $(ext)_ext.$(DLEXT))
|
42
42
|
$(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
$-w = true
|
3
|
+
Thread.abort_on_exception = true
|
4
|
+
require 'sleepy_penguin/sp'
|
5
|
+
|
6
|
+
class TestConstants < Test::Unit::TestCase
|
7
|
+
def test_constants
|
8
|
+
assert_equal SleepyPenguin::SLEEPY_PENGUIN_VERSION,
|
9
|
+
SP::SLEEPY_PENGUIN_VERSION
|
10
|
+
v = SP::SLEEPY_PENGUIN_VERSION.split('.')
|
11
|
+
|
12
|
+
(0..2).each do |i|
|
13
|
+
assert_equal v[i], v[i].to_i.to_s, v.inspect
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/test/test_epoll.rb
CHANGED
@@ -9,7 +9,6 @@ require 'sleepy_penguin'
|
|
9
9
|
|
10
10
|
class TestEpoll < Test::Unit::TestCase
|
11
11
|
include SleepyPenguin
|
12
|
-
RBX = defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'rbx')
|
13
12
|
|
14
13
|
def setup
|
15
14
|
@rd, @wr = IO.pipe
|
@@ -122,11 +121,9 @@ class TestEpoll < Test::Unit::TestCase
|
|
122
121
|
end
|
123
122
|
|
124
123
|
def teardown
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
@ep.close unless @ep.closed?
|
129
|
-
end
|
124
|
+
@rd.close unless @rd.closed?
|
125
|
+
@wr.close unless @wr.closed?
|
126
|
+
@ep.close unless @ep.closed?
|
130
127
|
end
|
131
128
|
|
132
129
|
def test_max_events_big
|
@@ -156,11 +153,17 @@ class TestEpoll < Test::Unit::TestCase
|
|
156
153
|
end
|
157
154
|
|
158
155
|
def test_signal_safe_wait_forever
|
156
|
+
sigpipe = IO.pipe
|
159
157
|
time = {}
|
158
|
+
thr = Thread.new do
|
159
|
+
IO.select([sigpipe[0]]) # wait for USR1
|
160
|
+
sigpipe[0].read(1)
|
161
|
+
sleep 0.5
|
162
|
+
@wr.syswrite '.'
|
163
|
+
end
|
160
164
|
trap(:USR1) do
|
161
165
|
time[:USR1] = Time.now
|
162
|
-
|
163
|
-
@wr.write '.'
|
166
|
+
sigpipe[1].syswrite('.') # wake up thr
|
164
167
|
end
|
165
168
|
@ep.add @rd, Epoll::IN
|
166
169
|
tmp = []
|
@@ -170,11 +173,9 @@ class TestEpoll < Test::Unit::TestCase
|
|
170
173
|
exit!(0)
|
171
174
|
end
|
172
175
|
time[:START_WAIT] = Time.now
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
time[:EP] = Time.now
|
177
|
-
end
|
176
|
+
@ep.wait do |flags, obj|
|
177
|
+
tmp << [ flags, obj ]
|
178
|
+
time[:EP] = Time.now
|
178
179
|
end
|
179
180
|
assert_equal([[Epoll::IN, @rd]], tmp)
|
180
181
|
_, status = Process.waitpid2(pid)
|
@@ -183,9 +184,12 @@ class TestEpoll < Test::Unit::TestCase
|
|
183
184
|
assert_in_delta(0.5, usr1_delay, 0.1, "usr1_delay=#{usr1_delay}")
|
184
185
|
ep_delay = time[:EP] - time[:USR1]
|
185
186
|
assert_in_delta(0.5, ep_delay, 0.1, "ep1_delay=#{ep_delay}")
|
187
|
+
assert_kind_of Thread, thr
|
188
|
+
thr.join
|
186
189
|
ensure
|
190
|
+
sigpipe.each { |io| io.close }
|
187
191
|
trap(:USR1, 'DEFAULT')
|
188
|
-
end
|
192
|
+
end
|
189
193
|
|
190
194
|
def test_close
|
191
195
|
@ep.add @rd, Epoll::IN
|
@@ -193,10 +197,12 @@ class TestEpoll < Test::Unit::TestCase
|
|
193
197
|
thr = Thread.new { @ep.wait { |flags, obj| tmp << [ flags, obj ] } }
|
194
198
|
@rd.close
|
195
199
|
@wr.close
|
196
|
-
|
200
|
+
Thread.pass
|
201
|
+
assert_nil thr.join(0.25)
|
197
202
|
assert thr.alive?
|
198
203
|
thr.kill
|
199
204
|
assert tmp.empty?
|
205
|
+
thr.join
|
200
206
|
end
|
201
207
|
|
202
208
|
def test_rdhup
|
@@ -222,12 +228,10 @@ class TestEpoll < Test::Unit::TestCase
|
|
222
228
|
|
223
229
|
def test_multiple
|
224
230
|
r, w = IO.pipe
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
@ep.add @wr, Epoll::OUT
|
230
|
-
end
|
231
|
+
@ep.add r, Epoll::IN
|
232
|
+
@ep.add @rd, Epoll::IN
|
233
|
+
@ep.add w, Epoll::OUT
|
234
|
+
@ep.add @wr, Epoll::OUT
|
231
235
|
tmp = []
|
232
236
|
@ep.wait { |flags, obj| tmp << [ flags, obj ] }
|
233
237
|
assert_equal 2, tmp.size
|
@@ -237,21 +241,6 @@ class TestEpoll < Test::Unit::TestCase
|
|
237
241
|
assert ios.include?(w)
|
238
242
|
end
|
239
243
|
|
240
|
-
def test_gc
|
241
|
-
assert_nothing_raised { 4096.times { Epoll.new } }
|
242
|
-
assert ! @ep.closed?
|
243
|
-
end unless RBX
|
244
|
-
|
245
|
-
def test_gc_to_io
|
246
|
-
assert_nothing_raised do
|
247
|
-
4096.times do
|
248
|
-
ep = Epoll.new
|
249
|
-
assert_kind_of IO, ep.to_io
|
250
|
-
end
|
251
|
-
end
|
252
|
-
assert ! @ep.closed?
|
253
|
-
end unless RBX
|
254
|
-
|
255
244
|
def test_clone
|
256
245
|
tmp = []
|
257
246
|
clone = @ep.clone
|
@@ -259,7 +248,7 @@ class TestEpoll < Test::Unit::TestCase
|
|
259
248
|
clone.add @wr, Epoll::OUT
|
260
249
|
@ep.wait(nil, 0) { |flags, obj| tmp << [ flags, obj ] }
|
261
250
|
assert_equal([[Epoll::OUT, @wr]], tmp)
|
262
|
-
|
251
|
+
clone.close
|
263
252
|
end
|
264
253
|
|
265
254
|
def test_dup
|
@@ -269,16 +258,14 @@ class TestEpoll < Test::Unit::TestCase
|
|
269
258
|
clone.add @wr, Epoll::OUT
|
270
259
|
@ep.wait(nil, 0) { |flags, obj| tmp << [ flags, obj ] }
|
271
260
|
assert_equal([[Epoll::OUT, @wr]], tmp)
|
272
|
-
|
261
|
+
clone.close
|
273
262
|
end
|
274
263
|
|
275
264
|
def test_set_idempotency
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
@ep.set @wr, Epoll::OUT
|
281
|
-
end
|
265
|
+
@ep.set @rd, Epoll::IN
|
266
|
+
@ep.set @rd, Epoll::IN
|
267
|
+
@ep.set @wr, Epoll::OUT
|
268
|
+
@ep.set @wr, Epoll::OUT
|
282
269
|
end
|
283
270
|
|
284
271
|
def test_wait_timeout
|
@@ -290,10 +277,8 @@ class TestEpoll < Test::Unit::TestCase
|
|
290
277
|
|
291
278
|
def test_del
|
292
279
|
assert_raises(Errno::ENOENT) { @ep.del(@rd) }
|
293
|
-
|
294
|
-
|
295
|
-
@ep.del(@rd)
|
296
|
-
end
|
280
|
+
@ep.add(@rd, Epoll::IN)
|
281
|
+
@ep.del(@rd)
|
297
282
|
end
|
298
283
|
|
299
284
|
def test_wait_read
|
@@ -368,7 +353,7 @@ class TestEpoll < Test::Unit::TestCase
|
|
368
353
|
def test_delete
|
369
354
|
assert_nil @ep.delete(@rd)
|
370
355
|
assert_nil @ep.delete(@wr)
|
371
|
-
|
356
|
+
@ep.add @rd, Epoll::IN
|
372
357
|
assert_equal @rd, @ep.delete(@rd)
|
373
358
|
assert_nil @ep.delete(@rd)
|
374
359
|
end
|
@@ -466,12 +451,12 @@ class TestEpoll < Test::Unit::TestCase
|
|
466
451
|
trap(:USR1, "DEFAULT")
|
467
452
|
sleep 0.1
|
468
453
|
ppid = Process.ppid
|
469
|
-
nr.times { Process.kill(:USR1, ppid); sleep 0.
|
454
|
+
nr.times { Process.kill(:USR1, ppid); sleep 0.05 }
|
470
455
|
@wr.syswrite('.')
|
471
456
|
exit!(0)
|
472
457
|
end
|
473
458
|
while tmp.empty?
|
474
|
-
|
459
|
+
@ep.wait(nil, 100) { |flags,obj| tmp << obj }
|
475
460
|
empty += 1
|
476
461
|
end
|
477
462
|
_, status = Process.waitpid2(pid)
|
@@ -545,4 +530,4 @@ class TestEpoll < Test::Unit::TestCase
|
|
545
530
|
end
|
546
531
|
@ep.wait(1) { |flags, io| assert_equal(first[0], io) }
|
547
532
|
end
|
548
|
-
end
|
533
|
+
end if defined?(SleepyPenguin::Epoll)
|