bran 0.0.2 → 0.0.3
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.
- checksums.yaml +4 -4
- data/lib/bran/ext/ethon/multi/bran.rb +7 -3
- data/lib/bran/ext/io.rb +1 -1
- data/lib/bran/ext/rainbows/bran.rb +12 -11
- data/lib/bran/libuv/reactor.rb +60 -261
- data/lib/bran/libuv/reactor/collections.rb +279 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a56dfe96ac8bd822a8dce4018ba0ad9f8fb090a6
|
4
|
+
data.tar.gz: 6e3045d8630a7264569f67350712d9f065b1f968
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90634a69c9f5edb887124ca8a66c65dc0cf953ee4501146ac79aeb28fec9396c87ba062eb7a866c9dce6fe727cbf82f3e24133e077efcfbff28f072c6231fa4b
|
7
|
+
data.tar.gz: 7ec1e47489f14a4735134e0b51d00c68336de33924e01865968d3abacbd151570c141305b08637d0cf482967f4728abe4aef229b63882a20716eba96faacbb53
|
@@ -31,8 +31,12 @@ module Ethon
|
|
31
31
|
@fm = fm
|
32
32
|
@multi = multi
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
# We must hold a reference to these Procs, because the multi won't.
|
35
|
+
# This prevents the Procs from being GC'd while C holds the callbacks.
|
36
|
+
@socketfunction = method(:_socketfunction_callback).to_proc
|
37
|
+
@timerfunction = method(:_timerfunction_callback).to_proc
|
38
|
+
@multi.socketfunction = @socketfunction
|
39
|
+
@multi.timerfunction = @timerfunction
|
36
40
|
end
|
37
41
|
|
38
42
|
def perform
|
@@ -115,7 +119,7 @@ module Ethon
|
|
115
119
|
end
|
116
120
|
|
117
121
|
def timer_cancel
|
118
|
-
@fm.loop.
|
122
|
+
@fm.loop.pop_timable @timeout_timer if @timeout_timer
|
119
123
|
end
|
120
124
|
|
121
125
|
def socket_action!(fd, flags)
|
data/lib/bran/ext/io.rb
CHANGED
@@ -80,7 +80,7 @@ Module.new do
|
|
80
80
|
begin
|
81
81
|
r_ary.each { |io| fm.loop.pop_readable(Integer(io)) } if r_ary
|
82
82
|
w_ary.each { |io| fm.loop.pop_writable(Integer(io)) } if w_ary
|
83
|
-
fm.loop.
|
83
|
+
fm.loop.pop_timable(timer) if timer
|
84
84
|
ensure
|
85
85
|
fiber.resume(item)
|
86
86
|
end
|
@@ -31,19 +31,14 @@ module Rainbows
|
|
31
31
|
def worker_loop(worker)
|
32
32
|
readers = init_worker_process(worker)
|
33
33
|
|
34
|
-
# We have to skip the implementation from Rainbows::Base,
|
35
|
-
# and use the implementation from Unicorn::HttpServer directly.
|
36
|
-
process_client = ::Unicorn::HttpServer.instance_method(:process_client)
|
37
|
-
process_client = process_client.bind(self)
|
38
|
-
|
39
34
|
manager = ::Bran::FiberManager.new
|
40
35
|
stopping = false
|
41
36
|
|
42
37
|
manager.run! do
|
43
|
-
manager.loop.
|
44
|
-
manager.loop.
|
45
|
-
manager.loop.
|
46
|
-
manager.loop.
|
38
|
+
manager.loop.push_signalable :INT, Proc.new { exit!(0) }
|
39
|
+
manager.loop.push_signalable :TERM, Proc.new { exit!(0) }
|
40
|
+
manager.loop.push_signalable :USR1, Proc.new { reopen_worker_logs(worker.nr) } # TODO: test
|
41
|
+
manager.loop.push_signalable :QUIT, Proc.new { stopping = true } # TODO: test softness
|
47
42
|
|
48
43
|
readers.each do |reader|
|
49
44
|
next unless reader.is_a?(::Kgio::TCPServer) # TODO: other readers?
|
@@ -51,8 +46,14 @@ module Rainbows
|
|
51
46
|
worker_connections.times.map do |i|
|
52
47
|
::Fiber.new do
|
53
48
|
until stopping # TODO: rescue and report errors here
|
54
|
-
|
55
|
-
|
49
|
+
# Try to accept a client, then if none, wait for one to appear.
|
50
|
+
# This may happen more than once when there all multiple
|
51
|
+
# workers all contending for clients on the same server socket.
|
52
|
+
until (client = reader.kgio_tryaccept)
|
53
|
+
manager.wait_for_readable!(reader)
|
54
|
+
end
|
55
|
+
|
56
|
+
process_client client
|
56
57
|
end
|
57
58
|
end.resume
|
58
59
|
end
|
data/lib/bran/libuv/reactor.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
|
2
|
+
require_relative "reactor/collections"
|
3
|
+
|
2
4
|
module Bran
|
3
5
|
module LibUV
|
4
6
|
class Reactor
|
@@ -14,26 +16,15 @@ module Bran
|
|
14
16
|
@finalizer = self.class.create_finalizer_for(@ptr)
|
15
17
|
ObjectSpace.define_finalizer(self, @finalizer)
|
16
18
|
|
17
|
-
@
|
18
|
-
@
|
19
|
-
@
|
20
|
-
@fds_by_read_addr = {}
|
21
|
-
@fds_by_write_addr = {}
|
22
|
-
@on_readables = {}
|
23
|
-
@on_writables = {}
|
24
|
-
|
25
|
-
@available_signals = []
|
26
|
-
@running_signals = {}
|
27
|
-
|
28
|
-
@available_timers = []
|
29
|
-
@running_timers = {}
|
19
|
+
@read_polls = Collections::Read.new(self)
|
20
|
+
@write_polls = Collections::Write.new(self)
|
21
|
+
@write_polls.bond_with @read_polls
|
30
22
|
|
31
|
-
@
|
32
|
-
@
|
33
|
-
@poll_rw_callback = FFI.uv_poll_cb(&method(:_poll_rw_callback))
|
23
|
+
@signal_polls = Collections::Signal.new(self)
|
24
|
+
@timer_polls = Collections::Timer.new(self)
|
34
25
|
|
35
26
|
# TODO: add more Ruby-compatible signal handlers by default?
|
36
|
-
|
27
|
+
push_signalable :INT, Proc.new { @abort_signal = :INT; stop! }
|
37
28
|
end
|
38
29
|
|
39
30
|
# Free the native resources associated with this object. This will
|
@@ -45,13 +36,8 @@ module Bran
|
|
45
36
|
end
|
46
37
|
@ptr = @finalizer = nil
|
47
38
|
|
48
|
-
@
|
49
|
-
|
50
|
-
@fds_by_read_addr = @fds_by_write_addr = \
|
51
|
-
@on_readables = @on_writables = \
|
52
|
-
@available_signals = @running_signals = \
|
53
|
-
@available_timers = @running_timers = \
|
54
|
-
@poll_read_callback = @poll_write_callback = nil
|
39
|
+
@read_polls = @write_polls = \
|
40
|
+
@signal_polls = @timer_polls = nil
|
55
41
|
|
56
42
|
self
|
57
43
|
end
|
@@ -104,293 +90,106 @@ module Bran
|
|
104
90
|
# Push the given handler for the given fd, adding if necessary.
|
105
91
|
# If persistent is false, the handler will be popped after one trigger.
|
106
92
|
def push_readable(fd, handler, persistent = true)
|
107
|
-
|
108
|
-
fd = Integer(fd)
|
109
|
-
poll = nil
|
110
|
-
|
111
|
-
if (readables = @on_readables[fd])
|
112
|
-
readables << [handler, persistent]
|
113
|
-
elsif (poll = @running_writes[fd])
|
114
|
-
@running_reads[fd] = poll
|
115
|
-
@fds_by_read_addr[poll.address] = fd
|
116
|
-
@on_readables[fd] = [[handler, persistent]]
|
117
|
-
|
118
|
-
Util.error_check "starting the poll readable + writable entry",
|
119
|
-
FFI.uv_poll_start(poll, FFI::UV_READABLE | FFI::UV_WRITABLE, @poll_rw_callback)
|
120
|
-
else
|
121
|
-
poll = @available_polls.pop || FFI.uv_poll_alloc
|
122
|
-
@running_reads[fd] = poll
|
123
|
-
@fds_by_read_addr[poll.address] = fd
|
124
|
-
@on_readables[fd] = [[handler, persistent]]
|
125
|
-
|
126
|
-
Util.error_check "creating the poll readable entry",
|
127
|
-
FFI.uv_poll_init(ptr, poll, fd)
|
128
|
-
|
129
|
-
Util.error_check "starting the poll readable entry",
|
130
|
-
FFI.uv_poll_start(poll, FFI::UV_READABLE, @poll_read_callback)
|
131
|
-
end
|
132
|
-
|
133
|
-
fd
|
93
|
+
@read_polls.push(Integer(fd), handler, persistent)
|
134
94
|
end
|
135
95
|
|
136
96
|
# Push the given handler for the given fd, adding if necessary.
|
137
97
|
# If persistent is false, the handler will be popped after one trigger.
|
138
98
|
def push_writable(fd, handler, persistent = true)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
@running_writes[fd] = poll
|
147
|
-
@fds_by_write_addr[poll.address] = fd
|
148
|
-
@on_writables[fd] = [[handler, persistent]]
|
149
|
-
|
150
|
-
Util.error_check "starting the poll readable + writable entry",
|
151
|
-
FFI.uv_poll_start(poll, FFI::UV_READABLE | FFI::UV_WRITABLE, @poll_rw_callback)
|
152
|
-
else
|
153
|
-
poll = @available_polls.pop || FFI.uv_poll_alloc
|
154
|
-
@running_writes[fd] = poll
|
155
|
-
@fds_by_write_addr[poll.address] = fd
|
156
|
-
@on_writables[fd] = [[handler, persistent]]
|
157
|
-
|
158
|
-
Util.error_check "creating the poll writeable entry",
|
159
|
-
FFI.uv_poll_init(ptr, poll, fd)
|
160
|
-
|
161
|
-
Util.error_check "starting the poll writeable entry",
|
162
|
-
FFI.uv_poll_start(poll, FFI::UV_WRITABLE, @poll_write_callback)
|
163
|
-
end
|
99
|
+
@write_polls.push(Integer(fd), handler, persistent)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Push the given handler for the given signo, adding if necessary.
|
103
|
+
# If persistent is false, the handler will be popped after one trigger.
|
104
|
+
def push_signalable(signo, handler, persistent = true)
|
105
|
+
signo = Signal.list.fetch(signo.to_s) unless signo.is_a?(Integer)
|
164
106
|
|
165
|
-
|
107
|
+
@signal_polls.push(signo, handler, persistent)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Push the given handler for the given timer id, adding if necessary.
|
111
|
+
# If persistent is false, the handler will be popped after one trigger.
|
112
|
+
def push_timable(ident, timeout, handler, persistent = true)
|
113
|
+
@timer_polls.push(ident, handler, persistent, timeout)
|
166
114
|
end
|
167
115
|
|
168
116
|
# Remove the next readable handler for the given fd.
|
169
117
|
def pop_readable(fd)
|
170
|
-
|
171
|
-
|
172
|
-
readables = @on_readables[fd]
|
173
|
-
return unless readables
|
174
|
-
|
175
|
-
readables.pop
|
176
|
-
return unless readables.empty?
|
177
|
-
|
178
|
-
@on_readables.delete(fd)
|
179
|
-
poll = @running_reads.delete(fd)
|
180
|
-
@fds_by_read_addr.delete(poll.address)
|
181
|
-
|
182
|
-
Util.error_check "stopping the poll readable entry",
|
183
|
-
FFI.uv_poll_stop(poll)
|
184
|
-
|
185
|
-
if poll == @running_writes[fd]
|
186
|
-
Util.error_check "restarting the poll writable entry",
|
187
|
-
FFI.uv_poll_start(poll, FFI::UV_WRITABLE, @poll_write_callback)
|
188
|
-
|
189
|
-
return
|
190
|
-
end
|
191
|
-
|
192
|
-
@available_polls << poll
|
193
|
-
|
194
|
-
nil
|
118
|
+
@read_polls.pop(Integer(fd))
|
195
119
|
end
|
196
120
|
|
197
121
|
# Remove the next writable handler for the given fd.
|
198
122
|
def pop_writable(fd)
|
199
|
-
|
200
|
-
|
201
|
-
writables = @on_writables[fd]
|
202
|
-
return unless writables
|
203
|
-
|
204
|
-
writables.pop
|
205
|
-
return unless writables.empty?
|
206
|
-
|
207
|
-
@on_writables.delete(fd)
|
208
|
-
poll = @running_writes.delete(fd)
|
209
|
-
@fds_by_write_addr.delete(poll.address)
|
210
|
-
|
211
|
-
Util.error_check "stopping the poll writable entry",
|
212
|
-
FFI.uv_poll_stop(poll)
|
213
|
-
|
214
|
-
if poll == @running_reads[fd]
|
215
|
-
Util.error_check "restarting the poll readable entry",
|
216
|
-
FFI.uv_poll_start(poll, FFI::UV_READABLE, @poll_read_callback)
|
217
|
-
|
218
|
-
return
|
219
|
-
end
|
220
|
-
|
221
|
-
@available_polls << poll
|
222
|
-
|
223
|
-
nil
|
123
|
+
@write_polls.pop(Integer(fd))
|
224
124
|
end
|
225
125
|
|
226
|
-
#
|
227
|
-
def
|
228
|
-
ptr = ptr()
|
126
|
+
# Remove the next signal handler for the given signal.
|
127
|
+
def pop_signalable(signo)
|
229
128
|
signo = Signal.list.fetch(signo.to_s) unless signo.is_a?(Integer)
|
230
129
|
|
231
|
-
|
232
|
-
|
233
|
-
callback = FFI.uv_signal_cb do |_, _|
|
234
|
-
rescue_abort do
|
235
|
-
block.call self, signo
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
signal = @available_signals.pop || FFI.uv_signal_alloc
|
240
|
-
@running_signals[signo] = [signal, callback]
|
241
|
-
|
242
|
-
# TODO: investigate if need not init existing available_signals
|
243
|
-
Util.error_check "creating the signal item",
|
244
|
-
FFI.uv_signal_init(ptr, signal)
|
245
|
-
|
246
|
-
Util.error_check "starting the signal item",
|
247
|
-
FFI.uv_signal_start(signal, callback, signo)
|
130
|
+
@signal_polls.pop(signo)
|
248
131
|
end
|
249
132
|
|
250
|
-
#
|
251
|
-
def
|
252
|
-
|
253
|
-
|
254
|
-
signal, callback = @running_signals.delete(signo)
|
255
|
-
|
256
|
-
return unless signal
|
257
|
-
|
258
|
-
Util.error_check "stopping the signal item",
|
259
|
-
FFI.uv_signal_stop(signal)
|
260
|
-
|
261
|
-
@available_signals << signal
|
262
|
-
|
263
|
-
nil
|
264
|
-
end
|
265
|
-
|
266
|
-
# Start a timer to run the given block after the given timeout.
|
267
|
-
# If a repeat_interval is given, after the first run, the block will be
|
268
|
-
# run repeatedly at that interval. If a repeat_interval is not given,
|
269
|
-
# or given as nil or 0, timer_cancel is called automatically at first run.
|
270
|
-
# Both timeout and repeat_interval should be given in seconds.
|
271
|
-
def timer_start(timeout, repeat_interval = nil, &block)
|
272
|
-
ptr = ptr()
|
273
|
-
|
274
|
-
timeout = (timeout * 1000).ceil
|
275
|
-
|
276
|
-
repeat = false
|
277
|
-
if repeat_interval and repeat_interval > 0
|
278
|
-
repeat_interval = (repeat_interval * 1000).ceil
|
279
|
-
repeat = true
|
280
|
-
else
|
281
|
-
repeat_interval = 0
|
282
|
-
end
|
283
|
-
|
284
|
-
raise ArgumentError, "callback block required" unless block
|
285
|
-
|
286
|
-
timer = @available_timers.pop || FFI.uv_timer_alloc
|
287
|
-
id = timer.address
|
288
|
-
|
289
|
-
callback = FFI.uv_timer_cb do |_|
|
290
|
-
rescue_abort do
|
291
|
-
block.call self, id
|
292
|
-
|
293
|
-
timer_cancel(id) unless repeat
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
@running_timers[id] = [timer, callback]
|
298
|
-
|
299
|
-
# TODO: investigate if need not init existing available_timers
|
300
|
-
Util.error_check "creating the timer item",
|
301
|
-
FFI.uv_timer_init(ptr, timer)
|
302
|
-
|
303
|
-
Util.error_check "starting the timer item",
|
304
|
-
FFI.uv_timer_start(timer, callback, timeout, repeat_interval)
|
305
|
-
|
306
|
-
id
|
307
|
-
end
|
308
|
-
|
309
|
-
# Stop handling the given timer.
|
310
|
-
def timer_cancel(id)
|
311
|
-
id = Integer(id)
|
312
|
-
|
313
|
-
timer, callback = @running_timers.delete(id)
|
314
|
-
|
315
|
-
return unless timer
|
316
|
-
|
317
|
-
Util.error_check "stopping the timer item",
|
318
|
-
FFI.uv_timer_stop(timer)
|
319
|
-
|
320
|
-
@available_timers << timer
|
321
|
-
|
322
|
-
nil
|
133
|
+
# Remove the next timer handler for the given timer.
|
134
|
+
def pop_timable(ident)
|
135
|
+
@timer_polls.pop(ident)
|
323
136
|
end
|
324
137
|
|
325
138
|
# Start a timer to run the given block after the given timeout.
|
326
139
|
# The timer will be run just once, starting now.
|
327
140
|
def timer_oneshot(time, &block)
|
328
|
-
|
141
|
+
push_timable(block.object_id, time, block, false)
|
329
142
|
end
|
330
143
|
|
331
144
|
# Start a timer to wake the given fiber after the given timeout.
|
332
145
|
# The timer will be run just once, starting now.
|
333
146
|
def timer_oneshot_wake(time, fiber)
|
334
|
-
|
147
|
+
timer_oneshot(time) { fiber.resume } # TODO: optimize this case, but be careful of ident uniqueness
|
335
148
|
end
|
336
149
|
|
337
150
|
private
|
338
151
|
|
339
152
|
# Callback method called directly from FFI when an event is readable.
|
340
|
-
def
|
153
|
+
def _read_callback(poll, rc, events)
|
341
154
|
rescue_abort do
|
342
|
-
|
343
|
-
return unless fd
|
344
|
-
|
345
|
-
readables = @on_readables.fetch(fd)
|
346
|
-
|
347
|
-
handler, persistent = readables.last
|
348
|
-
pop_readable(fd) unless persistent
|
349
|
-
|
350
|
-
invoke_handler(handler, rc)
|
155
|
+
@read_polls.invoke_by_addr(poll.address, rc)
|
351
156
|
end
|
352
157
|
end
|
353
158
|
|
354
159
|
# Callback method called directly from FFI when an event is writable.
|
355
|
-
def
|
160
|
+
def _write_callback(poll, rc, events)
|
356
161
|
rescue_abort do
|
357
|
-
|
358
|
-
return unless fd
|
359
|
-
|
360
|
-
writables = @on_writables.fetch(fd)
|
361
|
-
|
362
|
-
handler, persistent = writables.last
|
363
|
-
pop_writable(fd) unless persistent
|
364
|
-
|
365
|
-
invoke_handler(handler, rc)
|
162
|
+
@write_polls.invoke_by_addr(poll.address, rc)
|
366
163
|
end
|
367
164
|
end
|
368
165
|
|
369
166
|
# Callback method called directly from FFI when an event is readable or writable.
|
370
|
-
def
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
# Invoke the given handler, possibly converting the given rc to an error.
|
376
|
-
def invoke_handler(handler, rc)
|
377
|
-
case handler
|
378
|
-
when ::Fiber
|
379
|
-
if rc == 0
|
380
|
-
handler.resume nil
|
381
|
-
else
|
382
|
-
handler.resume Util.error_create("running the libuv loop", rc)
|
167
|
+
def _rw_callback(poll, rc, events)
|
168
|
+
rescue_abort do
|
169
|
+
if 0 != (events & FFI::UV_READABLE)
|
170
|
+
@read_polls.invoke_by_addr(poll.address, rc)
|
383
171
|
end
|
384
|
-
|
385
|
-
if
|
386
|
-
|
387
|
-
else
|
388
|
-
error = Util.error_create("running the libuv loop", rc)
|
389
|
-
handler.call error
|
172
|
+
|
173
|
+
if 0 != (events & FFI::UV_WRITABLE)
|
174
|
+
@write_polls.invoke_by_addr(poll.address, rc)
|
390
175
|
end
|
391
176
|
end
|
392
177
|
end
|
393
178
|
|
179
|
+
# Callback method called directly from FFI when an event is signalled.
|
180
|
+
def _signal_callback(handle, signo)
|
181
|
+
rescue_abort do
|
182
|
+
@signal_polls.invoke_by_ident(signo)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Callback method called directly from FFI when a timer has occurred.
|
187
|
+
def _timer_callback(handle)
|
188
|
+
rescue_abort do
|
189
|
+
@timer_polls.invoke_by_addr(handle.address)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
394
193
|
end
|
395
194
|
end
|
396
195
|
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
|
2
|
+
module Bran
|
3
|
+
module LibUV
|
4
|
+
class Reactor
|
5
|
+
module Collections
|
6
|
+
|
7
|
+
class Abstract
|
8
|
+
def initialize(reactor)
|
9
|
+
@reactor = reactor
|
10
|
+
|
11
|
+
@idents_by_addr = {}
|
12
|
+
@items_by_ident = {}
|
13
|
+
@stacks_by_ident = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def push(ident, handler, persistent, *extra_args)
|
17
|
+
if (stack = @stacks_by_ident[ident])
|
18
|
+
stack << [handler, persistent]
|
19
|
+
else
|
20
|
+
item = make_item(ident, extra_args)
|
21
|
+
|
22
|
+
@items_by_ident[ident] = item
|
23
|
+
@idents_by_addr[item.address] = ident
|
24
|
+
@stacks_by_ident[ident] = [[handler, persistent]]
|
25
|
+
end
|
26
|
+
|
27
|
+
ident
|
28
|
+
end
|
29
|
+
|
30
|
+
def pop(ident)
|
31
|
+
stack = @stacks_by_ident[ident]
|
32
|
+
return unless stack
|
33
|
+
|
34
|
+
stack.pop
|
35
|
+
return unless stack.empty?
|
36
|
+
|
37
|
+
@stacks_by_ident.delete(ident)
|
38
|
+
item = @items_by_ident.delete(ident)
|
39
|
+
@idents_by_addr.delete(item.address)
|
40
|
+
|
41
|
+
drop_item(ident, item)
|
42
|
+
end
|
43
|
+
|
44
|
+
def item_by_ident(ident)
|
45
|
+
@items_by_ident[ident]
|
46
|
+
end
|
47
|
+
|
48
|
+
def invoke_by_ident(ident, rc = 0)
|
49
|
+
stack = @stacks_by_ident[ident]
|
50
|
+
return unless ident
|
51
|
+
|
52
|
+
handler, persistent = stack.last
|
53
|
+
pop ident unless persistent
|
54
|
+
|
55
|
+
invoke_handler(handler, rc)
|
56
|
+
end
|
57
|
+
|
58
|
+
def invoke_by_addr(addr, rc = 0)
|
59
|
+
ident = @idents_by_addr[addr]
|
60
|
+
return unless ident
|
61
|
+
|
62
|
+
stack = @stacks_by_ident.fetch(ident)
|
63
|
+
|
64
|
+
handler, persistent = stack.last
|
65
|
+
pop ident unless persistent
|
66
|
+
|
67
|
+
invoke_handler(handler, rc)
|
68
|
+
end
|
69
|
+
|
70
|
+
def invoke_handler(handler, rc = 0)
|
71
|
+
case handler
|
72
|
+
when ::Fiber
|
73
|
+
if rc == 0
|
74
|
+
handler.resume nil
|
75
|
+
else
|
76
|
+
handler.resume Util.error_create("running the libuv loop", rc)
|
77
|
+
end
|
78
|
+
when ::Proc
|
79
|
+
if rc == 0
|
80
|
+
handler.call nil
|
81
|
+
else
|
82
|
+
error = Util.error_create("running the libuv loop", rc)
|
83
|
+
handler.call error
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def make_item(ident, extra_args)
|
89
|
+
item = concrete_alloc_item
|
90
|
+
concrete_start_item(ident, item, *extra_args)
|
91
|
+
|
92
|
+
item
|
93
|
+
end
|
94
|
+
|
95
|
+
def drop_item(ident, item)
|
96
|
+
concrete_stop_item(ident, item)
|
97
|
+
concrete_release_item(item)
|
98
|
+
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class AbstractSister < Abstract
|
104
|
+
attr_accessor :sister
|
105
|
+
attr_accessor :item_pool
|
106
|
+
|
107
|
+
def bond_with(sister)
|
108
|
+
@sister = sister
|
109
|
+
@item_pool = []
|
110
|
+
|
111
|
+
@sister.sister = self
|
112
|
+
@sister.item_pool = @item_pool
|
113
|
+
end
|
114
|
+
|
115
|
+
def make_item(ident, extra_args)
|
116
|
+
item = @sister.item_by_ident(ident)
|
117
|
+
return super unless item
|
118
|
+
|
119
|
+
@sister.concrete_sister_share_item(ident, item)
|
120
|
+
|
121
|
+
item
|
122
|
+
end
|
123
|
+
|
124
|
+
def drop_item(ident, item)
|
125
|
+
sister_item = @sister.item_by_ident(ident)
|
126
|
+
return super unless sister_item == item
|
127
|
+
|
128
|
+
@sister.concrete_sister_unshare_item(ident, item)
|
129
|
+
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class Read < AbstractSister
|
135
|
+
def initialize(*)
|
136
|
+
super
|
137
|
+
@callback = FFI.uv_poll_cb(&@reactor.method(:_read_callback))
|
138
|
+
@rw_callback = FFI.uv_poll_cb(&@reactor.method(:_rw_callback))
|
139
|
+
end
|
140
|
+
|
141
|
+
def concrete_alloc_item
|
142
|
+
@item_pool.pop || FFI.uv_poll_alloc
|
143
|
+
end
|
144
|
+
|
145
|
+
def concrete_release_item(item)
|
146
|
+
@item_pool << item
|
147
|
+
end
|
148
|
+
|
149
|
+
def concrete_start_item(ident, item)
|
150
|
+
Util.error_check "creating the poll readable item",
|
151
|
+
FFI.uv_poll_init(@reactor.ptr, item, ident)
|
152
|
+
|
153
|
+
Util.error_check "starting the poll readable item",
|
154
|
+
FFI.uv_poll_start(item, FFI::UV_READABLE, @callback)
|
155
|
+
end
|
156
|
+
|
157
|
+
def concrete_stop_item(ident, item)
|
158
|
+
Util.error_check "stopping the poll readable item",
|
159
|
+
FFI.uv_poll_stop(item)
|
160
|
+
end
|
161
|
+
|
162
|
+
def concrete_sister_share_item(ident, item)
|
163
|
+
Util.error_check "starting the poll readable + writable item",
|
164
|
+
FFI.uv_poll_start(item,
|
165
|
+
FFI::UV_READABLE | FFI::UV_WRITABLE, @rw_callback)
|
166
|
+
end
|
167
|
+
|
168
|
+
def concrete_sister_unshare_item(ident, item)
|
169
|
+
Util.error_check "restarting the poll readable item",
|
170
|
+
FFI.uv_poll_start(item, FFI::UV_READABLE, @callback)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class Write < AbstractSister
|
175
|
+
def initialize(*)
|
176
|
+
super
|
177
|
+
@callback = FFI.uv_poll_cb(&@reactor.method(:_write_callback))
|
178
|
+
@rw_callback = FFI.uv_poll_cb(&@reactor.method(:_rw_callback))
|
179
|
+
end
|
180
|
+
|
181
|
+
def concrete_alloc_item
|
182
|
+
@item_pool.pop || FFI.uv_poll_alloc
|
183
|
+
end
|
184
|
+
|
185
|
+
def concrete_release_item(item)
|
186
|
+
@item_pool << item
|
187
|
+
end
|
188
|
+
|
189
|
+
def concrete_start_item(ident, item)
|
190
|
+
Util.error_check "creating the poll writable item",
|
191
|
+
FFI.uv_poll_init(@reactor.ptr, item, ident)
|
192
|
+
|
193
|
+
Util.error_check "starting the poll writable item",
|
194
|
+
FFI.uv_poll_start(item, FFI::UV_WRITABLE, @callback)
|
195
|
+
end
|
196
|
+
|
197
|
+
def concrete_stop_item(ident, item)
|
198
|
+
Util.error_check "stopping the poll writable item",
|
199
|
+
FFI.uv_poll_stop(item)
|
200
|
+
end
|
201
|
+
|
202
|
+
def concrete_sister_share_item(ident, item)
|
203
|
+
Util.error_check "starting the poll writable + writable item",
|
204
|
+
FFI.uv_poll_start(item,
|
205
|
+
FFI::UV_READABLE | FFI::UV_WRITABLE, @rw_callback)
|
206
|
+
end
|
207
|
+
|
208
|
+
def concrete_sister_unshare_item(ident, item)
|
209
|
+
Util.error_check "restarting the poll writable item",
|
210
|
+
FFI.uv_poll_start(item, FFI::UV_WRITABLE, @callback)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class Signal < Abstract
|
215
|
+
def initialize(*)
|
216
|
+
super
|
217
|
+
@item_pool = []
|
218
|
+
@callback = FFI.uv_signal_cb(&@reactor.method(:_signal_callback))
|
219
|
+
end
|
220
|
+
|
221
|
+
def concrete_alloc_item
|
222
|
+
@item_pool.pop || FFI.uv_signal_alloc
|
223
|
+
end
|
224
|
+
|
225
|
+
def concrete_release_item(item)
|
226
|
+
@item_pool << item
|
227
|
+
end
|
228
|
+
|
229
|
+
def concrete_start_item(ident, item)
|
230
|
+
# TODO: need not init existing signal item?
|
231
|
+
Util.error_check "creating the signal handler item",
|
232
|
+
FFI.uv_signal_init(@reactor.ptr, item)
|
233
|
+
|
234
|
+
Util.error_check "starting the signal handler item",
|
235
|
+
FFI.uv_signal_start(item, @callback, ident)
|
236
|
+
end
|
237
|
+
|
238
|
+
def concrete_stop_item(ident, item)
|
239
|
+
Util.error_check "stopping the signal handler item",
|
240
|
+
FFI.uv_signal_stop(item)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
class Timer < Abstract
|
245
|
+
def initialize(*)
|
246
|
+
super
|
247
|
+
@item_pool = []
|
248
|
+
@callback = FFI.uv_timer_cb(&@reactor.method(:_timer_callback))
|
249
|
+
end
|
250
|
+
|
251
|
+
def concrete_alloc_item
|
252
|
+
@item_pool.pop || FFI.uv_timer_alloc
|
253
|
+
end
|
254
|
+
|
255
|
+
def concrete_release_item(item)
|
256
|
+
@item_pool << item
|
257
|
+
end
|
258
|
+
|
259
|
+
def concrete_start_item(ident, item, timeout)
|
260
|
+
timeout_ms = (timeout * 1000).ceil
|
261
|
+
|
262
|
+
# TODO: need not init existing timer item?
|
263
|
+
Util.error_check "creating the timer item",
|
264
|
+
FFI.uv_timer_init(@reactor.ptr, item)
|
265
|
+
|
266
|
+
Util.error_check "starting the timer item",
|
267
|
+
FFI.uv_timer_start(item, @callback, timeout_ms, timeout_ms)
|
268
|
+
end
|
269
|
+
|
270
|
+
def concrete_stop_item(ident, item)
|
271
|
+
Util.error_check "stopping the timer item",
|
272
|
+
FFI.uv_timer_stop(item)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bran
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe McIlvain
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -138,6 +138,7 @@ files:
|
|
138
138
|
- lib/bran/libuv.rb
|
139
139
|
- lib/bran/libuv/ffi.rb
|
140
140
|
- lib/bran/libuv/reactor.rb
|
141
|
+
- lib/bran/libuv/reactor/collections.rb
|
141
142
|
- lib/bran/libuv/util.rb
|
142
143
|
homepage: https://github.com/jemc/ruby-bran
|
143
144
|
licenses:
|