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.
@@ -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
- p = C::EpollEvent.new
98
- p[:events] = C::EPOLLIN
99
- p[:data][:u32] = C::MAX
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, p) < 0)
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 (what)
115
- super.tap {|l|
116
- FFI.raise_if(C.epoll_ctl(@fd, :add, l.to_i, C::EpollEvent.new) < 0)
134
+ def add (*)
135
+ super {|l|
136
+ @ev[:events] = 0
137
+ @ev[:data][:fd] = l.to_i
117
138
 
118
- @last = nil
139
+ FFI.raise_if(C.epoll_ctl(@fd, :add, l.to_i, @ev) < 0)
119
140
  }
120
141
  end
121
142
 
122
- def remove (what)
123
- super.tap {|l|
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 available (timeout = nil)
133
- set :both; epoll timeout
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
- Available.new(to(:read), to(:write), to(:error))
156
+ FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
157
+ }
136
158
  end
137
159
 
138
- def readable (timeout = nil)
139
- set :read; epoll timeout
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
- if report_errors?
142
- [to(:read), to(:error)]
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 (timeout = nil)
149
- set :write; epoll timeout
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
- if report_errors?
152
- [to(:write), to(:error)]
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 set (what)
159
- return if @last == what
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
- 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
183
+ FFI.raise_if(C.epoll_ctl(@fd, :mod, l.to_i, @ev) < 0)
184
+ }
185
+ end
167
186
 
168
- descriptors.each_with_index {|descriptor, index|
169
- p[:data][:u32] = index
187
+ def available (timeout = nil, &block)
188
+ return enum_for :available, timeout unless block
170
189
 
171
- FFI.raise_if(C.epoll_ctl(@fd, :mod, descriptor.to_i, p) < 0)
172
- }
190
+ FFI.raise_if((length = C.epoll_wait(@fd, @events, @size, timeout ? timeout * 1000 : -1)) < 0)
173
191
 
174
- @last = what
175
- end
192
+ if length == 0
193
+ yield :timeout, timeout
176
194
 
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
195
+ return self
183
196
  end
184
197
 
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]]
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
- def epoll (timeout = nil)
197
- FFI.raise_if((@length = C.epoll_wait(@fd, @events, size, timeout ? timeout * 1000 : -1)) < 0)
224
+ n += 1
225
+ end
198
226
 
199
- @breaker.flush
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.raise
24
- value = FFI.errno
24
+ def self.errno_exception
25
+ Errno.const_get(Errno.constants[FFI.errno]).new
26
+ end
25
27
 
26
- Kernel.raise Errno.constants[FFI.errno].new
28
+ def self.raise
29
+ Kernel.raise errno_exception
27
30
  rescue Exception => e
28
31
  e.backtrace.shift(3)
29
32