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
@@ -0,0 +1,204 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of barlume.
|
5
|
+
#
|
6
|
+
# barlume is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# barlume is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with barlume. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
module Barlume; class Lanterna
|
21
|
+
|
22
|
+
class DPoll < Lanterna; begin
|
23
|
+
raise unless File.exists?('/dev/poll')
|
24
|
+
|
25
|
+
module C
|
26
|
+
extend FFI::Library
|
27
|
+
|
28
|
+
ffi_lib FFI::Library::LIBC
|
29
|
+
|
30
|
+
class PollFD < FFI::Struct
|
31
|
+
layout \
|
32
|
+
:fd, :int,
|
33
|
+
:events, :short,
|
34
|
+
:revents, :short
|
35
|
+
end
|
36
|
+
|
37
|
+
class DVPoll < FFI::Struct
|
38
|
+
layout \
|
39
|
+
:fds, :pointer,
|
40
|
+
:nfds, :nfds_t,
|
41
|
+
:timeout, :int
|
42
|
+
end
|
43
|
+
|
44
|
+
attach_function :malloc, [:size_t], :pointer
|
45
|
+
attach_function :realloc, [:pointer, :size_t], :pointer
|
46
|
+
attach_function :free, [:pointer], :void
|
47
|
+
|
48
|
+
DP_POLL = (0xD0 << 8) | 1
|
49
|
+
|
50
|
+
POLLIN = 0x001
|
51
|
+
POLLPRI = 0x002
|
52
|
+
POLLOUT = 0x004
|
53
|
+
|
54
|
+
POLLERR = 0x008
|
55
|
+
POLLHUP = 0x010
|
56
|
+
POLLNVAL = 0x020
|
57
|
+
|
58
|
+
POLLRDNORM = 0x040
|
59
|
+
POLLRDBAND = 0x080
|
60
|
+
POLLWRNORM = 0x100
|
61
|
+
POLLWRBAND = 0x200
|
62
|
+
|
63
|
+
POLLMSG = 0x0400
|
64
|
+
POLLREMOVE = 0x1000
|
65
|
+
POLLRDHUP = 0x2000
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.supported?
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize
|
73
|
+
super
|
74
|
+
|
75
|
+
@out = C::DVPoll.new
|
76
|
+
@out[:fds] = FFI::AutoPointer.new(C.malloc(C::PollFD.size), C.method(:free))
|
77
|
+
@out[:nfds] = 1
|
78
|
+
|
79
|
+
@set = FFI::AutoPointer.new(C.malloc(C::PollFD.size), C.method(:free))
|
80
|
+
|
81
|
+
pfd = C::PollFD.new(@set + 0)
|
82
|
+
pfd[:fd] = @breaker.to_i
|
83
|
+
pfd[:events] = C::POLLIN
|
84
|
+
end
|
85
|
+
|
86
|
+
def add (*)
|
87
|
+
super {|l|
|
88
|
+
@set.autorelease = false
|
89
|
+
@set = FFI::AutoPointer.new(C.realloc(@set, (@descriptors.length + 1) * C::PollFD.size), C.method(:free))
|
90
|
+
|
91
|
+
@out[:fds].autorelease = false
|
92
|
+
@out[:fds] = FFI::AutoPointer.new(C.realloc(@out[:fds], (@descriptors.length + 1) * C::PollFD.size), C.method(:free))
|
93
|
+
@out[:nfds] += 1
|
94
|
+
|
95
|
+
pfd = C::PollFD.new(@set + (@descriptors.length * C::PollFD.size))
|
96
|
+
pfd[:fd] = l.to_i
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def remove (*)
|
101
|
+
super {|l|
|
102
|
+
index = index_of(l)
|
103
|
+
offset = (index + 1) * C::PollFD.size
|
104
|
+
pointer = @set + offset
|
105
|
+
|
106
|
+
pointer.write_bytes((pointer + C::PollFD.size).read_bytes((@descriptors.length - index) * C::PollFD.size))
|
107
|
+
|
108
|
+
@set.autorelease = false
|
109
|
+
@set = FFI::AutoPointer.new(C.realloc(@set, (@descriptors.length) * C::PollFD.size), C.method(:free))
|
110
|
+
|
111
|
+
@out[:fds].autorelease = false
|
112
|
+
@out[:fds] = FFI::AutoPointer.new(C.realloc(@out[:fds], @descriptors.length * C::PollFD.size), C.method(:free))
|
113
|
+
@out[:nfds] -= 1
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def readable! (*)
|
118
|
+
super {|l|
|
119
|
+
pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
|
120
|
+
pfd[:events] |= C::POLLIN
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def no_readable! (*)
|
125
|
+
super {|l|
|
126
|
+
pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
|
127
|
+
pfd[:events] &= ~C::POLLIN
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def writable! (*)
|
132
|
+
super {|l|
|
133
|
+
pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
|
134
|
+
pfd[:events] |= C::POLLOUT
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
def no_writable! (*)
|
139
|
+
super {|l|
|
140
|
+
pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
|
141
|
+
pfd[:events] &= ~C::POLLOUT
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
145
|
+
def available (timeout = nil, &block)
|
146
|
+
return enum_for :available, timeout unless block
|
147
|
+
|
148
|
+
@out[:timeout] = timeout ? timeout * 1000 : -1
|
149
|
+
|
150
|
+
io = IO.for_fd(IO.sysopen('/dev/poll', IO::RDWR))
|
151
|
+
io.syswrite(@set.read_bytes((@descriptors.length + 1) * C::PollFD.size))
|
152
|
+
|
153
|
+
length = io.ioctl(C::DP_POLL, @out.pointer.address)
|
154
|
+
io.close
|
155
|
+
|
156
|
+
if length == 0
|
157
|
+
yield :timeout, timeout
|
158
|
+
|
159
|
+
return self
|
160
|
+
end
|
161
|
+
|
162
|
+
n = 0
|
163
|
+
size = C::PollFD.size
|
164
|
+
while n < length
|
165
|
+
p = C::PollFD.new(@out[:fds] + (n * size))
|
166
|
+
events = p[:revents]
|
167
|
+
fd = p[:fd]
|
168
|
+
lucciola = self[fd]
|
169
|
+
|
170
|
+
if lucciola
|
171
|
+
if (events & (C::POLLERR | C::POLLHUP)).nonzero?
|
172
|
+
yield :error, lucciola
|
173
|
+
else
|
174
|
+
if (events & C::POLLIN).nonzero?
|
175
|
+
yield :readable, lucciola
|
176
|
+
end
|
177
|
+
|
178
|
+
if (events & C::POLLOUT).nonzero?
|
179
|
+
yield :writable, lucciola
|
180
|
+
end
|
181
|
+
end
|
182
|
+
elsif fd == @breaker.to_i
|
183
|
+
yield :break, @breaker.reason
|
184
|
+
else
|
185
|
+
raise "#{fd} isn't trapped here"
|
186
|
+
end
|
187
|
+
|
188
|
+
n += 1
|
189
|
+
end
|
190
|
+
|
191
|
+
self
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
def index_of (what)
|
196
|
+
@descriptors.keys.index(what.to_i)
|
197
|
+
end
|
198
|
+
rescue Exception
|
199
|
+
def self.supported?
|
200
|
+
false
|
201
|
+
end
|
202
|
+
end; end
|
203
|
+
|
204
|
+
end; end
|
@@ -17,8 +17,6 @@
|
|
17
17
|
# along with barlume. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
#++
|
19
19
|
|
20
|
-
require 'ffi'
|
21
|
-
|
22
20
|
module Barlume; class Lanterna
|
23
21
|
|
24
22
|
class Epoll < Lanterna; begin
|
@@ -48,9 +46,7 @@ class Epoll < Lanterna; begin
|
|
48
46
|
attach_function :epoll_create, [:int], :int
|
49
47
|
attach_function :epoll_create1, [:int], :int
|
50
48
|
attach_function :epoll_ctl, [:int, Control, :int, :pointer], :int
|
51
|
-
attach_function :epoll_wait, [:int, :pointer, :int, :int], :int
|
52
|
-
|
53
|
-
MAX = 4294967295
|
49
|
+
attach_function :epoll_wait, [:int, :pointer, :int, :int], :int, :blocking => true
|
54
50
|
|
55
51
|
EPOLLIN = 0x001
|
56
52
|
EPOLLPRI = 0x002
|
@@ -89,114 +85,146 @@ class Epoll < Lanterna; begin
|
|
89
85
|
}
|
90
86
|
end
|
91
87
|
|
88
|
+
attr_reader :size
|
89
|
+
|
92
90
|
def initialize
|
93
91
|
super
|
94
92
|
|
95
93
|
FFI.raise_if((@fd = C.epoll_create1(0)) < 0)
|
96
94
|
|
97
|
-
|
98
|
-
|
99
|
-
|
95
|
+
@ev = C::EpollEvent.new
|
96
|
+
@ev[:events] = C::EPOLLIN
|
97
|
+
@ev[:data][:fd] = @breaker.to_i
|
100
98
|
|
101
|
-
FFI.raise_if(C.epoll_ctl(@fd, :add, @breaker.to_i,
|
99
|
+
FFI.raise_if(C.epoll_ctl(@fd, :add, @breaker.to_i, @ev) < 0)
|
102
100
|
|
103
101
|
self.size = 4096
|
104
102
|
end
|
105
103
|
|
106
|
-
def size
|
107
|
-
@events.size / C::EpollEvent.size
|
108
|
-
end
|
109
|
-
|
110
104
|
def size= (n)
|
111
105
|
@events = FFI::MemoryPointer.new C::EpollEvent.size, n
|
106
|
+
@size = @events.size / C::EpollEvent.size
|
107
|
+
end
|
108
|
+
|
109
|
+
def edge_triggered?; @edge; end
|
110
|
+
def level_triggered?; !@edge; end
|
111
|
+
|
112
|
+
def edge_triggered!
|
113
|
+
@edge = true
|
114
|
+
|
115
|
+
each {|l|
|
116
|
+
@ev[:events] = C::EPOLLET | (l.readable? ? C::EPOLLIN : 0) | (l.writable? ? C::EPOLLOUT : 0)
|
117
|
+
@ev[:data][:fd] = l.to_i
|
118
|
+
|
119
|
+
FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
def level_triggered!
|
124
|
+
@edge = false
|
125
|
+
|
126
|
+
each {|l|
|
127
|
+
@ev[:events] = (l.readable? ? C::EPOLLIN : 0) | (l.writable? ? C::EPOLLOUT : 0)
|
128
|
+
@ev[:data][:fd] = l.to_i
|
129
|
+
|
130
|
+
FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
|
131
|
+
}
|
112
132
|
end
|
113
133
|
|
114
|
-
def add (
|
115
|
-
super
|
116
|
-
|
134
|
+
def add (*)
|
135
|
+
super {|l|
|
136
|
+
@ev[:events] = 0
|
137
|
+
@ev[:data][:fd] = l.to_i
|
117
138
|
|
118
|
-
@
|
139
|
+
FFI.raise_if(C.epoll_ctl(@fd, :add, l.to_i, @ev) < 0)
|
119
140
|
}
|
120
141
|
end
|
121
142
|
|
122
|
-
def remove (
|
123
|
-
super
|
143
|
+
def remove (*)
|
144
|
+
super {|l|
|
124
145
|
begin
|
125
146
|
FFI.raise_if(C.epoll_ctl(@fd, :del, l.to_i, nil) < 0)
|
126
147
|
rescue Errno::ENOENT; end
|
127
|
-
|
128
|
-
@last = nil
|
129
148
|
}
|
130
149
|
end
|
131
150
|
|
132
|
-
def
|
133
|
-
|
151
|
+
def readable! (*)
|
152
|
+
super {|l|
|
153
|
+
@ev[:events] = C::EPOLLIN | (l.writable? ? C::EPOLLOUT : 0) | (edge_triggered? ? C::EPOLLET : 0)
|
154
|
+
@ev[:data][:fd] = l.to_i
|
134
155
|
|
135
|
-
|
156
|
+
FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
|
157
|
+
}
|
136
158
|
end
|
137
159
|
|
138
|
-
def
|
139
|
-
|
160
|
+
def no_readable! (*)
|
161
|
+
super {|l|
|
162
|
+
@ev[:events] = (l.writable? ? C::EPOLLOUT : 0) | (edge_triggered? ? C::EPOLLET : 0)
|
163
|
+
@ev[:data][:fd] = l.to_i
|
140
164
|
|
141
|
-
|
142
|
-
|
143
|
-
else
|
144
|
-
to :read
|
145
|
-
end
|
165
|
+
FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
|
166
|
+
}
|
146
167
|
end
|
147
168
|
|
148
|
-
def writable (
|
149
|
-
|
169
|
+
def writable! (*)
|
170
|
+
super {|l|
|
171
|
+
@ev[:events] = C::EPOLLOUT | (l.readable? ? C::EPOLLIN : 0) | (edge_triggered? ? C::EPOLLET : 0)
|
172
|
+
@ev[:data][:fd] = l.to_i
|
150
173
|
|
151
|
-
|
152
|
-
|
153
|
-
else
|
154
|
-
to :write
|
155
|
-
end
|
174
|
+
FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
|
175
|
+
}
|
156
176
|
end
|
157
177
|
|
158
|
-
def
|
159
|
-
|
178
|
+
def no_writable! (*)
|
179
|
+
super {|l|
|
180
|
+
@ev[:events] = (l.readable? ? C::EPOLLIN : 0) | (edge_triggered? ? C::EPOLLET : 0)
|
181
|
+
@ev[:data][:fd] = l.to_i
|
160
182
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
when :read then C::EPOLLIN
|
165
|
-
when :write then C::EPOLLOUT
|
166
|
-
end
|
183
|
+
FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
|
184
|
+
}
|
185
|
+
end
|
167
186
|
|
168
|
-
|
169
|
-
|
187
|
+
def available (timeout = nil, &block)
|
188
|
+
return enum_for :available, timeout unless block
|
170
189
|
|
171
|
-
|
172
|
-
}
|
190
|
+
FFI.raise_if((length = C.epoll_wait(@fd, @events, @size, timeout ? timeout * 1000 : -1)) < 0)
|
173
191
|
|
174
|
-
|
175
|
-
|
192
|
+
if length == 0
|
193
|
+
yield :timeout, timeout
|
176
194
|
|
177
|
-
|
178
|
-
result = []
|
179
|
-
events = case what
|
180
|
-
when :read then C::EPOLLIN
|
181
|
-
when :write then C::EPOLLOUT
|
182
|
-
when :error then C::EPOLLERR | C::EPOLLHUP
|
195
|
+
return self
|
183
196
|
end
|
184
197
|
|
185
|
-
0
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
198
|
+
n = 0
|
199
|
+
size = C::EpollEvent.size
|
200
|
+
while n < length
|
201
|
+
p = C::EpollEvent.new(@events + (n * size))
|
202
|
+
events = p[:events]
|
203
|
+
fd = p[:data][:fd]
|
204
|
+
lucciola = self[fd]
|
205
|
+
|
206
|
+
if lucciola
|
207
|
+
if (events & (C::EPOLLERR | C::EPOLLHUP)).nonzero?
|
208
|
+
yield :error, lucciola
|
209
|
+
else
|
210
|
+
if (events & C::EPOLLIN).nonzero?
|
211
|
+
yield :readable, lucciola
|
212
|
+
end
|
213
|
+
|
214
|
+
if (events & C::EPOLLOUT).nonzero?
|
215
|
+
yield :writable, lucciola
|
216
|
+
end
|
217
|
+
end
|
218
|
+
elsif fd == @breaker.to_i
|
219
|
+
yield :break, @breaker.reason
|
220
|
+
else
|
221
|
+
raise "#{fd} isn't trapped here"
|
190
222
|
end
|
191
|
-
}
|
192
|
-
|
193
|
-
result
|
194
|
-
end
|
195
223
|
|
196
|
-
|
197
|
-
|
224
|
+
n += 1
|
225
|
+
end
|
198
226
|
|
199
|
-
|
227
|
+
self
|
200
228
|
end
|
201
229
|
rescue Exception
|
202
230
|
def self.supported?
|
@@ -17,13 +17,16 @@
|
|
17
17
|
# along with barlume. If not, see <http://www.gnu.org/licenses/>.
|
18
18
|
#++
|
19
19
|
|
20
|
+
require 'backports'
|
20
21
|
require 'ffi'
|
21
22
|
|
22
23
|
module FFI
|
23
|
-
def self.
|
24
|
-
|
24
|
+
def self.errno_exception
|
25
|
+
Errno.const_get(Errno.constants[FFI.errno]).new
|
26
|
+
end
|
25
27
|
|
26
|
-
|
28
|
+
def self.raise
|
29
|
+
Kernel.raise errno_exception
|
27
30
|
rescue Exception => e
|
28
31
|
e.backtrace.shift(3)
|
29
32
|
|