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 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: