barlume 0.0.1.rc.1 → 0.0.1.rc.2
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/barlume.gemspec +2 -1
- data/examples/echo.rb +78 -0
- data/examples/slowpokes.rb +75 -0
- data/lib/barlume/lanterna.rb +243 -65
- data/lib/barlume/lanterna/dpoll.rb +204 -0
- data/lib/barlume/lanterna/epoll.rb +98 -70
- data/lib/barlume/lanterna/{utils.rb → helpers.rb} +6 -3
- data/lib/barlume/lanterna/kqueue.rb +88 -101
- data/lib/barlume/lanterna/poll.rb +67 -66
- data/lib/barlume/lanterna/port.rb +211 -0
- data/lib/barlume/lanterna/select.rb +22 -44
- data/lib/barlume/lucciola.rb +221 -10
- data/lib/barlume/version.rb +1 -1
- data/test/benchmark.client.rb +17 -0
- data/test/benchmark.server.rb +35 -0
- data/test/flood.js +28 -0
- metadata +30 -5
- data/examples/test.rb +0 -27
@@ -24,59 +24,37 @@ class Select < Lanterna
|
|
24
24
|
true
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
|
29
|
-
@descriptors_with_breaker = nil
|
30
|
-
}
|
31
|
-
end
|
27
|
+
def available (timeout = nil, &block)
|
28
|
+
return enum_for :available, timeout unless block
|
32
29
|
|
33
|
-
|
34
|
-
super.tap {
|
35
|
-
@descriptors_with_breaker = nil
|
36
|
-
}
|
37
|
-
end
|
30
|
+
readable, writable, error = IO.select([@breaker.to_io] + @readable.values, @writable.values, @descriptors.values, timeout)
|
38
31
|
|
39
|
-
|
40
|
-
|
32
|
+
unless readable
|
33
|
+
yield :timeout, timeout
|
41
34
|
|
42
|
-
|
43
|
-
@breaker.flush
|
35
|
+
return self
|
44
36
|
end
|
45
37
|
|
46
|
-
|
47
|
-
|
38
|
+
error.each {|io|
|
39
|
+
readable.delete(io)
|
40
|
+
writable.delete(io)
|
48
41
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if readable && readable.delete(@breaker.to_io)
|
53
|
-
@breaker.flush
|
54
|
-
end
|
55
|
-
|
56
|
-
if report_errors?
|
57
|
-
[readable || [], error || []]
|
58
|
-
else
|
59
|
-
readable || []
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def writable (timeout = nil)
|
64
|
-
readable, writable, error = IO.select([@breaker], descriptors, descriptors, timeout)
|
42
|
+
yield :error, io
|
43
|
+
}
|
65
44
|
|
66
|
-
|
67
|
-
@breaker.
|
68
|
-
|
45
|
+
readable.each {|io|
|
46
|
+
if io == @breaker.to_io
|
47
|
+
yield :break, @breaker.reason
|
48
|
+
else
|
49
|
+
yield :readable, io
|
50
|
+
end
|
51
|
+
}
|
69
52
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
writable || []
|
74
|
-
end
|
75
|
-
end
|
53
|
+
writable.each {|io|
|
54
|
+
yield :writable, io
|
55
|
+
}
|
76
56
|
|
77
|
-
|
78
|
-
def descriptors_with_breaker
|
79
|
-
@descriptors_with_breaker ||= [@breaker.to_io] + descriptors
|
57
|
+
self
|
80
58
|
end
|
81
59
|
end
|
82
60
|
|
data/lib/barlume/lucciola.rb
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
#++
|
19
19
|
|
20
20
|
require 'fcntl'
|
21
|
+
require 'socket'
|
21
22
|
|
22
23
|
module Barlume
|
23
24
|
|
@@ -44,13 +45,7 @@ class Lucciola
|
|
44
45
|
|
45
46
|
def method_missing (id, *args, &block)
|
46
47
|
if @io.respond_to? id
|
47
|
-
|
48
|
-
return @io.__send__ id, *args, &block
|
49
|
-
rescue EOFError
|
50
|
-
@closed = true
|
51
|
-
|
52
|
-
raise
|
53
|
-
end
|
48
|
+
return @io.__send__ id, *args, &block
|
54
49
|
end
|
55
50
|
|
56
51
|
super
|
@@ -74,8 +69,16 @@ class Lucciola
|
|
74
69
|
@closed or @io.respond_to?(:closed?) ? @io.closed? : false
|
75
70
|
end
|
76
71
|
|
72
|
+
def alive?
|
73
|
+
if @io.is_a?(Socket)
|
74
|
+
!!@io.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE).nonzero?
|
75
|
+
else
|
76
|
+
!@io.closed?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
77
80
|
def nonblocking?
|
78
|
-
(@io.fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK).
|
81
|
+
!(@io.fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK).zero?
|
79
82
|
end
|
80
83
|
|
81
84
|
alias asynchronous? nonblocking?
|
@@ -84,12 +87,220 @@ class Lucciola
|
|
84
87
|
!nonblocking?
|
85
88
|
end
|
86
89
|
|
90
|
+
alias synchronous? blocking?
|
91
|
+
|
87
92
|
def blocking!
|
88
|
-
|
93
|
+
if block_given?
|
94
|
+
if was_nonblocking = nonblocking?
|
95
|
+
@io.fcntl(Fcntl::F_SETFL, @io.fcntl(Fcntl::F_GETFL, 0) & ~Fcntl::O_NONBLOCK)
|
96
|
+
end
|
97
|
+
|
98
|
+
begin
|
99
|
+
return yield
|
100
|
+
ensure
|
101
|
+
nonblocking! if was_nonblocking
|
102
|
+
end
|
103
|
+
else
|
104
|
+
@io.fcntl(Fcntl::F_SETFL, @io.fcntl(Fcntl::F_GETFL, 0) & ~Fcntl::O_NONBLOCK)
|
105
|
+
end
|
106
|
+
|
107
|
+
self
|
89
108
|
end
|
90
109
|
|
110
|
+
alias sychronous! blocking!
|
111
|
+
|
91
112
|
def nonblocking!
|
92
|
-
|
113
|
+
if block_given?
|
114
|
+
if was_blocking = blocking?
|
115
|
+
@io.fcntl(Fcntl::F_SETFL, @io.fcntl(Fcntl::F_GETFL, 0) | Fcntl::O_NONBLOCK)
|
116
|
+
end
|
117
|
+
|
118
|
+
begin
|
119
|
+
return yield
|
120
|
+
ensure
|
121
|
+
blocking! if was_blocking
|
122
|
+
end
|
123
|
+
else
|
124
|
+
@io.fcntl(Fcntl::F_SETFL, @io.fcntl(Fcntl::F_GETFL, 0) | Fcntl::O_NONBLOCK)
|
125
|
+
end
|
126
|
+
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
130
|
+
alias asynchronous! nonblocking!
|
131
|
+
|
132
|
+
def no_delay?
|
133
|
+
raise 'no_delay is TCP only' unless @io.is_a? TCPSocket
|
134
|
+
|
135
|
+
@io.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY).nonzero?
|
136
|
+
end
|
137
|
+
|
138
|
+
def delay?
|
139
|
+
!no_delay?
|
140
|
+
end
|
141
|
+
|
142
|
+
def no_delay!
|
143
|
+
raise 'no_delay is TCP only' unless @io.is_a? TCPSocket
|
144
|
+
|
145
|
+
@io.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
146
|
+
|
147
|
+
self
|
148
|
+
end
|
149
|
+
|
150
|
+
def delay!
|
151
|
+
raise 'no_delay is TCP only' unless @io.is_a? TCPSocket
|
152
|
+
|
153
|
+
@io.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 0)
|
154
|
+
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
def transaction
|
159
|
+
unless to_io.is_a?(TCPSocket) && Socket.const_defined?(:TCP_CORK)
|
160
|
+
raise 'transaction is not supported on this kind of IO'
|
161
|
+
end
|
162
|
+
|
163
|
+
begin
|
164
|
+
@io.setsockopt Socket::IPPROTO_TCP, Socket::TCP_CORK, 1
|
165
|
+
|
166
|
+
yield self
|
167
|
+
ensure
|
168
|
+
@io.setsockopt Socket::IPPROTO_TCP, Socket::TCP_CORK, 0
|
169
|
+
end
|
170
|
+
|
171
|
+
self
|
172
|
+
end
|
173
|
+
|
174
|
+
def trap_in (lanterna)
|
175
|
+
raise 'already trapped' if @lanterna
|
176
|
+
|
177
|
+
@lanterna = lanterna
|
178
|
+
end
|
179
|
+
|
180
|
+
def set_free
|
181
|
+
raise 'not trapped' unless @lanterna
|
182
|
+
|
183
|
+
if @lanterna.has?(self)
|
184
|
+
@lanterna.remove(self)
|
185
|
+
end
|
186
|
+
|
187
|
+
@lanterna = nil
|
188
|
+
end
|
189
|
+
|
190
|
+
def readable?
|
191
|
+
raise 'not trapped' unless @lanterna
|
192
|
+
|
193
|
+
@lanterna.readable? self
|
194
|
+
end
|
195
|
+
|
196
|
+
def readable!
|
197
|
+
raise 'not trapped' unless @lanterna
|
198
|
+
|
199
|
+
@lanterna.readable! self
|
200
|
+
|
201
|
+
self
|
202
|
+
end
|
203
|
+
|
204
|
+
def no_readable!
|
205
|
+
raise 'not trapped' unless @lanterna
|
206
|
+
|
207
|
+
@lanterna.no_readable! self
|
208
|
+
|
209
|
+
self
|
210
|
+
end
|
211
|
+
|
212
|
+
def writable?
|
213
|
+
raise 'not trapped' unless @lanterna
|
214
|
+
|
215
|
+
@lanterna.writable? self
|
216
|
+
end
|
217
|
+
|
218
|
+
def writable!
|
219
|
+
raise 'not trapped' unless @lanterna
|
220
|
+
|
221
|
+
@lanterna.writable! self
|
222
|
+
|
223
|
+
self
|
224
|
+
end
|
225
|
+
|
226
|
+
def no_writable!
|
227
|
+
raise 'not trapped' unless @lanterna
|
228
|
+
|
229
|
+
@lanterna.no_writable! self
|
230
|
+
|
231
|
+
self
|
232
|
+
end
|
233
|
+
|
234
|
+
def delete!
|
235
|
+
raise 'not trapped' unless @lanterna
|
236
|
+
|
237
|
+
@lanterna.remove self
|
238
|
+
|
239
|
+
self
|
240
|
+
end
|
241
|
+
|
242
|
+
def accept (*args)
|
243
|
+
if blocking?
|
244
|
+
@io.accept(*args)
|
245
|
+
else
|
246
|
+
@io.accept_nonblock(*args)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def accept_nonblock (*args)
|
251
|
+
nonblocking! {
|
252
|
+
accept(*args)
|
253
|
+
}
|
254
|
+
end
|
255
|
+
|
256
|
+
def accept_block (*args)
|
257
|
+
blocking! {
|
258
|
+
accept(*args)
|
259
|
+
}
|
260
|
+
end
|
261
|
+
|
262
|
+
def read (*args)
|
263
|
+
if (result = @io.sysread(*args)).nil?
|
264
|
+
@closed = true
|
265
|
+
end
|
266
|
+
|
267
|
+
result
|
268
|
+
rescue EOFError
|
269
|
+
@closed = true
|
270
|
+
|
271
|
+
raise
|
272
|
+
end
|
273
|
+
|
274
|
+
def read_nonblock (*args)
|
275
|
+
nonblocking! {
|
276
|
+
read(*args)
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
def read_block (*args)
|
281
|
+
blocking! {
|
282
|
+
read(*args)
|
283
|
+
}
|
284
|
+
end
|
285
|
+
|
286
|
+
def write (*args)
|
287
|
+
@io.syswrite(*args)
|
288
|
+
rescue EOFError
|
289
|
+
@closed = true
|
290
|
+
|
291
|
+
raise
|
292
|
+
end
|
293
|
+
|
294
|
+
def write_nonblock (*args)
|
295
|
+
nonblocking! {
|
296
|
+
write(*args)
|
297
|
+
}
|
298
|
+
end
|
299
|
+
|
300
|
+
def write_block (*args)
|
301
|
+
blocking! {
|
302
|
+
write(*args)
|
303
|
+
}
|
93
304
|
end
|
94
305
|
|
95
306
|
def to_io
|
data/lib/barlume/version.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'socket'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
2.times.map {
|
6
|
+
Thread.new {
|
7
|
+
sockets = []
|
8
|
+
|
9
|
+
100.times {
|
10
|
+
sockets << TCPSocket.new('localhost', 43215)
|
11
|
+
}
|
12
|
+
|
13
|
+
sockets.each {|socket|
|
14
|
+
socket.puts 'a' * 4096
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}.each(&:join)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'barlume'
|
3
|
+
|
4
|
+
lantern = Barlume::Lanterna.best
|
5
|
+
server = lantern.add(TCPServer.new(43215))
|
6
|
+
bytes = 0
|
7
|
+
clients = 0
|
8
|
+
|
9
|
+
puts "Using #{lantern.name}..."
|
10
|
+
|
11
|
+
trap 'INT' do
|
12
|
+
puts "Received #{bytes} bytes from #{clients} clients"
|
13
|
+
exit!
|
14
|
+
end
|
15
|
+
|
16
|
+
loop do
|
17
|
+
lantern.readable.each {|lucciola|
|
18
|
+
if lucciola == server
|
19
|
+
while client = server.accept_nonblock rescue nil
|
20
|
+
clients += 1
|
21
|
+
lantern.add(client)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
begin
|
25
|
+
while value = lucciola.read(2048)
|
26
|
+
bytes += value.bytesize
|
27
|
+
end
|
28
|
+
rescue EOFError, Errno::EAGAIN; end
|
29
|
+
|
30
|
+
if lucciola.closed?
|
31
|
+
lantern.remove(lucciola)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
data/test/flood.js
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
var net = require('net');
|
2
|
+
|
3
|
+
var created = 255,
|
4
|
+
answered = 0,
|
5
|
+
errored = 0,
|
6
|
+
time = +new Date;
|
7
|
+
|
8
|
+
|
9
|
+
function createClient() {
|
10
|
+
var socket = net.createConnection(1337, '127.0.0.1');
|
11
|
+
socket.setEncoding('utf8');
|
12
|
+
socket
|
13
|
+
.on('connect', function() { socket.write('lol'); })
|
14
|
+
.on('data', function(c) {
|
15
|
+
errored += c !== 'lol' ? 1 : 0;
|
16
|
+
if(++answered === created) {
|
17
|
+
var t = +new Date - time;
|
18
|
+
console.log('Time (ms): ' + t);
|
19
|
+
console.log('Errored: ' + errored);
|
20
|
+
process.exit();
|
21
|
+
}
|
22
|
+
});
|
23
|
+
}
|
24
|
+
|
25
|
+
for(var i=0; i <= created; i++) {
|
26
|
+
createClient();
|
27
|
+
}
|
28
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: barlume
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1.rc.
|
4
|
+
version: 0.0.1.rc.2
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: backports
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
30
46
|
description:
|
31
47
|
email: meh@paranoici.org
|
32
48
|
executables: []
|
@@ -35,16 +51,22 @@ extra_rdoc_files: []
|
|
35
51
|
files:
|
36
52
|
- README.md
|
37
53
|
- barlume.gemspec
|
38
|
-
- examples/
|
54
|
+
- examples/echo.rb
|
55
|
+
- examples/slowpokes.rb
|
39
56
|
- lib/barlume.rb
|
40
57
|
- lib/barlume/lanterna.rb
|
58
|
+
- lib/barlume/lanterna/dpoll.rb
|
41
59
|
- lib/barlume/lanterna/epoll.rb
|
60
|
+
- lib/barlume/lanterna/helpers.rb
|
42
61
|
- lib/barlume/lanterna/kqueue.rb
|
43
62
|
- lib/barlume/lanterna/poll.rb
|
63
|
+
- lib/barlume/lanterna/port.rb
|
44
64
|
- lib/barlume/lanterna/select.rb
|
45
|
-
- lib/barlume/lanterna/utils.rb
|
46
65
|
- lib/barlume/lucciola.rb
|
47
66
|
- lib/barlume/version.rb
|
67
|
+
- test/benchmark.client.rb
|
68
|
+
- test/benchmark.server.rb
|
69
|
+
- test/flood.js
|
48
70
|
homepage: http://github.com/meh/barlume
|
49
71
|
licenses: []
|
50
72
|
post_install_message:
|
@@ -69,4 +91,7 @@ rubygems_version: 1.8.24
|
|
69
91
|
signing_key:
|
70
92
|
specification_version: 3
|
71
93
|
summary: A dim light over asynchronous I/O land.
|
72
|
-
test_files:
|
94
|
+
test_files:
|
95
|
+
- test/benchmark.client.rb
|
96
|
+
- test/benchmark.server.rb
|
97
|
+
- test/flood.js
|