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.
@@ -42,9 +42,7 @@ class Kqueue < Lanterna; begin
42
42
  end
43
43
 
44
44
  attach_function :kqueue, [], :int
45
- attach_function :kevent, [:int, :pointer, :int, :pointer, :int, :pointer], :int
46
-
47
- MAX = 4294967295
45
+ attach_function :kevent, [:int, :pointer, :int, :pointer, :int, :pointer], :int, :blocking => true
48
46
 
49
47
  EVFILT_READ = -1
50
48
  EVFILT_WRITE = -2
@@ -100,145 +98,134 @@ class Kqueue < Lanterna; begin
100
98
  }
101
99
  end
102
100
 
101
+ attr_reader :size
102
+
103
103
  def initialize
104
104
  super
105
105
 
106
106
  FFI.raise_if((@fd = C.kqueue) < 0)
107
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
108
+ @timeout = C::TimeSpec.new
109
+ @ev = C::Kevent.new
111
110
 
112
- self.size = 4096
113
- end
111
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, @breaker.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_ENABLE, 0, 0, 0), 1, nil, 0, nil) < 0)
114
112
 
115
- def size
116
- @events.size / C::Kevent.size
113
+ self.size = 4096
117
114
  end
118
115
 
119
116
  def size= (n)
120
117
  @events = FFI::MemoryPointer.new C::Kevent.size, n
118
+ @size = @events.size / C::Kevent.size
121
119
  end
122
120
 
123
- def add (*)
124
- super.tap {
125
- @last = nil
126
- }
127
- end
121
+ def edge_triggered?; @edge; end
122
+ def level_triggered?; !@edge; end
128
123
 
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
124
+ def edge_triggered!
125
+ @edge = true
134
126
 
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
127
+ each {|l|
128
+ if l.readable?
129
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_ENABLE | C::EV_CLEAR, 0, 0, l.to_i), 1, nil, 0, nil) < 0)
130
+ end
138
131
 
139
- @last = nil
132
+ if l.writable?
133
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_WRITE, C::EV_ADD | C::EV_ENABLE | C::EV_CLEAR, 0, 0, l.to_i), 1, nil, 0, nil) < 0)
134
+ end
140
135
  }
141
136
  end
142
137
 
143
- def available (timeout = nil)
144
- set :both; kevent timeout
145
-
146
- Available.new(to(:read), to(:write), to(:error))
147
- end
138
+ def level_triggered!
139
+ @edge = false
148
140
 
149
- def readable (timeout = nil)
150
- set :read; kevent timeout
141
+ each {|l|
142
+ if l.readable?
143
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_ENABLE, 0, 0, l.to_i), 1, nil, 0, nil) < 0)
144
+ end
151
145
 
152
- if report_errors?
153
- [to(:read), to(:error)]
154
- else
155
- to :read
156
- end
146
+ if l.writable?
147
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_WRITE, C::EV_ADD | C::EV_ENABLE, 0, 0, l.to_i), 1, nil, 0, nil) < 0)
148
+ end
149
+ }
157
150
  end
158
151
 
159
- def writable (timeout = nil)
160
- set :write; kevent timeout
152
+ def remove (*)
153
+ super {|l|
154
+ begin
155
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_READ, C::EV_DELETE | C::EV_DISABLE, 0, 0, 0), 1, nil, 0, nil) < 0)
156
+ rescue Errno::ENOENT, Errno::ENOTDIR; end
161
157
 
162
- if report_errors?
163
- [to(:write), to(:error)]
164
- else
165
- to :write
166
- end
158
+ begin
159
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_WRITE, C::EV_DELETE | C::EV_DISABLE, 0, 0, 0), 1, nil, 0, nil) < 0)
160
+ rescue Errno::ENOENT, Errno::ENOTDIR; end
161
+ }
167
162
  end
168
163
 
169
- def set (what)
170
- return if @last == what
164
+ def readable! (*)
165
+ super {|l|
166
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_ENABLE | (edge_triggered? ? C::EV_CLEAR : 0), 0, 0, 0), 1, nil, 0, nil) < 0)
167
+ }
168
+ end
171
169
 
172
- ev = C::Kevent.new
170
+ def no_readable! (*)
171
+ super {|l|
172
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_READ, C::EV_ADD | C::EV_DISABLE, 0, 0, 0), 1, nil, 0, nil) < 0)
173
+ }
174
+ end
173
175
 
174
- if what == :read
175
- descriptors.each_with_index {|descriptor, index|
176
- index = FFI::Pointer.new(index)
176
+ def writable! (*)
177
+ super {|l|
178
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_WRITE, C::EV_ADD | C::EV_ENABLE | (edge_triggered? ? C::EV_CLEAR : 0), 0, 0, 0), 1, nil, 0, nil) < 0)
179
+ }
180
+ end
177
181
 
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)
182
+ def no_writable! (*)
183
+ super {|l|
184
+ FFI.raise_if(C.kevent(@fd, C::EV_SET(@ev, l.to_i, C::EVFILT_WRITE, C::EV_ADD | C::EV_DISABLE, 0, 0, 0), 1, nil, 0, nil) < 0)
185
+ }
186
+ end
184
187
 
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)
188
+ def available (timeout = nil, &block)
189
+ return enum_for :available, timeout unless block
191
190
 
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
- }
191
+ if timeout
192
+ @timeout[:tv_sec] = timeout.to_i
193
+ @timeout[:tv_nsec] = (timeout - timeout.to_i) * 1000
195
194
  end
196
195
 
197
- @last = what
198
- end
196
+ FFI.raise_if((length = C.kevent(@fd, nil, 0, @events, size, timeout ? @timeout : nil)) < 0)
199
197
 
200
- def to (what)
201
- result = []
198
+ if length == 0
199
+ yield :timeout, timeout
202
200
 
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
201
+ return self
202
+ end
207
203
 
208
- if p != index && (p[:flags] & C::EV_ERROR).nonzero?
209
- result << descriptors[index]
204
+ n = 0
205
+ size = C::Kevent.size
206
+ while n < length
207
+ p = C::Kevent.new(@events + (n * size))
208
+ fd = p[:ident]
209
+ lucciola = self[fd]
210
+
211
+ if lucciola
212
+ if (p[:flags] & C::EV_ERROR).nonzero?
213
+ yield :error, lucciola
214
+ elsif p[:filter] == C::EVFILT_READ
215
+ yield :readable, lucciola
216
+ elsif p[:filter] == C::EVFILT_WRITE
217
+ yield :writable, lucciola
210
218
  end
211
- }
212
- else
213
- filter = case what
214
- when :read then C::EVFILT_READ
215
- when :write then C::EVFILT_WRITE
219
+ elsif fd == @breaker.to_i
220
+ yield :break, @breaker.reason
221
+ else
222
+ raise "#{fd} isn't trapped here"
216
223
  end
217
224
 
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
- }
225
+ n += 1
237
226
  end
238
227
 
239
- FFI.raise_if((@length = C.kevent(@fd, nil, 0, @events, size, timeout)) < 0)
240
-
241
- @breaker.flush
228
+ self
242
229
  end
243
230
  rescue Exception
244
231
  def self.supported?
@@ -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 Poll < Lanterna; begin
@@ -34,7 +32,7 @@ class Poll < Lanterna; begin
34
32
  :revents, :short
35
33
  end
36
34
 
37
- attach_function :poll, [:pointer, :ulong, :int], :int
35
+ attach_function :poll, [:pointer, :ulong, :int], :int, :blocking => true
38
36
 
39
37
  attach_function :malloc, [:size_t], :pointer
40
38
  attach_function :realloc, [:pointer, :size_t], :pointer
@@ -72,101 +70,104 @@ class Poll < Lanterna; begin
72
70
  pfd[:events] = C::POLLIN
73
71
  end
74
72
 
