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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28390755dc30a2dc1027f082f7f5340d88222bb8
4
- data.tar.gz: 32514e834d6f931cab276f2480d45be6588e3982
3
+ metadata.gz: a56dfe96ac8bd822a8dce4018ba0ad9f8fb090a6
4
+ data.tar.gz: 6e3045d8630a7264569f67350712d9f065b1f968
5
5
  SHA512:
6
- metadata.gz: 52c90e1f8c60ccc4607da7af594e30366732c1a97778b320749f09f5feced266b4169bb5e1320621fc7a8a72eef7aee3f1edc6ddac2bd85b392e3e33024e7aa6
7
- data.tar.gz: 86e450e1c22aacd177e02e4331f71100de0761912361304d63eb9bd579327a05a4874202c3caccc86d085384959d7512c59b30ad52bb783f9d6c41e62852e1e1
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
- @multi.socketfunction = method(:_socketfunction_callback).to_proc
35
- @multi.timerfunction = method(:_timerfunction_callback).to_proc
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.timer_cancel @timeout_timer if @timeout_timer
122
+ @fm.loop.pop_timable @timeout_timer if @timeout_timer
119
123
  end
120
124
 
121
125
  def socket_action!(fd, flags)
@@ -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.timer_cancel(timer) if timer
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.signal_start(:INT) { exit!(0) }
44
- manager.loop.signal_start(:TERM) { exit!(0) }
45
- manager.loop.signal_start(:USR1) { reopen_worker_logs(worker.nr) } # TODO: test
46
- manager.loop.signal_start(:QUIT) { stopping = true } # TODO: test softness
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
- manager.wait_for_readable!(reader)
55
- process_client.call(reader.kgio_accept)
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
@@ -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
- @available_polls = []
18
- @running_reads = {}
19
- @running_writes = {}
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
- @poll_read_callback = FFI.uv_poll_cb(&method(:_poll_read_callback))
32
- @poll_write_callback = FFI.uv_poll_cb(&method(:_poll_write_callback))
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
- signal_start(:INT) { @abort_signal = :INT; stop! }
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
- @available_polls = \
49
- @running_reads = @running_writes = \
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
- ptr = ptr()
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
- ptr = ptr()
140
- fd = Integer(fd)
141
- poll = nil
142
-
143
- if (writables = @on_writables[fd])
144
- writables << [handler, persistent]
145
- elsif (poll = @running_reads[fd])
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
- fd
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
- fd = Integer(fd)
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
- fd = Integer(fd)
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
- # Start handling the given signal, running the given block when it occurs.
227
- def signal_start(signo, &block)
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
- signal_stop(signo) if @running_signals.has_key?(signo)
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
- # Stop handling the given signal.
251
- def signal_stop(signo)
252
- signo = Signal.list.fetch(signo.to_s) unless signo.is_a?(Integer)
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
- timer_start(time, &block)
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
- timer_start(time) { fiber.resume } # TODO: optimize this case
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 _poll_read_callback(poll, rc, events)
153
+ def _read_callback(poll, rc, events)
341
154
  rescue_abort do
342
- fd = @fds_by_read_addr[poll.address]
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 _poll_write_callback(poll, rc, events)
160
+ def _write_callback(poll, rc, events)
356
161
  rescue_abort do
357
- fd = @fds_by_write_addr[poll.address]
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 _poll_rw_callback(poll, rc, events)
371
- _poll_read_callback(poll, rc, events) if events & FFI::UV_READABLE != 0
372
- _poll_write_callback(poll, rc, events) if events & FFI::UV_WRITABLE != 0
373
- end
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
- when ::Proc
385
- if rc == 0
386
- handler.call nil
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.2
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-09 00:00:00.000000000 Z
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: