bran 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|