barlume 0.0.1.rc.1
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/README.md +2 -0
- data/barlume.gemspec +18 -0
- data/examples/test.rb +27 -0
- data/lib/barlume.rb +20 -0
- data/lib/barlume/lanterna.rb +134 -0
- data/lib/barlume/lanterna/epoll.rb +207 -0
- data/lib/barlume/lanterna/kqueue.rb +249 -0
- data/lib/barlume/lanterna/poll.rb +177 -0
- data/lib/barlume/lanterna/select.rb +83 -0
- data/lib/barlume/lanterna/utils.rb +48 -0
- data/lib/barlume/lucciola.rb +108 -0
- data/lib/barlume/version.rb +24 -0
- metadata +72 -0
data/README.md
ADDED
data/barlume.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Kernel.load 'lib/barlume/version.rb'
|
2
|
+
|
3
|
+
Gem::Specification.new {|s|
|
4
|
+
s.name = 'barlume'
|
5
|
+
s.version = Barlume.version
|
6
|
+
s.author = 'meh.'
|
7
|
+
s.email = 'meh@paranoici.org'
|
8
|
+
s.homepage = 'http://github.com/meh/barlume'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'A dim light over asynchronous I/O land.'
|
11
|
+
|
12
|
+
s.files = `git ls-files`.split("\n")
|
13
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.require_paths = ['lib']
|
16
|
+
|
17
|
+
s.add_dependency 'ffi'
|
18
|
+
}
|
data/examples/test.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'barlume'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
lantern = Barlume::Lanterna.best
|
6
|
+
server = TCPServer.new 43215
|
7
|
+
clients = []
|
8
|
+
|
9
|
+
puts "Using #{lantern.name}..."
|
10
|
+
|
11
|
+
lantern << server
|
12
|
+
|
13
|
+
loop do
|
14
|
+
lantern.readable.each {|lucciola|
|
15
|
+
if lucciola == server
|
16
|
+
server.accept.tap {|client|
|
17
|
+
clients.push(lantern.add(client))
|
18
|
+
}
|
19
|
+
else
|
20
|
+
puts lucciola.readline rescue nil
|
21
|
+
|
22
|
+
if lucciola.closed?
|
23
|
+
clients.delete(lantern.remove(lucciola))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
data/lib/barlume.rb
ADDED
@@ -0,0 +1,20 @@
|
|
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
|
+
require 'barlume/lanterna'
|
@@ -0,0 +1,134 @@
|
|
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
|
+
require 'barlume/lucciola'
|
21
|
+
|
22
|
+
module Barlume
|
23
|
+
|
24
|
+
class Lanterna
|
25
|
+
class << self
|
26
|
+
%w[select poll epoll kqueue].each {|name|
|
27
|
+
define_method "#{name}?" do
|
28
|
+
const_get(name.capitalize).supported?
|
29
|
+
end
|
30
|
+
|
31
|
+
define_method name do
|
32
|
+
const_get(name.capitalize).new
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
def best
|
37
|
+
return kqueue if kqueue?
|
38
|
+
|
39
|
+
return epoll if epoll?
|
40
|
+
|
41
|
+
return poll if poll?
|
42
|
+
|
43
|
+
return select
|
44
|
+
end
|
45
|
+
|
46
|
+
def new (*)
|
47
|
+
raise 'unsupported platform' unless supported?
|
48
|
+
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Available = Struct.new(:readable, :writable, :error)
|
54
|
+
|
55
|
+
class Breaker
|
56
|
+
def initialize
|
57
|
+
@pipes = IO.pipe
|
58
|
+
end
|
59
|
+
|
60
|
+
def break
|
61
|
+
@pipes.last.write_nonblock 'x'
|
62
|
+
end
|
63
|
+
|
64
|
+
def flush
|
65
|
+
@pipes.first.read_nonblock 2048 rescue nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_io
|
69
|
+
@pipes.first
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_i
|
73
|
+
to_io.to_i
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_reader :descriptors
|
78
|
+
|
79
|
+
def initialize
|
80
|
+
@breaker = Breaker.new
|
81
|
+
@descriptors = []
|
82
|
+
@report_errors = false
|
83
|
+
end
|
84
|
+
|
85
|
+
def name
|
86
|
+
self.class.name[/(?:::)?([^:]*)$/, 1].downcase.to_sym
|
87
|
+
end
|
88
|
+
|
89
|
+
def report_errors?
|
90
|
+
@report_errors
|
91
|
+
end
|
92
|
+
|
93
|
+
def report_errors!
|
94
|
+
@report_errors = true
|
95
|
+
end
|
96
|
+
|
97
|
+
def dont_report_errors!
|
98
|
+
@report_errors = false
|
99
|
+
end
|
100
|
+
|
101
|
+
def break
|
102
|
+
@breaker.break
|
103
|
+
end
|
104
|
+
|
105
|
+
def add (what)
|
106
|
+
Lucciola.wrap(what).tap {|l|
|
107
|
+
return false if @descriptors.member?(l)
|
108
|
+
|
109
|
+
@descriptors.push(l)
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def push (*args)
|
114
|
+
args.each { |a| add a }
|
115
|
+
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
alias << push
|
120
|
+
|
121
|
+
def remove (what)
|
122
|
+
@descriptors.delete(Lucciola.wrap(what))
|
123
|
+
end
|
124
|
+
|
125
|
+
alias delete remove
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
require 'barlume/lanterna/utils'
|
131
|
+
require 'barlume/lanterna/select'
|
132
|
+
require 'barlume/lanterna/poll'
|
133
|
+
require 'barlume/lanterna/epoll'
|
134
|
+
require 'barlume/lanterna/kqueue'
|
@@ -0,0 +1,207 @@
|
|
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
|
+
require 'ffi'
|
21
|
+
|
22
|
+
module Barlume; class Lanterna
|
23
|
+
|
24
|
+
class Epoll < Lanterna; begin
|
25
|
+
module C
|
26
|
+
extend FFI::Library
|
27
|
+
|
28
|
+
ffi_lib FFI::Library::LIBC
|
29
|
+
|
30
|
+
class EpollData < FFI::Union
|
31
|
+
layout \
|
32
|
+
:ptr, :pointer,
|
33
|
+
:fd, :int,
|
34
|
+
:u32, :uint32,
|
35
|
+
:u64, :uint64
|
36
|
+
end
|
37
|
+
|
38
|
+
class EpollEvent < FFI::Struct
|
39
|
+
pack 1
|
40
|
+
|
41
|
+
layout \
|
42
|
+
:events, :uint32,
|
43
|
+
:data, EpollData
|
44
|
+
end
|
45
|
+
|
46
|
+
Control = FFI::Enum.new([:add, 1, :del, :mod])
|
47
|
+
|
48
|
+
attach_function :epoll_create, [:int], :int
|
49
|
+
attach_function :epoll_create1, [:int], :int
|
50
|
+
attach_function :epoll_ctl, [:int, Control, :int, :pointer], :int
|
51
|
+
attach_function :epoll_wait, [:int, :pointer, :int, :int], :int
|
52
|
+
|
53
|
+
MAX = 4294967295
|
54
|
+
|
55
|
+
EPOLLIN = 0x001
|
56
|
+
EPOLLPRI = 0x002
|
57
|
+
EPOLLOUT = 0x004
|
58
|
+
|
59
|
+
EPOLLERR = 0x008
|
60
|
+
EPOLLHUP = 0x010
|
61
|
+
EPOLLNVAL = 0x020
|
62
|
+
|
63
|
+
EPOLLRDNORM = 0x040
|
64
|
+
EPOLLRDBAND = 0x080
|
65
|
+
EPOLLWRNORM = 0x100
|
66
|
+
EPOLLWRBAND = 0x200
|
67
|
+
|
68
|
+
EPOLLMSG = 0x0400
|
69
|
+
EPOLLREMOVE = 0x1000
|
70
|
+
EPOLLRDHUP = 0x2000
|
71
|
+
|
72
|
+
EPOLLONESHOT = 1 << 30
|
73
|
+
EPOLLET = 1 << 31
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.supported?
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.new (*)
|
81
|
+
super.tap {|c|
|
82
|
+
ObjectSpace.define_finalizer c, finalizer(c.instance_variable_get :@fd)
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.finalizer (fd)
|
87
|
+
proc {
|
88
|
+
IO.for_fd(fd).close
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
def initialize
|
93
|
+
super
|
94
|
+
|
95
|
+
FFI.raise_if((@fd = C.epoll_create1(0)) < 0)
|
96
|
+
|
97
|
+
p = C::EpollEvent.new
|
98
|
+
p[:events] = C::EPOLLIN
|
99
|
+
p[:data][:u32] = C::MAX
|
100
|
+
|
101
|
+
FFI.raise_if(C.epoll_ctl(@fd, :add, @breaker.to_i, p) < 0)
|
102
|
+
|
103
|
+
self.size = 4096
|
104
|
+
end
|
105
|
+
|
106
|
+
def size
|
107
|
+
@events.size / C::EpollEvent.size
|
108
|
+
end
|
109
|
+
|
110
|
+
def size= (n)
|
111
|
+
@events = FFI::MemoryPointer.new C::EpollEvent.size, n
|
112
|
+
end
|
113
|
+
|
114
|
+
def add (what)
|
115
|
+
super.tap {|l|
|
116
|
+
FFI.raise_if(C.epoll_ctl(@fd, :add, l.to_i, C::EpollEvent.new) < 0)
|
117
|
+
|
118
|
+
@last = nil
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def remove (what)
|
123
|
+
super.tap {|l|
|
124
|
+
begin
|
125
|
+
FFI.raise_if(C.epoll_ctl(@fd, :del, l.to_i, nil) < 0)
|
126
|
+
rescue Errno::ENOENT; end
|
127
|
+
|
128
|
+
@last = nil
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
def available (timeout = nil)
|
133
|
+
set :both; epoll timeout
|
134
|
+
|
135
|
+
Available.new(to(:read), to(:write), to(:error))
|
136
|
+
end
|
137
|
+
|
138
|
+
def readable (timeout = nil)
|
139
|
+
set :read; epoll timeout
|
140
|
+
|
141
|
+
if report_errors?
|
142
|
+
[to(:read), to(:error)]
|
143
|
+
else
|
144
|
+
to :read
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def writable (timeout = nil)
|
149
|
+
set :write; epoll timeout
|
150
|
+
|
151
|
+
if report_errors?
|
152
|
+
[to(:write), to(:error)]
|
153
|
+
else
|
154
|
+
to :write
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def set (what)
|
159
|
+
return if @last == what
|
160
|
+
|
161
|
+
p = C::EpollEvent.new
|
162
|
+
p[:events] = case what
|
163
|
+
when :both then C::EPOLLIN | C::EPOLLOUT
|
164
|
+
when :read then C::EPOLLIN
|
165
|
+
when :write then C::EPOLLOUT
|
166
|
+
end
|
167
|
+
|
168
|
+
descriptors.each_with_index {|descriptor, index|
|
169
|
+
p[:data][:u32] = index
|
170
|
+
|
171
|
+
FFI.raise_if(C.epoll_ctl(@fd, :mod, descriptor.to_i, p) < 0)
|
172
|
+
}
|
173
|
+
|
174
|
+
@last = what
|
175
|
+
end
|
176
|
+
|
177
|
+
def to (what)
|
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
|
183
|
+
end
|
184
|
+
|
185
|
+
0.upto(@length - 1) {|n|
|
186
|
+
p = C::EpollEvent.new(@events + (n * C::EpollEvent.size))
|
187
|
+
|
188
|
+
if p[:data][:u32] != C::MAX && (p[:events] & events).nonzero?
|
189
|
+
result << descriptors[p[:data][:u32]]
|
190
|
+
end
|
191
|
+
}
|
192
|
+
|
193
|
+
result
|
194
|
+
end
|
195
|
+
|
196
|
+
def epoll (timeout = nil)
|
197
|
+
FFI.raise_if((@length = C.epoll_wait(@fd, @events, size, timeout ? timeout * 1000 : -1)) < 0)
|
198
|
+
|
199
|
+
@breaker.flush
|
200
|
+
end
|
201
|
+
rescue Exception
|
202
|
+
def self.supported?
|
203
|
+
false
|
204
|
+
end
|
205
|
+
end; end
|
206
|
+
|
207
|
+
end; end
|
@@ -0,0 +1,249 @@
|
|
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 Kqueue < Lanterna; begin
|
23
|
+
module C
|
24
|
+
extend FFI::Library
|
25
|
+
|
26
|
+
ffi_lib FFI::Library::LIBC
|
27
|
+
|
28
|
+
class Kevent < FFI::Struct
|
29
|
+
layout \
|
30
|
+
:ident, :intptr_t,
|
31
|
+
:filter, :short,
|
32
|
+
:flags, :ushort,
|
33
|
+
:fflags, :uint,
|
34
|
+
:data, :long,
|
35
|
+
:udata, :pointer
|
36
|
+
end
|
37
|
+
|
38
|
+
class TimeSpec < FFI::Struct
|
39
|
+
layout \
|
40
|
+
:tv_sec, :time_t,
|
41
|
+
:tv_nsec, :int
|
42
|
+
end
|
43
|
+
|
44
|
+
attach_function :kqueue, [], :int
|
45
|
+
attach_function :kevent, [:int, :pointer, :int, :pointer, :int, :pointer], :int
|
46
|
+
|
47
|
+
MAX = 4294967295
|
48
|
+
|
49
|
+
EVFILT_READ = -1
|
50
|
+
EVFILT_WRITE = -2
|
51
|
+
EVFILT_AIO = -3
|
52
|
+
EVFILT_VNODE = -4
|
53
|
+
EVFILT_PROC = -5
|
54
|
+
EVFILT_SIGNAL = -6
|
55
|
+
EVFILT_TIMER = -7
|
56
|
+
EVFILT_NETDEV = -8
|
57
|
+
EVFILT_FS = -9
|
58
|
+
EVFILT_LIO = -10
|
59
|
+
EVFILT_USER = -11
|
60
|
+
EVFILT_SYSCOUNT = 11
|
61
|
+
|
62
|
+
EV_ADD = 0x0001
|
63
|
+
EV_DELETE = 0x0002
|
64
|
+
EV_ENABLE = 0x0004
|
65
|
+
EV_DISABLE = 0x0008
|
66
|
+
EV_ONESHOT = 0x0010
|
67
|
+
EV_CLEAR = 0x0020
|
68
|
+
EV_RECEIPT = 0x0040
|
69
|
+
EV_DISPATCH = 0x0080
|
70
|
+
EV_SYSFLAGS = 0xF000
|
71
|
+
EV_FLAG1 = 0x2000
|
72
|
+
EV_EOF = 0x8000
|
73
|
+
EV_ERROR = 0x4000
|
74
|
+
|
75
|
+
def self.EV_SET (event, a, b, c, d, e, f)
|
76
|
+
event[:ident] = a
|
77
|
+
event[:filter] = b
|
78
|
+
event[:flags] = c
|
79
|
+
event[:fflags] = d
|
80
|
+
event[:data] = e
|
81
|
+
event[:udata] = f
|
82
|
+
|
83
|
+
event
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.supported?
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.new (*)
|
92
|
+
super.tap {|c|
|
93
|
+
ObjectSpace.define_finalizer c, finalizer(c.instance_variable_get :@fd)
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.finalizer (fd)
|
98
|
+
proc {
|
99
|
+
IO.for_fd(fd).close
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def initialize
|
104
|
+
super
|
105
|
+
|
106
|
+
FFI.raise_if((@fd = C.kqueue) < 0)
|
107
|
+
|
108
|
+
if C.kevent(@fd, C::EV_SET(C::Kevent.new, @breaker.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_ENABLE, 0, 0, FFI::Pointer.new(C::MAX)), 1, nil, 0, nil) < 0
|
109
|
+
FFI.raise
|
110
|
+
end
|
111
|
+
|
112
|
+
self.size = 4096
|
113
|
+
end
|
114
|
+
|
115
|
+
def size
|
116
|
+
@events.size / C::Kevent.size
|
117
|
+
end
|
118
|
+
|
119
|
+
def size= (n)
|
120
|
+
@events = FFI::MemoryPointer.new C::Kevent.size, n
|
121
|
+
end
|
122
|
+
|
123
|
+
def add (*)
|
124
|
+
super.tap {
|
125
|
+
@last = nil
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
def remove (what)
|
130
|
+
super.tap {|l|
|
131
|
+
begin
|
132
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(C::Kevent.new, what.to_i, C::EVFILT_READ, C::EV_DELETE | C::EV_DISABLE, 0, 0, 0), 1, nil, 0, nil) < 0)
|
133
|
+
rescue Errno::ENOENT; end
|
134
|
+
|
135
|
+
begin
|
136
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(C::Kevent.new, what.to_i, C::EVFILT_WRITE, C::EV_DELETE | C::EV_DISABLE, 0, 0, 0), 1, nil, 0, nil) < 0)
|
137
|
+
rescue Errno::ENOENT; end
|
138
|
+
|
139
|
+
@last = nil
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
def available (timeout = nil)
|
144
|
+
set :both; kevent timeout
|
145
|
+
|
146
|
+
Available.new(to(:read), to(:write), to(:error))
|
147
|
+
end
|
148
|
+
|
149
|
+
def readable (timeout = nil)
|
150
|
+
set :read; kevent timeout
|
151
|
+
|
152
|
+
if report_errors?
|
153
|
+
[to(:read), to(:error)]
|
154
|
+
else
|
155
|
+
to :read
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def writable (timeout = nil)
|
160
|
+
set :write; kevent timeout
|
161
|
+
|
162
|
+
if report_errors?
|
163
|
+
[to(:write), to(:error)]
|
164
|
+
else
|
165
|
+
to :write
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def set (what)
|
170
|
+
return if @last == what
|
171
|
+
|
172
|
+
ev = C::Kevent.new
|
173
|
+
|
174
|
+
if what == :read
|
175
|
+
descriptors.each_with_index {|descriptor, index|
|
176
|
+
index = FFI::Pointer.new(index)
|
177
|
+
|
178
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(ev, descriptor.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_ENABLE, 0, 0, index), 1, nil, 0, nil) < 0)
|
179
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(ev, descriptor.to_i, C::EVFILT_WRITE, C::EV_ADD | C::EV_DISABLE, 0, 0, index), 1, nil, 0, nil) < 0)
|
180
|
+
}
|
181
|
+
elsif what == :write
|
182
|
+
descriptors.each_with_index {|descriptor, index|
|
183
|
+
index = FFI::Pointer.new(index)
|
184
|
+
|
185
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(ev, descriptor.to_i, C::EVFILT_WRITE, C::EV_ADD | C::EV_ENABLE, 0, 0, index), 1, nil, 0, nil) < 0)
|
186
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(ev, descriptor.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_DISABLE, 0, 0, index), 1, nil, 0, nil) < 0)
|
187
|
+
}
|
188
|
+
else
|
189
|
+
descriptors.each_with_index {|descriptor, index|
|
190
|
+
index = FFI::Pointer.new(index)
|
191
|
+
|
192
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(ev, descriptor.to_i, C::EVFILT_WRITE, C::EV_ADD | C::EV_ENABLE, 0, 0, index), 1, nil, 0, nil) < 0)
|
193
|
+
FFI.raise_if(C.kevent(@fd, C::EV_SET(ev, descriptor.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_ENABLE, 0, 0, index), 1, nil, 0, nil) < 0)
|
194
|
+
}
|
195
|
+
end
|
196
|
+
|
197
|
+
@last = what
|
198
|
+
end
|
199
|
+
|
200
|
+
def to (what)
|
201
|
+
result = []
|
202
|
+
|
203
|
+
if what == :error
|
204
|
+
0.upto(@length - 1) {|n|
|
205
|
+
p = C::Kevent.new(@events + (n * C::Kevent.size))
|
206
|
+
index = p[:udata].address
|
207
|
+
|
208
|
+
if p != index && (p[:flags] & C::EV_ERROR).nonzero?
|
209
|
+
result << descriptors[index]
|
210
|
+
end
|
211
|
+
}
|
212
|
+
else
|
213
|
+
filter = case what
|
214
|
+
when :read then C::EVFILT_READ
|
215
|
+
when :write then C::EVFILT_WRITE
|
216
|
+
end
|
217
|
+
|
218
|
+
0.upto(@length - 1) {|n|
|
219
|
+
p = C::Kevent.new(@events + (n * C::Kevent.size))
|
220
|
+
index = p[:udata].address
|
221
|
+
|
222
|
+
if index != C::MAX && p[:filter] == filter
|
223
|
+
result << descriptors[index]
|
224
|
+
end
|
225
|
+
}
|
226
|
+
end
|
227
|
+
|
228
|
+
result
|
229
|
+
end
|
230
|
+
|
231
|
+
def kevent (timeout = nil)
|
232
|
+
if timeout
|
233
|
+
timeout = C::TimeSpec.new.tap {|t|
|
234
|
+
t[:tv_sec] = timeout.to_i
|
235
|
+
t[:tv_nsec] = (timeout - timeout.to_i) * 1000
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
FFI.raise_if((@length = C.kevent(@fd, nil, 0, @events, size, timeout)) < 0)
|
240
|
+
|
241
|
+
@breaker.flush
|
242
|
+
end
|
243
|
+
rescue Exception
|
244
|
+
def self.supported?
|
245
|
+
false
|
246
|
+
end
|
247
|
+
end; end
|
248
|
+
|
249
|
+
end; end
|
@@ -0,0 +1,177 @@
|
|
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
|
+
require 'ffi'
|
21
|
+
|
22
|
+
module Barlume; class Lanterna
|
23
|
+
|
24
|
+
class Poll < Lanterna; begin
|
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
|
+
attach_function :poll, [:pointer, :ulong, :int], :int
|
38
|
+
|
39
|
+
attach_function :malloc, [:size_t], :pointer
|
40
|
+
attach_function :realloc, [:pointer, :size_t], :pointer
|
41
|
+
attach_function :free, [:pointer], :void
|
42
|
+
|
43
|
+
POLLIN = 0x001
|
44
|
+
POLLPRI = 0x002
|
45
|
+
POLLOUT = 0x004
|
46
|
+
|
47
|
+
POLLERR = 0x008
|
48
|
+
POLLHUP = 0x010
|
49
|
+
POLLNVAL = 0x020
|
50
|
+
|
51
|
+
POLLRDNORM = 0x040
|
52
|
+
POLLRDBAND = 0x080
|
53
|
+
POLLWRNORM = 0x100
|
54
|
+
POLLWRBAND = 0x200
|
55
|
+
|
56
|
+
POLLMSG = 0x0400
|
57
|
+
POLLREMOVE = 0x1000
|
58
|
+
POLLRDHUP = 0x2000
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.supported?
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize
|
66
|
+
super
|
67
|
+
|
68
|
+
@set = FFI::AutoPointer.new(C.malloc(C::PollFD.size), C.method(:free))
|
69
|
+
|
70
|
+
pfd = C::PollFD.new(@set + 0)
|
71
|
+
pfd[:fd] = @breaker.to_i
|
72
|
+
pfd[:events] = C::POLLIN
|
73
|
+
end
|
74
|
+
|
75
|
+
def add (what)
|
76
|
+
super.tap {|l|
|
77
|
+
next unless l
|
78
|
+
|
79
|
+
@set.autorelease = false
|
80
|
+
@set = FFI::AutoPointer.new(C.realloc(@set, (descriptors.length + 1) * C::PollFD.size), C.method(:free))
|
81
|
+
|
82
|
+
pfd = C::PollFD.new(@set + descriptors.length * C::PollFD.size)
|
83
|
+
pfd[:fd] = l.to_i
|
84
|
+
|
85
|
+
@last = nil
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def remove (what)
|
90
|
+
Lucciola.wrap(what).tap {|l|
|
91
|
+
index = descriptors.index(l)
|
92
|
+
offset = (index + 1) * C::PollFD.size
|
93
|
+
pointer = @set + offset
|
94
|
+
|
95
|
+
pointer.write_bytes((pointer + C::PollFD.size).read_bytes((descriptors.length - index) * C::PollFD.size))
|
96
|
+
|
97
|
+
@set.autorelease = false
|
98
|
+
@set = FFI::AutoPointer.new(C.realloc(@set, (descriptors.length) * C::PollFD.size), C.method(:free))
|
99
|
+
|
100
|
+
super(l)
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def available (timeout = nil)
|
105
|
+
set :both; poll timeout
|
106
|
+
|
107
|
+
Available.new(to(:read), to(:write), to(:error))
|
108
|
+
end
|
109
|
+
|
110
|
+
def readable (timeout = nil)
|
111
|
+
set :read; poll timeout
|
112
|
+
|
113
|
+
if report_errors?
|
114
|
+
[to(:read), to(:error)]
|
115
|
+
else
|
116
|
+
to :read
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def writable (timeout = nil)
|
121
|
+
set :write; poll timeout
|
122
|
+
|
123
|
+
if report_errors?
|
124
|
+
[to(:write), to(:error)]
|
125
|
+
else
|
126
|
+
to :write
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def set (what)
|
131
|
+
return if @last == what
|
132
|
+
|
133
|
+
events = case what
|
134
|
+
when :both then C::POLLIN | C::POLLOUT
|
135
|
+
when :read then C::POLLIN
|
136
|
+
when :write then C::POLLOUT
|
137
|
+
end
|
138
|
+
|
139
|
+
1.upto(descriptors.length) {|n|
|
140
|
+
pfd = C::PollFD.new(@set + (n * C::PollFD.size))
|
141
|
+
pfd[:events] = events
|
142
|
+
}
|
143
|
+
|
144
|
+
@last = what
|
145
|
+
end
|
146
|
+
|
147
|
+
def to (what)
|
148
|
+
result = []
|
149
|
+
events = case what
|
150
|
+
when :read then C::POLLIN
|
151
|
+
when :write then C::POLLOUT
|
152
|
+
when :error then C::POLLERR | C::POLLHUP
|
153
|
+
end
|
154
|
+
|
155
|
+
1.upto(descriptors.length) {|n|
|
156
|
+
pfd = C::PollFD.new(@set + (n * C::PollFD.size))
|
157
|
+
|
158
|
+
if (pfd[:revents] & events).nonzero?
|
159
|
+
result << descriptors[n - 1]
|
160
|
+
end
|
161
|
+
}
|
162
|
+
|
163
|
+
result
|
164
|
+
end
|
165
|
+
|
166
|
+
def poll (timeout = nil)
|
167
|
+
FFI.raise_if(C.poll(@set, descriptors.length + 1, timeout ? timeout * 1000 : -1) < 0)
|
168
|
+
|
169
|
+
@breaker.flush
|
170
|
+
end
|
171
|
+
rescue Exception
|
172
|
+
def self.supported?
|
173
|
+
false
|
174
|
+
end
|
175
|
+
end; end
|
176
|
+
|
177
|
+
end; end
|
@@ -0,0 +1,83 @@
|
|
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 Select < Lanterna
|
23
|
+
def self.supported?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def add (*)
|
28
|
+
super.tap {
|
29
|
+
@descriptors_with_breaker = nil
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove (*)
|
34
|
+
super.tap {
|
35
|
+
@descriptors_with_breaker = nil
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def available (timeout = nil)
|
40
|
+
readable, writable, error = IO.select(descriptors_with_breaker, descriptors, descriptors, timeout)
|
41
|
+
|
42
|
+
if readable && readable.delete(@breaker.to_io)
|
43
|
+
@breaker.flush
|
44
|
+
end
|
45
|
+
|
46
|
+
Available.new(readable || [], writable || [], error || [])
|
47
|
+
end
|
48
|
+
|
49
|
+
def readable (timeout = nil)
|
50
|
+
readable, writable, error = IO.select(descriptors_with_breaker, nil, descriptors, timeout)
|
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)
|
65
|
+
|
66
|
+
if readable && readable.delete(@breaker.to_io)
|
67
|
+
@breaker.flush
|
68
|
+
end
|
69
|
+
|
70
|
+
if report_errors?
|
71
|
+
[writable || [], error || []]
|
72
|
+
else
|
73
|
+
writable || []
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def descriptors_with_breaker
|
79
|
+
@descriptors_with_breaker ||= [@breaker.to_io] + descriptors
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end; end
|
@@ -0,0 +1,48 @@
|
|
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
|
+
require 'ffi'
|
21
|
+
|
22
|
+
module FFI
|
23
|
+
def self.raise
|
24
|
+
value = FFI.errno
|
25
|
+
|
26
|
+
Kernel.raise Errno.constants[FFI.errno].new
|
27
|
+
rescue Exception => e
|
28
|
+
e.backtrace.shift(3)
|
29
|
+
|
30
|
+
Kernel.raise e
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.raise_unless (what)
|
34
|
+
what ? what : FFI.raise
|
35
|
+
rescue Exception => e
|
36
|
+
e.backtrace.shift(1)
|
37
|
+
|
38
|
+
Kernel.raise e
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.raise_if (what)
|
42
|
+
what ? FFI.raise : what
|
43
|
+
rescue Exception => e
|
44
|
+
e.backtrace.shift(1)
|
45
|
+
|
46
|
+
Kernel.raise e
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,108 @@
|
|
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
|
+
require 'fcntl'
|
21
|
+
|
22
|
+
module Barlume
|
23
|
+
|
24
|
+
class Lucciola
|
25
|
+
def self.wrap (what)
|
26
|
+
return what if what.is_a? self
|
27
|
+
|
28
|
+
new(what)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize (what)
|
32
|
+
@io = what.is_a?(::Integer) ? ::IO.for_fd(what) : what
|
33
|
+
|
34
|
+
unless @io.respond_to? :to_i
|
35
|
+
raise ArgumentError, 'the object must respond to to_i'
|
36
|
+
end
|
37
|
+
|
38
|
+
@fd = @io.to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def respond_to_missing? (*args)
|
42
|
+
@io.respond_to? *args
|
43
|
+
end
|
44
|
+
|
45
|
+
def method_missing (id, *args, &block)
|
46
|
+
if @io.respond_to? id
|
47
|
+
begin
|
48
|
+
return @io.__send__ id, *args, &block
|
49
|
+
rescue EOFError
|
50
|
+
@closed = true
|
51
|
+
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
def == (other)
|
60
|
+
to_i == other.to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
alias eql? ==
|
64
|
+
|
65
|
+
def equal? (other)
|
66
|
+
to_io == (other.respond_to?(:to_io) ? other.to_io : other)
|
67
|
+
end
|
68
|
+
|
69
|
+
def hash
|
70
|
+
to_i.hash
|
71
|
+
end
|
72
|
+
|
73
|
+
def closed?
|
74
|
+
@closed or @io.respond_to?(:closed?) ? @io.closed? : false
|
75
|
+
end
|
76
|
+
|
77
|
+
def nonblocking?
|
78
|
+
(@io.fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK).nonzero?
|
79
|
+
end
|
80
|
+
|
81
|
+
alias asynchronous? nonblocking?
|
82
|
+
|
83
|
+
def blocking?
|
84
|
+
!nonblocking?
|
85
|
+
end
|
86
|
+
|
87
|
+
def blocking!
|
88
|
+
@io.fcntl(Fcntl::F_SETFL, @io.fcntl(Fcntl::F_GETFL, 0) | Fcntl::O_NONBLOCK)
|
89
|
+
end
|
90
|
+
|
91
|
+
def nonblocking!
|
92
|
+
@io.fcntl(Fcntl::F_SETFL, @io.fcntl(Fcntl::F_GETFL, 0) & ~Fcntl::O_NONBLOCK)
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_io
|
96
|
+
@io
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_i
|
100
|
+
@fd
|
101
|
+
end
|
102
|
+
|
103
|
+
def inspect
|
104
|
+
"#<#{self.class.name}: #{to_io.inspect}>"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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
|
21
|
+
def self.version
|
22
|
+
'0.0.1.rc.1'
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: barlume
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.rc.1
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- meh.
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ffi
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description:
|
31
|
+
email: meh@paranoici.org
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- README.md
|
37
|
+
- barlume.gemspec
|
38
|
+
- examples/test.rb
|
39
|
+
- lib/barlume.rb
|
40
|
+
- lib/barlume/lanterna.rb
|
41
|
+
- lib/barlume/lanterna/epoll.rb
|
42
|
+
- lib/barlume/lanterna/kqueue.rb
|
43
|
+
- lib/barlume/lanterna/poll.rb
|
44
|
+
- lib/barlume/lanterna/select.rb
|
45
|
+
- lib/barlume/lanterna/utils.rb
|
46
|
+
- lib/barlume/lucciola.rb
|
47
|
+
- lib/barlume/version.rb
|
48
|
+
homepage: http://github.com/meh/barlume
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>'
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.3.1
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.24
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: A dim light over asynchronous I/O land.
|
72
|
+
test_files: []
|