75
- def add (what)
76
- super.tap {|l|
77
- next unless l
78
-
73
+ def add (*)
74
+ super {|l|
79
75
  @set.autorelease = false
80
- @set = FFI::AutoPointer.new(C.realloc(@set, (descriptors.length + 1) * C::PollFD.size), C.method(:free))
76
+ @set = FFI::AutoPointer.new(C.realloc(@set, (@descriptors.length + 1) * C::PollFD.size), C.method(:free))
81
77
 
82
- pfd = C::PollFD.new(@set + descriptors.length * C::PollFD.size)
78
+ pfd = C::PollFD.new(@set + (@descriptors.length * C::PollFD.size))
83
79
  pfd[:fd] = l.to_i
84
-
85
- @last = nil
86
80
  }
87
81
  end
88
82
 
89
- def remove (what)
90
- Lucciola.wrap(what).tap {|l|
91
- index = descriptors.index(l)
83
+ def remove (*)
84
+ super {|l|
85
+ index = index_of(l)
92
86
  offset = (index + 1) * C::PollFD.size
93
87
  pointer = @set + offset
94
88
 
95
- pointer.write_bytes((pointer + C::PollFD.size).read_bytes((descriptors.length - index) * C::PollFD.size))
89
+ pointer.write_bytes((pointer + C::PollFD.size).read_bytes((@descriptors.length - index) * C::PollFD.size))
96
90
 
97
91
  @set.autorelease = false
98
- @set = FFI::AutoPointer.new(C.realloc(@set, (descriptors.length) * C::PollFD.size), C.method(:free))
99
-
100
- super(l)
92
+ @set = FFI::AutoPointer.new(C.realloc(@set, @descriptors.length * C::PollFD.size), C.method(:free))
101
93
  }
102
94
  end
103
95
 
104
- def available (timeout = nil)
105
- set :both; poll timeout
96
+ def readable! (*)
97
+ super {|l|
98
+ pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
99
+ pfd[:events] |= C::POLLIN
100
+ }
101
+ end
106
102
 
107
- Available.new(to(:read), to(:write), to(:error))
103
+ def no_readable! (*)
104
+ super {|l|
105
+ pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
106
+ pfd[:events] &= ~C::POLLIN
107
+ }
108
108
  end
109
109
 
110
- def readable (timeout = nil)
111
- set :read; poll timeout
110
+ def writable! (*)
111
+ super {|l|
112
+ pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
113
+ pfd[:events] |= C::POLLOUT
114
+ }
115
+ end
112
116
 
113
- if report_errors?
114
- [to(:read), to(:error)]
115
- else
116
- to :read
117
- end
117
+ def no_writable! (*)
118
+ super {|l|
119
+ pfd = C::PollFD.new(@set + ((index_of(l) + 1) * C::PollFD.size))
120
+ pfd[:events] &= ~C::POLLOUT
121
+ }
118
122
  end
119
123
 
120
- def writable (timeout = nil)
121
- set :write; poll timeout
124
+ def available (timeout = nil, &block)
125
+ return enum_for :available, timeout unless block
122
126
 
123
- if report_errors?
124
- [to(:write), to(:error)]
125
- else
126
- to :write
127
- end
128
- end
127
+ FFI.raise_if((length = C.poll(@set, @descriptors.length + 1, timeout ? timeout * 1000 : -1)) < 0)
129
128
 
130
- def set (what)
131
- return if @last == what
129
+ if length == 0
130
+ yield :timeout, timeout
132
131
 
133
- events = case what
134
- when :both then C::POLLIN | C::POLLOUT
135
- when :read then C::POLLIN
136
- when :write then C::POLLOUT
132
+ return self
137
133
  end
138
134
 
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
135
+ if (C::PollFD.new(@set)[:revents] & C::POLLIN).nonzero?
136
+ yield :break, @breaker.reason
137
+ end
146
138
 
147
- def to (what)
139
+ n = 0
140
+ size = C::PollFD.size
148
141
  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
142
+ while n < @descriptors.length
143
+ p = C::PollFD.new(@set + ((n + 1) * size))
144
+ events = p[:revents]
145
+ fd = p[:fd]
146
+ lucciola = self[fd]
147
+
148
+ if (events & (C::POLLERR | C::POLLHUP)).nonzero?
149
+ result << [:error, lucciola]
150
+ else
151
+ if (events & C::POLLIN).nonzero?
152
+ result << [:readable, lucciola]
153
+ end
154
+
155
+ if (events & C::POLLOUT).nonzero?
156
+ result << [:writable, lucciola]
157
+ end
158
+ end
154
159
 
155
- 1.upto(descriptors.length) {|n|
156
- pfd = C::PollFD.new(@set + (n * C::PollFD.size))
160
+ n += 1
161
+ end
157
162
 
158
- if (pfd[:revents] & events).nonzero?
159
- result << descriptors[n - 1]
160
- end
161
- }
163
+ result.each(&block)
162
164
 
163
- result
165
+ self
164
166
  end
165
167
 
166
- def poll (timeout = nil)
167
- FFI.raise_if(C.poll(@set, descriptors.length + 1, timeout ? timeout * 1000 : -1) < 0)
168
-
169
- @breaker.flush
168
+ private
169
+ def index_of (what)
170
+ @descriptors.keys.index(what.to_i)
170
171
  end
171
172
  rescue Exception
172
173
  def self.supported?
@@ -0,0 +1,211 @@
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 Port < Lanterna; begin
23
+ module C
24
+ extend FFI::Library
25
+
26
+ ffi_lib FFI::Library::LIBC
27
+
28
+ class PortEvent < FFI::Struct
29
+ layout \
30
+ :events, :int,
31
+ :source, :ushort,
32
+ :pad, :ushort,
33
+ :object, :uintptr_t,
34
+ :user, :pointer
35
+ end
36
+
37
+ class TimeSpec < FFI::Struct
38
+ layout \
39
+ :tv_sec, :time_t,
40
+ :tv_nsec, :int
41
+ end
42
+
43
+ attach_function :port_create, [], :int
44
+ attach_function :port_associate, [:int, :int, :uintptr_t, :int, :pointer], :int
45
+ attach_function :port_dissociate, [:int, :int, :uintptr_t], :int
46
+ attach_function :port_send, [:int, :int, :pointer], :int
47
+ attach_function :port_sendn, [:pointer, :pointer, :uint, :int, :pointer], :int
48
+ attach_function :port_get, [:int, :pointer, :pointer], :int
49
+ attach_function :port_getn, [:int, :pointer, :uint, :pointer, :pointer], :int
50
+ attach_function :port_alert, [:int, :int, :int, :pointer], :int
51
+
52
+ SOURCE_AIO = 1
53
+ SOURCE_TIMER = 2
54
+ SOURCE_USER = 3
55
+ SOURCE_FD = 4
56
+ SOURCE_ALERT = 5
57
+ SOURCE_MQ = 6
58
+ SOURCE_FILE = 7
59
+
60
+ POLLIN = 0x001
61
+ POLLPRI = 0x002
62
+ POLLOUT = 0x004
63
+
64
+ POLLERR = 0x008
65
+ POLLHUP = 0x010
66
+ POLLNVAL = 0x020
67
+
68
+ POLLRDNORM = 0x040
69
+ POLLRDBAND = 0x080
70
+ POLLWRNORM = 0x100
71
+ POLLWRBAND = 0x200
72
+
73
+ POLLMSG = 0x0400
74
+ POLLREMOVE = 0x1000
75
+ POLLRDHUP = 0x2000
76
+ end
77
+
78
+ def self.supported?
79
+ true
80
+ end
81
+
82
+ def self.new (*)
83
+ super.tap {|c|
84
+ ObjectSpace.define_finalizer c, finalizer(c.instance_variable_get :@fd)
85
+ }
86
+ end
87
+
88
+ def self.finalizer (fd)
89
+ proc {
90
+ IO.for_fd(fd).close
91
+ }
92
+ end
93
+
94
+ attr_reader :size
95
+
96
+ def initialize
97
+ super
98
+
99
+ FFI.raise_if((@fd = C.port_create) < 0)
100
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, @breaker.to_i, C::POLLIN, nil) < 0)
101
+
102
+ @timeout = C::TimeSpec.new
103
+ @length = FFI::MemoryPointer.new :uint
104
+
105
+ self.size = 4096
106
+ end
107
+
108
+ def size= (n)
109
+ @events = FFI::MemoryPointer.new C::PortEvent.size, n
110
+ @size = @events.size / C::PortEvent.size
111
+ end
112
+
113
+ def add (*)
114
+ super {|l|
115
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, l.to_i, C::POLLIN, nil) < 0)
116
+ }
117
+ end
118
+
119
+ def remove (*)
120
+ super {|l|
121
+ begin
122
+ FFI.raise_if(C.port_dissociate(@fd, C::SOURCE_FD, l.to_i) < 0)
123
+ rescue Errno::EIDRM; end
124
+ }
125
+ end
126
+
127
+ def readable! (*)
128
+ super {|l|
129
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, l.to_i, C::POLLIN | (l.writable? ? C::POLLOUT : 0), nil) < 0)
130
+ }
131
+ end
132
+
133
+ def no_readable! (*)
134
+ super {|l|
135
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, l.to_i, (l.writable? ? C::POLLOUT : 0), nil) < 0)
136
+ }
137
+ end
138
+
139
+ def writable! (*)
140
+ super {|l|
141
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, l.to_i, C::POLLOUT | (l.readable? ? C::POLLIN : 0), nil) < 0)
142
+ }
143
+ end
144
+
145
+ def no_writable! (*)
146
+ super {|l|
147
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, l.to_i, (l.readable? ? C::POLLIN : 0), nil) < 0)
148
+ }
149
+ end
150
+
151
+ def available (timeout = nil, &block)
152
+ return enum_for :available, timeout unless block
153
+
154
+ if timeout
155
+ @timeout[:tv_sec] = timeout.to_i
156
+ @timeout[:tv_nsec] = (timeout - timeout.to_i) * 1000
157
+ end
158
+
159
+ @length.write_uint 1
160
+
161
+ if C.port_getn(@fd, @events, size, @length, timeout ? @timeout : nil) < 0
162
+ FFI.raise_unless FFI.errno == Errno::ETIME::Errno
163
+
164
+ yield :timeout, timeout
165
+
166
+ return self
167
+ end
168
+
169
+ n = 0
170
+ size = C::PortEvent.size
171
+ length = @length.read_uint
172
+ while n < length
173
+ p = C::PortEvent.new(@events + (n * size))
174
+ events = p[:events]
175
+ fd = p[:object]
176
+ lucciola = self[fd]
177
+
178
+ if lucciola
179
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, lucciola.to_i, (lucciola.readable? ? C::POLLIN : 0) | (lucciola.writable? ? C::POLLOUT : 0), nil) < 0)
180
+
181
+ if (events & (C::POLLERR | C::POLLHUP)).nonzero?
182
+ yield :error, lucciola
183
+ else
184
+ if (events & C::POLLIN).nonzero?
185
+ yield :readable, lucciola
186
+ end
187
+
188
+ if (events & C::POLLOUT).nonzero?
189
+ yield :writable, lucciola
190
+ end
191
+ end
192
+ elsif fd == @breaker.to_i
193
+ FFI.raise_if(C.port_associate(@fd, C::SOURCE_FD, @breaker.to_i, C::POLLIN, nil) < 0)
194
+
195
+ yield :break, @breaker.reason
196
+ else
197
+ raise "#{fd} isn't trapped here"
198
+ end
199
+
200
+ n += 1
201
+ end
202
+
203
+ self
204
+ end
205
+ rescue Exception
206
+ def self.supported?
207
+ false
208
+ end
209
+ end; end
210
+
211
+ end; end