barlume 0.0.1.rc.1 → 0.0.1.rc.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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