sleepy_penguin 1.0.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/.document +9 -0
- data/.gitignore +20 -0
- data/COPYING +165 -0
- data/GIT-VERSION-GEN +40 -0
- data/GNUmakefile +192 -0
- data/LICENSE +18 -0
- data/README +62 -0
- data/Rakefile +167 -0
- data/TODO +3 -0
- data/ext/sleepy_penguin/epoll.c +563 -0
- data/ext/sleepy_penguin/eventfd.c +177 -0
- data/ext/sleepy_penguin/extconf.rb +13 -0
- data/ext/sleepy_penguin/init.c +20 -0
- data/ext/sleepy_penguin/nonblock.h +19 -0
- data/ext/sleepy_penguin/sleepy_penguin.h +44 -0
- data/ext/sleepy_penguin/timerfd.c +128 -0
- data/ext/sleepy_penguin/value2timespec.h +64 -0
- data/lib/sleepy_penguin.rb +7 -0
- data/setup.rb +1586 -0
- data/sleepy_penguin.gemspec +36 -0
- data/test/test_epoll.rb +320 -0
- data/test/test_eventfd.rb +48 -0
- data/test/test_timerfd.rb +38 -0
- metadata +108 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
ENV["VERSION"] or abort "VERSION= must be specified"
|
2
|
+
manifest = File.readlines('.manifest').map! { |x| x.chomp! }
|
3
|
+
summary = File.readlines("README")[0].gsub(/\A=\s+\S+[^\w]+/, '').strip
|
4
|
+
description = File.read("README").split(/\n\n/)[1].strip
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{sleepy_penguin}
|
8
|
+
s.version = ENV["VERSION"]
|
9
|
+
|
10
|
+
s.homepage = 'http://bogomips.org/sleepy_penguin/'
|
11
|
+
s.authors = ["sleepy_penguin hackers"]
|
12
|
+
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
13
|
+
s.description = description
|
14
|
+
s.email = %q{sleepy.penguin@librelist.com}
|
15
|
+
|
16
|
+
s.extra_rdoc_files = File.readlines('.document').map! do |x|
|
17
|
+
x.chomp!
|
18
|
+
if File.directory?(x)
|
19
|
+
manifest.grep(%r{\A#{x}/})
|
20
|
+
elsif File.file?(x)
|
21
|
+
x
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end.flatten.compact
|
26
|
+
|
27
|
+
s.files = manifest
|
28
|
+
s.rdoc_options = [ "-t", summary ]
|
29
|
+
s.require_paths = %w(lib ext)
|
30
|
+
s.rubyforge_project = %q{rainbows}
|
31
|
+
s.summary = summary
|
32
|
+
s.test_files = Dir['test/test_*.rb']
|
33
|
+
s.extensions = %w(ext/sleepy_penguin/extconf.rb)
|
34
|
+
|
35
|
+
# s.license = %w(LGPL) # disabled for compatibility with older RubyGems
|
36
|
+
end
|
data/test/test_epoll.rb
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fcntl'
|
3
|
+
require 'socket'
|
4
|
+
$-w = true
|
5
|
+
|
6
|
+
require 'sleepy_penguin'
|
7
|
+
|
8
|
+
class TestEpoll < Test::Unit::TestCase
|
9
|
+
include SleepyPenguin
|
10
|
+
RBX = defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'rbx')
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@rd, @wr = IO.pipe
|
14
|
+
@ep = Epoll.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
[ @rd, @wr, @ep ].each { |io| io.close unless io.closed? }
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_cross_thread
|
22
|
+
tmp = []
|
23
|
+
Thread.new { sleep 0.100; @ep.add(@wr, Epoll::OUT) }
|
24
|
+
t0 = Time.now
|
25
|
+
@ep.wait { |flags,obj| tmp << [ flags, obj ] }
|
26
|
+
elapsed = Time.now - t0
|
27
|
+
assert elapsed >= 0.100
|
28
|
+
assert_equal [[Epoll::OUT, @wr]], tmp
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_fork_safe
|
32
|
+
tmp = []
|
33
|
+
@ep.add @rd, Epoll::IN
|
34
|
+
pid = fork do
|
35
|
+
@ep.wait(nil, 100) { |flags,obj| tmp << [ flags, obj ] }
|
36
|
+
exit!(tmp.empty?)
|
37
|
+
end
|
38
|
+
@wr.syswrite "HI"
|
39
|
+
_, status = Process.waitpid2(pid)
|
40
|
+
assert status.success?
|
41
|
+
@ep.wait(nil, 0) { |flags,obj| tmp << [ flags, obj ] }
|
42
|
+
assert_equal [[Epoll::IN, @rd]], tmp
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_after_fork_usability
|
46
|
+
fork { @ep.add(@rd, Epoll::IN); exit!(0) }
|
47
|
+
fork { @ep.set(@rd, Epoll::IN); exit!(0) }
|
48
|
+
fork { @ep.to_io; exit!(0) }
|
49
|
+
fork { @ep.dup; exit!(0) }
|
50
|
+
fork { @ep.clone; exit!(0) }
|
51
|
+
fork { @ep.close; exit!(0) }
|
52
|
+
fork { @ep.closed?; exit!(0) }
|
53
|
+
fork {
|
54
|
+
begin
|
55
|
+
@ep.del(@rd)
|
56
|
+
rescue Errno::ENOENT
|
57
|
+
exit!(0)
|
58
|
+
end
|
59
|
+
exit!(1)
|
60
|
+
}
|
61
|
+
res = Process.waitall
|
62
|
+
res.each { |(pid,status)| assert status.success? }
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_tcp_connect_nonblock_edge
|
66
|
+
epflags = Epoll::OUT | Epoll::ET
|
67
|
+
host = '127.0.0.1'
|
68
|
+
srv = TCPServer.new(host, 0)
|
69
|
+
port = srv.addr[1]
|
70
|
+
addr = Socket.pack_sockaddr_in(port, host)
|
71
|
+
sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
72
|
+
assert_raises(Errno::EINPROGRESS) { sock.connect_nonblock(addr) }
|
73
|
+
IO.select(nil, [ sock ], [sock ])
|
74
|
+
@ep.add(sock, epflags)
|
75
|
+
tmp = []
|
76
|
+
@ep.wait(1) { |flags, obj| tmp << [ flags, obj ] }
|
77
|
+
assert_equal [ [Epoll::OUT, sock] ], tmp
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_tcp_connect_edge
|
81
|
+
epflags = Epoll::OUT | Epoll::ET
|
82
|
+
host = '127.0.0.1'
|
83
|
+
srv = TCPServer.new(host, 0)
|
84
|
+
port = srv.addr[1]
|
85
|
+
sock = TCPSocket.new(host, port)
|
86
|
+
@ep.add(sock, epflags)
|
87
|
+
tmp = []
|
88
|
+
@ep.wait(1) { |flags, obj| tmp << [ flags, obj ] }
|
89
|
+
assert_equal [ [Epoll::OUT, sock] ], tmp
|
90
|
+
end
|
91
|
+
|
92
|
+
def teardown
|
93
|
+
assert_nothing_raised do
|
94
|
+
@rd.close unless @rd.closed?
|
95
|
+
@wr.close unless @wr.closed?
|
96
|
+
@ep.close unless @ep.closed?
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_max_events_big
|
101
|
+
@ep.add @rd, Epoll::IN
|
102
|
+
tmp = []
|
103
|
+
thr = Thread.new { @ep.wait(1024) { |flags, obj| tmp << [ flags, obj ] } }
|
104
|
+
Thread.pass
|
105
|
+
assert tmp.empty?
|
106
|
+
@wr.write '.'
|
107
|
+
thr.join
|
108
|
+
assert_equal([[Epoll::IN, @rd]], tmp)
|
109
|
+
tmp.clear
|
110
|
+
thr = Thread.new { @ep.wait { |flags, obj| tmp << [ flags, obj ] } }
|
111
|
+
thr.join
|
112
|
+
assert_equal([[Epoll::IN, @rd]], tmp)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_max_events_small
|
116
|
+
@ep.add @rd, Epoll::IN | Epoll::ET
|
117
|
+
@ep.add @wr, Epoll::OUT | Epoll::ET
|
118
|
+
@wr.write '.'
|
119
|
+
tmp = []
|
120
|
+
@ep.wait(1) { |flags, obj| tmp << [ flags, obj ] }
|
121
|
+
assert_equal 1, tmp.size
|
122
|
+
@ep.wait(1) { |flags, obj| tmp << [ flags, obj ] }
|
123
|
+
assert_equal 2, tmp.size
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_signal_safe
|
127
|
+
time = {}
|
128
|
+
trap(:USR1) { time[:USR1] = Time.now; sleep 0.1; @wr.write '.' }
|
129
|
+
@ep.add @rd, Epoll::IN
|
130
|
+
tmp = []
|
131
|
+
pid = fork do
|
132
|
+
sleep 0.1 # slightly racy :<
|
133
|
+
Process.kill(:USR1, Process.ppid)
|
134
|
+
end
|
135
|
+
time[:START_WAIT] = Time.now
|
136
|
+
@ep.wait { |flags, obj| tmp << [ flags, obj ]; time[:EP] = Time.now }
|
137
|
+
assert_equal([[Epoll::IN, @rd]], tmp)
|
138
|
+
_, status = Process.waitpid2(pid)
|
139
|
+
assert status.success?
|
140
|
+
assert((time[:USR1] - time[:START_WAIT]) >= 0.1)
|
141
|
+
assert((time[:USR1] - time[:START_WAIT]) < 0.15)
|
142
|
+
assert((time[:EP] - time[:USR1]) >= 0.1)
|
143
|
+
assert((time[:EP] - time[:USR1]) < 0.15)
|
144
|
+
ensure
|
145
|
+
trap(:USR1, 'DEFAULT')
|
146
|
+
end unless RBX
|
147
|
+
|
148
|
+
def test_close
|
149
|
+
@ep.add @rd, Epoll::IN
|
150
|
+
tmp = []
|
151
|
+
thr = Thread.new { @ep.wait { |flags, obj| tmp << [ flags, obj ] } }
|
152
|
+
@rd.close
|
153
|
+
@wr.close
|
154
|
+
assert_nil thr.join(0.01)
|
155
|
+
assert thr.alive?
|
156
|
+
thr.kill
|
157
|
+
assert tmp.empty?
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_rdhup
|
161
|
+
rd, wr = UNIXSocket.pair
|
162
|
+
@ep.add rd, Epoll::RDHUP
|
163
|
+
tmp = []
|
164
|
+
thr = Thread.new { @ep.wait { |flags, obj| tmp << [ flags, obj ] } }
|
165
|
+
wr.shutdown Socket::SHUT_WR
|
166
|
+
thr.join
|
167
|
+
assert_equal([[ Epoll::RDHUP, rd ]], tmp)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_hup
|
171
|
+
@ep.add @rd, Epoll::IN
|
172
|
+
tmp = []
|
173
|
+
thr = Thread.new { @ep.wait { |flags, obj| tmp << [ flags, obj ] } }
|
174
|
+
@wr.close
|
175
|
+
thr.join
|
176
|
+
assert_equal([[ Epoll::HUP, @rd ]], tmp)
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_multiple
|
180
|
+
r, w = IO.pipe
|
181
|
+
assert_nothing_raised do
|
182
|
+
@ep.add r, Epoll::IN
|
183
|
+
@ep.add @rd, Epoll::IN
|
184
|
+
@ep.add w, Epoll::OUT
|
185
|
+
@ep.add @wr, Epoll::OUT
|
186
|
+
end
|
187
|
+
tmp = []
|
188
|
+
@ep.wait { |flags, obj| tmp << [ flags, obj ] }
|
189
|
+
assert_equal 2, tmp.size
|
190
|
+
assert_equal [ Epoll::OUT ], tmp.map { |flags, obj| flags }.uniq
|
191
|
+
ios = tmp.map { |flags, obj| obj }
|
192
|
+
assert ios.include?(@wr)
|
193
|
+
assert ios.include?(w)
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_gc
|
197
|
+
assert_nothing_raised { 4096.times { Epoll.new } }
|
198
|
+
assert ! @ep.closed?
|
199
|
+
end unless RBX
|
200
|
+
|
201
|
+
def test_gc_to_io
|
202
|
+
assert_nothing_raised do
|
203
|
+
4096.times do
|
204
|
+
ep = Epoll.new
|
205
|
+
io = ep.to_io
|
206
|
+
end
|
207
|
+
end
|
208
|
+
assert ! @ep.closed?
|
209
|
+
end unless RBX
|
210
|
+
|
211
|
+
def test_clone
|
212
|
+
tmp = []
|
213
|
+
clone = @ep.clone
|
214
|
+
assert @ep.to_io.fileno != clone.to_io.fileno
|
215
|
+
clone.add @wr, Epoll::OUT
|
216
|
+
@ep.wait(nil, 0) { |flags, obj| tmp << [ flags, obj ] }
|
217
|
+
assert_equal([[Epoll::OUT, @wr]], tmp)
|
218
|
+
assert_nothing_raised { clone.close }
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_dup
|
222
|
+
tmp = []
|
223
|
+
clone = @ep.dup
|
224
|
+
assert @ep.to_io.fileno != clone.to_io.fileno
|
225
|
+
clone.add @wr, Epoll::OUT
|
226
|
+
@ep.wait(nil, 0) { |flags, obj| tmp << [ flags, obj ] }
|
227
|
+
assert_equal([[Epoll::OUT, @wr]], tmp)
|
228
|
+
assert_nothing_raised { clone.close }
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_set_idempotency
|
232
|
+
assert_nothing_raised do
|
233
|
+
@ep.set @rd, Epoll::IN
|
234
|
+
@ep.set @rd, Epoll::IN
|
235
|
+
@ep.set @wr, Epoll::OUT
|
236
|
+
@ep.set @wr, Epoll::OUT
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_wait_timeout
|
241
|
+
t0 = Time.now
|
242
|
+
assert_equal 0, @ep.wait(nil, 100) { |flags,obj| assert false }
|
243
|
+
diff = Time.now - t0
|
244
|
+
assert(diff >= 0.075, "#{diff} < 0.100s")
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_del
|
248
|
+
assert_raises(Errno::ENOENT) { @ep.del(@rd) }
|
249
|
+
assert_nothing_raised do
|
250
|
+
@ep.add(@rd, Epoll::IN)
|
251
|
+
@ep.del(@rd)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_wait_read
|
256
|
+
@ep.add(@rd, Epoll::IN)
|
257
|
+
assert_equal 0, @ep.wait(nil, 0) { |flags,obj| assert false }
|
258
|
+
@wr.syswrite '.'
|
259
|
+
i = 0
|
260
|
+
nr = @ep.wait(nil, 0) do |flags,obj|
|
261
|
+
assert_equal Epoll::IN, flags
|
262
|
+
assert_equal obj, @rd
|
263
|
+
i += 1
|
264
|
+
end
|
265
|
+
assert_equal 1, i
|
266
|
+
assert_equal 1, nr
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_wait_write
|
270
|
+
@ep.add(@wr, Epoll::OUT | Epoll::IN)
|
271
|
+
i = 0
|
272
|
+
nr = @ep.wait(nil, 0) do |flags, obj|
|
273
|
+
assert_equal Epoll::OUT, flags
|
274
|
+
assert_equal obj, @wr
|
275
|
+
i += 1
|
276
|
+
end
|
277
|
+
assert_equal 1, nr
|
278
|
+
assert_equal 1, i
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_wait_write_blocked
|
282
|
+
begin
|
283
|
+
@wr.write_nonblock('.' * 65536)
|
284
|
+
rescue Errno::EAGAIN
|
285
|
+
break
|
286
|
+
end while true
|
287
|
+
@ep.add(@wr, Epoll::OUT | Epoll::IN)
|
288
|
+
i = 0
|
289
|
+
assert_equal 0, @ep.wait(nil, 0) { |flags,event| assert false }
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_selectable
|
293
|
+
tmp = nil
|
294
|
+
@ep.add @rd, Epoll::IN
|
295
|
+
thr = Thread.new { tmp = IO.select([ @ep ]) }
|
296
|
+
thr.join 0.01
|
297
|
+
assert_nil tmp
|
298
|
+
@wr.write '.'
|
299
|
+
thr.join
|
300
|
+
assert_equal([[@ep],[],[]], tmp)
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_new_no_cloexec
|
304
|
+
@ep.close
|
305
|
+
io = Epoll.new(0).to_io
|
306
|
+
assert((io.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC) == 0)
|
307
|
+
end
|
308
|
+
|
309
|
+
def test_new_cloexec
|
310
|
+
@ep.close
|
311
|
+
io = Epoll.new(Epoll::CLOEXEC).to_io
|
312
|
+
assert((io.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC) == Fcntl::FD_CLOEXEC)
|
313
|
+
end
|
314
|
+
|
315
|
+
def test_new
|
316
|
+
@ep.close
|
317
|
+
io = Epoll.new.to_io
|
318
|
+
assert((io.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC) == Fcntl::FD_CLOEXEC)
|
319
|
+
end
|
320
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fcntl'
|
3
|
+
$-w = true
|
4
|
+
|
5
|
+
require 'sleepy_penguin'
|
6
|
+
|
7
|
+
class TestEventFD < Test::Unit::TestCase
|
8
|
+
include SleepyPenguin
|
9
|
+
|
10
|
+
def test_constants
|
11
|
+
defined?(EventFD::NONBLOCK) and
|
12
|
+
assert_kind_of Integer, EventFD::NONBLOCK
|
13
|
+
defined?(EventFD::CLOEXEC) and
|
14
|
+
assert_kind_of Integer, EventFD::CLOEXEC
|
15
|
+
defined?(EventFD::SEMAPHORE) and
|
16
|
+
assert_kind_of Integer, EventFD::SEMAPHORE
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_new
|
20
|
+
efd = EventFD.new 0
|
21
|
+
assert_kind_of(IO, efd)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_new_nonblock
|
25
|
+
efd = EventFD.new(0, EventFD::NONBLOCK)
|
26
|
+
flags = efd.fcntl(Fcntl::F_GETFL) & Fcntl::O_NONBLOCK
|
27
|
+
assert_equal(Fcntl::O_NONBLOCK, flags)
|
28
|
+
end if defined?(EventFD::NONBLOCK)
|
29
|
+
|
30
|
+
def test_new_cloexec
|
31
|
+
efd = EventFD.new(0, EventFD::CLOEXEC)
|
32
|
+
flags = efd.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC
|
33
|
+
assert_equal(Fcntl::FD_CLOEXEC, flags)
|
34
|
+
end if defined?(EventFD::CLOEXEC)
|
35
|
+
|
36
|
+
def test_incr_value
|
37
|
+
efd = EventFD.new(0)
|
38
|
+
assert_nil efd.incr(1)
|
39
|
+
assert_equal 1, efd.value
|
40
|
+
|
41
|
+
assert_raises(Errno::EAGAIN) { efd.value_nonblock }
|
42
|
+
assert_nil efd.incr(9)
|
43
|
+
assert_equal 9, efd.value_nonblock
|
44
|
+
|
45
|
+
assert_nil efd.incr(0xfffffffffffffffe)
|
46
|
+
assert_raises(Errno::EAGAIN) { efd.incr_nonblock 1 }
|
47
|
+
end
|
48
|
+
end if defined?(SleepyPenguin::EventFD)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fcntl'
|
3
|
+
$-w = true
|
4
|
+
|
5
|
+
require 'sleepy_penguin'
|
6
|
+
|
7
|
+
class TestTimerFD < Test::Unit::TestCase
|
8
|
+
include SleepyPenguin
|
9
|
+
|
10
|
+
def test_constants
|
11
|
+
assert_kind_of Integer, TimerFD::REALTIME
|
12
|
+
assert_kind_of Integer, TimerFD::MONOTONIC
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_create
|
16
|
+
tfd = TimerFD.create
|
17
|
+
assert_kind_of(IO, tfd)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_create_nonblock
|
21
|
+
tfd = TimerFD.create(TimerFD::REALTIME, TimerFD::NONBLOCK)
|
22
|
+
flags = tfd.fcntl(Fcntl::F_GETFL) & Fcntl::O_NONBLOCK
|
23
|
+
assert_equal(Fcntl::O_NONBLOCK, flags)
|
24
|
+
end if defined?(TimerFD::NONBLOCK)
|
25
|
+
|
26
|
+
def test_create_cloexec
|
27
|
+
tfd = TimerFD.create(TimerFD::REALTIME, TimerFD::CLOEXEC)
|
28
|
+
flags = tfd.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC
|
29
|
+
assert_equal(Fcntl::FD_CLOEXEC, flags)
|
30
|
+
end if defined?(TimerFD::CLOEXEC)
|
31
|
+
|
32
|
+
def test_settime
|
33
|
+
tfd = TimerFD.create(TimerFD::REALTIME)
|
34
|
+
assert_equal([0, 0], tfd.settime(TimerFD::ABSTIME, 0, 0.01))
|
35
|
+
sleep 0.01
|
36
|
+
assert_equal 1, tfd.expirations
|
37
|
+
end
|
38
|
+
end if defined?(SleepyPenguin::TimerFD)
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sleepy_penguin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- sleepy_penguin hackers
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-26 00:00:00 +00:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: |-
|
23
|
+
sleepy_penguin provides access to newer, Linux-only system calls to wait
|
24
|
+
on events from traditionally non-I/O sources. Bindings to the eventfd,
|
25
|
+
timerfd, and epoll interfaces are provided.
|
26
|
+
email: sleepy.penguin@librelist.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions:
|
30
|
+
- ext/sleepy_penguin/extconf.rb
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README
|
34
|
+
- TODO
|
35
|
+
- NEWS
|
36
|
+
- ChangeLog
|
37
|
+
- lib/sleepy_penguin.rb
|
38
|
+
- ext/sleepy_penguin/init.c
|
39
|
+
- ext/sleepy_penguin/eventfd.c
|
40
|
+
- ext/sleepy_penguin/timerfd.c
|
41
|
+
files:
|
42
|
+
- .document
|
43
|
+
- .gitignore
|
44
|
+
- .manifest
|
45
|
+
- COPYING
|
46
|
+
- ChangeLog
|
47
|
+
- GIT-VERSION-FILE
|
48
|
+
- GIT-VERSION-GEN
|
49
|
+
- GNUmakefile
|
50
|
+
- LICENSE
|
51
|
+
- NEWS
|
52
|
+
- README
|
53
|
+
- Rakefile
|
54
|
+
- TODO
|
55
|
+
- ext/sleepy_penguin/epoll.c
|
56
|
+
- ext/sleepy_penguin/eventfd.c
|
57
|
+
- ext/sleepy_penguin/extconf.rb
|
58
|
+
- ext/sleepy_penguin/init.c
|
59
|
+
- ext/sleepy_penguin/nonblock.h
|
60
|
+
- ext/sleepy_penguin/sleepy_penguin.h
|
61
|
+
- ext/sleepy_penguin/timerfd.c
|
62
|
+
- ext/sleepy_penguin/value2timespec.h
|
63
|
+
- lib/sleepy_penguin.rb
|
64
|
+
- setup.rb
|
65
|
+
- sleepy_penguin.gemspec
|
66
|
+
- test/test_epoll.rb
|
67
|
+
- test/test_eventfd.rb
|
68
|
+
- test/test_timerfd.rb
|
69
|
+
has_rdoc: true
|
70
|
+
homepage: http://bogomips.org/sleepy_penguin/
|
71
|
+
licenses: []
|
72
|
+
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options:
|
75
|
+
- -t
|
76
|
+
- Ruby I/O events for Linux
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
- ext
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
requirements: []
|
99
|
+
|
100
|
+
rubyforge_project: rainbows
|
101
|
+
rubygems_version: 1.3.7
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: Ruby I/O events for Linux
|
105
|
+
test_files:
|
106
|
+
- test/test_epoll.rb
|
107
|
+
- test/test_eventfd.rb
|
108
|
+
- test/test_timerfd.rb
|