rbgo 0.3.2 → 0.3.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
  SHA256:
3
- metadata.gz: a366b8a6e6ab4c87ba41bd939f9d7f27668901accc91b2c8391e1408e25a6cac
4
- data.tar.gz: b44e73f8e6a5d45bcf5840d5c4de9294af6bea333ec88cc30da9a218b5991232
3
+ metadata.gz: 17553429e36bb85945fd70a9f0a5e1e77e0987d2c202d32f1c2c5e6cba2690b5
4
+ data.tar.gz: 11b5fa246822d7e8612046cd68465f13d838d7b86ea60bce80e4a89d6d6f7d28
5
5
  SHA512:
6
- metadata.gz: 227992f58aa87e3ee24160589bb5dfc9a51e6dd333295532be497492c12261549242eb87637fb7245140608014ef123937c100d8b4b2da6c3bc8238c23304e14
7
- data.tar.gz: f05339257fee9a92046468e77095281a6106daedeb75b337fd5246001b63cf6f526415e7aa277f1c6564517e8ec68e88aabf24fe557146578ce2abf1729ef824
6
+ metadata.gz: 13cd9e6735154aca3a0c539044fca29edf3fe84a97969b9c2dc05e55eed3976e019bf5f7ccd6c3d6408ee7ea388d4cc4d0789cc73516ae35a142a7d93643b900
7
+ data.tar.gz: 42222f0c07f7e2932c1815b0b75b0eb043553793f454238d12857819b67116bff6083078eb4fd3d9a17ea0c5d2301df4b3a472ec0c4c5a3de06169695db261c7
data/.gitignore CHANGED
@@ -7,4 +7,6 @@ tmp/*
7
7
  .rbx
8
8
  Gemfile.lock
9
9
  .bash_history
10
+ *.key
11
+ *.pem
10
12
 
data/README.md CHANGED
@@ -9,7 +9,7 @@ but not statically typed in my implementation.
9
9
  example:
10
10
 
11
11
  ```ruby
12
- relative 'rbgo'
12
+ require 'rbgo'
13
13
 
14
14
  include Rbgo::Channel
15
15
 
@@ -123,7 +123,20 @@ go do
123
123
  # ...
124
124
  Fiber.yield
125
125
  end
126
+ end
127
+
128
+ # yield_io create a new thread to do operations, current routine will yield to do other task,
129
+ # it will come back to go on execute when yield_io block finish.
130
+
131
+ require 'open-uri'
132
+ go do
133
+ res = yield_io do
134
+ f = open("http://www.google.com")
135
+ f.read
136
+ end
137
+ p res
126
138
  end
139
+
127
140
 
128
141
  # Or use go!
129
142
 
@@ -322,6 +335,15 @@ go do
322
335
  # this operation will *NOT* block the current thread
323
336
  # when io operation complete, thread will resume to execute from this point.
324
337
  p data
338
+ end
339
+
340
+ require 'open-uri'
341
+ go do
342
+ res = yield_io do
343
+ f = open("http://www.google.com")
344
+ f.read
345
+ end
346
+ p res
325
347
  end
326
348
 
327
349
  sleep 2
@@ -5,6 +5,7 @@ require_relative 'rbgo/reentrant_mutex'
5
5
  require_relative 'rbgo/reentrant_rw_mutex'
6
6
  require_relative 'rbgo/semaphore'
7
7
  require_relative 'rbgo/synchronized_collection'
8
+ require_relative 'rbgo/observer'
8
9
  require_relative 'rbgo/once'
9
10
  require_relative 'rbgo/actor'
10
11
  require_relative 'rbgo/task_list'
@@ -180,7 +180,7 @@ module Rbgo
180
180
  break
181
181
  else
182
182
  call_handler(msg)
183
- end
183
+ end
184
184
  Fiber.yield
185
185
  end
186
186
  end
@@ -2,13 +2,15 @@ require 'thread'
2
2
  require 'fiber'
3
3
  require 'system'
4
4
  require 'singleton'
5
+ require 'openssl'
5
6
  require_relative 'io_machine'
7
+ require_relative 'io_receipt'
6
8
  require_relative 'once'
7
9
 
8
10
  module Rbgo
9
11
  module CoRun
10
12
  IS_CORUN_FIBER = :is_corun_fiber_bbc0f70e
11
- LOCAL_TASK_QUEUES = :local_task_queues_bbc0f70e
13
+ LOCAL_TASK_QUEUES = :local_task_queues_bbc0f70e
12
14
  YIELD_IO_OPERATION = :yield_bbc0f70e
13
15
 
14
16
  def self.is_in_corun_fiber?
@@ -17,7 +19,24 @@ module Rbgo
17
19
 
18
20
  def self.have_other_task_on_thread?
19
21
  queues = Thread.current.thread_variable_get(LOCAL_TASK_QUEUES)
20
- queues&.any?{|q| !q.empty?}
22
+ queues&.any? { |q| !q.empty? }
23
+ end
24
+
25
+ def self.yield_io(&blk)
26
+ if is_in_corun_fiber?
27
+ receipt = IOReceipt.new([:yield_io])
28
+ CoRun::Routine.new(new_thread: true, queue_tag: :none) do
29
+ begin
30
+ res = blk&.call
31
+ receipt.res = res
32
+ ensure
33
+ receipt.notify
34
+ end
35
+ end
36
+ Fiber.yield [YIELD_IO_OPERATION, receipt]
37
+ else
38
+ blk&.call
39
+ end
21
40
  end
22
41
 
23
42
  def self.read_from(io, length: nil)
@@ -124,10 +143,15 @@ module Rbgo
124
143
  end
125
144
 
126
145
  def perform
127
- self.fiber = Fiber.new do |*args|
128
- Thread.current[IS_CORUN_FIBER] = true
129
- blk.call(*args)
130
- end if fiber.nil?
146
+ if fiber.nil?
147
+ self.fiber = Fiber.new do |*args|
148
+ Thread.current[IS_CORUN_FIBER] = true
149
+ blk.call(*args)
150
+ end
151
+ fiber.define_singleton_method(:transfer) do
152
+ raise 'can not call transfer on CoRun fiber'
153
+ end
154
+ end
131
155
 
132
156
  if fiber.alive?
133
157
  if io_receipt.nil?
@@ -203,8 +227,8 @@ module Rbgo
203
227
  yield_task_queue = Queue.new
204
228
  pending_io_task_queue = Queue.new
205
229
  local_task_queue = Queue.new
206
- Thread.current.thread_variable_set(LOCAL_TASK_QUEUES,[yield_task_queue, pending_io_task_queue, local_task_queue])
207
- task_queue = get_queue(queue_tag)
230
+ Thread.current.thread_variable_set(LOCAL_TASK_QUEUES, [yield_task_queue, pending_io_task_queue, local_task_queue])
231
+ task_queue = get_queue(queue_tag)
208
232
  local_task_queue << init_task if init_task
209
233
  loop do
210
234
  task = nil
@@ -292,7 +316,7 @@ module Rbgo
292
316
  end
293
317
  end
294
318
  ensure
295
- Rbgo.logger&.debug('Rbgo') { 'supervisor thread exit' }
319
+ Rbgo.logger&.warn('Rbgo') { 'supervisor thread exit' }
296
320
  end
297
321
  end
298
322
  nil
@@ -306,7 +330,7 @@ module Rbgo
306
330
  sleep check_interval
307
331
  end
308
332
  ensure
309
- Rbgo.logger&.debug('Rbgo') { 'check generator thread exit' }
333
+ Rbgo.logger&.warn('Rbgo') { 'check generator thread exit' }
310
334
  end
311
335
  end
312
336
  nil
@@ -377,6 +401,10 @@ module Rbgo
377
401
  def have_other_task_on_thread?
378
402
  CoRun.have_other_task_on_thread?
379
403
  end
404
+
405
+ def yield_io(&blk)
406
+ CoRun.yield_io(&blk)
407
+ end
380
408
  end
381
409
 
382
410
  refine IO do
@@ -418,5 +446,31 @@ module Rbgo
418
446
  CoRun.sendmsg_to(self, mesg, flags: flags, dest_sockaddr: dest_sockaddr, controls: controls)
419
447
  end
420
448
  end
449
+
450
+ refine OpenSSL::SSL::SSLSocket do
451
+ def yield_accept
452
+ CoRun.accept_from(self)
453
+ end
454
+
455
+ def yield_connect(remote_sockaddr)
456
+ CoRun.connect_to(self, remote_sockaddr: remote_sockaddr)
457
+ end
458
+
459
+ def yield_read(len = nil)
460
+ CoRun.read_from(self, length: len)
461
+ end
462
+
463
+ def yield_read_line(sep = $/, limit = nil)
464
+ CoRun.read_line_from(self, sep: sep, limit: limit)
465
+ end
466
+
467
+ def yield_read_partial(maxlen)
468
+ CoRun.read_partial_from(self, maxlen: maxlen)
469
+ end
470
+
471
+ def yield_write(str)
472
+ CoRun.write_to(self, str: str)
473
+ end
474
+ end
421
475
  end
422
476
  end
@@ -1,42 +1,8 @@
1
1
  require 'nio'
2
2
  require_relative 'actor'
3
+ require_relative 'io_receipt'
3
4
 
4
5
  module Rbgo
5
- class IOReceipt
6
- attr_reader :registered_op, :done_flag
7
- attr_accessor :res
8
-
9
- def wait
10
- mutex.synchronize do
11
- until done_flag
12
- cond.wait(mutex)
13
- end
14
- end
15
- nil
16
- end
17
-
18
- def notify
19
- mutex.synchronize do
20
- self.done_flag = true
21
- cond.signal
22
- end
23
- nil
24
- end
25
-
26
- private
27
-
28
- attr_accessor :mutex, :cond
29
- attr_writer :registered_op, :done_flag
30
-
31
- def initialize(op)
32
- self.done_flag = false
33
- self.mutex = Mutex.new
34
- self.cond = ConditionVariable.new
35
- self.registered_op = op
36
- end
37
- end
38
-
39
-
40
6
  class IOMachine
41
7
  def do_read(io, length: nil)
42
8
  op = [:register_read, io, length]
@@ -638,25 +604,24 @@ module Rbgo
638
604
  def handle_write_msg(receipt, actor)
639
605
  op = receipt.registered_op
640
606
  io = op[1]
641
- str = op[2].to_s
607
+ buf = op[2].to_s
642
608
 
643
609
  monitor = register(receipt, interest: :w)
644
610
  return if monitor.nil?
645
611
 
646
- buf = NIO::ByteBuffer.new(str.bytesize)
647
- buf << str
648
- buf.flip
649
612
  bytes_written_n = 0
650
613
  monitor.value ||= []
651
614
  monitor.value[1] = proc do
652
615
  begin
653
- if buf.remaining > 0
654
- n = buf.write_to(io)
655
- bytes_written_n += n
616
+ if buf.size - bytes_written_n > 0
617
+ n = io.write_nonblock(buf[bytes_written_n..-1], exception: false)
618
+ if n.is_a? Numeric
619
+ bytes_written_n += n
620
+ end
656
621
  else
657
622
  monitors.delete(monitor.io)
658
623
  monitor.close
659
- receipt.res = str.bytesize
624
+ receipt.res = buf.bytesize
660
625
  receipt.notify
661
626
  end
662
627
  rescue Exception => ex
@@ -674,6 +639,15 @@ module Rbgo
674
639
  def register(receipt, interest:)
675
640
  io = receipt.registered_op[1]
676
641
  registered_monitor = monitors[io]
642
+
643
+ if io.closed?
644
+ monitors.delete(io)
645
+ registered_monitor.close if registered_monitor
646
+ receipt.res = nil
647
+ receipt.notify
648
+ return nil
649
+ end
650
+
677
651
  if registered_monitor && (registered_monitor.interests == interest || registered_monitor.interests == :rw)
678
652
  actor.send_msg receipt
679
653
  return nil
@@ -0,0 +1,35 @@
1
+ module Rbgo
2
+ class IOReceipt
3
+ attr_reader :registered_op, :done_flag
4
+ attr_accessor :res
5
+
6
+ def wait
7
+ mutex.synchronize do
8
+ until done_flag
9
+ cond.wait(mutex)
10
+ end
11
+ end
12
+ nil
13
+ end
14
+
15
+ def notify
16
+ mutex.synchronize do
17
+ self.done_flag = true
18
+ cond.signal
19
+ end
20
+ nil
21
+ end
22
+
23
+ private
24
+
25
+ attr_accessor :mutex, :cond
26
+ attr_writer :registered_op, :done_flag
27
+
28
+ def initialize(op)
29
+ self.done_flag = false
30
+ self.mutex = Mutex.new
31
+ self.cond = ConditionVariable.new
32
+ self.registered_op = op
33
+ end
34
+ end
35
+ end
@@ -1,4 +1,5 @@
1
1
  require 'socket'
2
+ require 'openssl'
2
3
  require_relative 'select_chan'
3
4
  require_relative 'corun'
4
5
 
@@ -39,7 +40,138 @@ module Rbgo
39
40
  end
40
41
  end
41
42
 
42
- def open_tcp_service(host = nil, port, &blk)
43
+ def self.open_tcp_service_with_sockets(sockets, &blk)
44
+ res_chan = Chan.new(1)
45
+ service = Service.send :new
46
+
47
+ routine = go! do
48
+ service.send :type=, :tcp
49
+ service.send :host=, sockets.first.local_address.ip_address
50
+ service.send :port=, sockets.first.local_address.ip_port
51
+ service.task = blk
52
+ service.send :sockets=, sockets
53
+ res_chan << service
54
+ begin
55
+ Socket.accept_loop(sockets) do |sock, clientAddrInfo|
56
+ go do
57
+ if service.task.nil?
58
+ sock.close
59
+ else
60
+ service.task.call(sock, clientAddrInfo)
61
+ end
62
+ end
63
+ end
64
+ rescue Exception => ex
65
+ Rbgo.logger&.error('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
66
+ end
67
+ end
68
+ service.send :service_routine=, routine
69
+ res_chan.deq
70
+ service
71
+ end
72
+
73
+ def self.open_ssl_service_with_socket(socket, cert_file, key_file, &blk)
74
+ res_chan = Chan.new(1)
75
+ service = Service.send :new
76
+
77
+ routine = go! do
78
+ service.send :type=, :tcp
79
+ service.send :host=, socket.local_address.ip_address
80
+ service.send :port=, socket.local_address.ip_port
81
+ service.task = blk
82
+ begin
83
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
84
+ key = OpenSSL::PKey::RSA.new(File.open(key_file))
85
+ ctx = OpenSSL::SSL::SSLContext.new()
86
+ ctx.cert = cert
87
+ ctx.key = key
88
+
89
+ tcp_server = socket
90
+ ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)
91
+ service.send :sockets=, [ssl_server]
92
+ res_chan << service
93
+ begin
94
+ loop do
95
+ sock = ssl_server.accept
96
+ sock.sync_close = true
97
+ go do
98
+ if service.task.nil?
99
+ sock.close
100
+ else
101
+ service.task.call(sock, sock.io.remote_address)
102
+ end
103
+ end
104
+ end
105
+ rescue Exception => ex
106
+ if ex.is_a? OpenSSL::SSL::SSLError
107
+ Rbgo.logger&.info('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
108
+ retry
109
+ else
110
+ Rbgo.logger&.error('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
111
+ end
112
+ end
113
+ rescue Exception => ex
114
+ res_chan << service
115
+ Rbgo.logger&.error('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
116
+ end
117
+ end
118
+ service.send :service_routine=, routine
119
+ res_chan.deq
120
+ service
121
+ end
122
+
123
+ def self.open_ssl_service(host = nil, port, cert_file, key_file, &blk)
124
+ res_chan = Chan.new(1)
125
+ service = Service.send :new
126
+
127
+ routine = go! do
128
+ service.send :type=, :tcp
129
+ service.send :host=, host
130
+ service.send :port=, port
131
+ service.task = blk
132
+ begin
133
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
134
+ key = OpenSSL::PKey::RSA.new(File.open(key_file))
135
+ ctx = OpenSSL::SSL::SSLContext.new()
136
+ ctx.cert = cert
137
+ ctx.key = key
138
+
139
+ tcp_server = TCPServer.new(host, port)
140
+ service.send :port=, tcp_server.local_address.ip_port
141
+ ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)
142
+ service.send :sockets=, [ssl_server]
143
+ res_chan << service
144
+ begin
145
+ loop do
146
+ sock = ssl_server.accept
147
+ sock.sync_close = true
148
+ go do
149
+ if service.task.nil?
150
+ sock.close
151
+ else
152
+ service.task.call(sock, sock.io.remote_address)
153
+ end
154
+ end
155
+ end
156
+ rescue Exception => ex
157
+ if ex.is_a? OpenSSL::SSL::SSLError
158
+ Rbgo.logger&.info('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
159
+ retry
160
+ else
161
+ Rbgo.logger&.error('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
162
+ end
163
+ end
164
+ rescue Exception => ex
165
+ res_chan << service
166
+ Rbgo.logger&.error('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
167
+ end
168
+ end
169
+ service.send :service_routine=, routine
170
+ res_chan.deq
171
+ service
172
+ end
173
+
174
+ def self.open_tcp_service(host = nil, port, &blk)
43
175
 
44
176
  res_chan = Chan.new(1)
45
177
  service = Service.send :new
@@ -78,7 +210,32 @@ module Rbgo
78
210
  service
79
211
  end
80
212
 
81
- def open_udp_service(host = nil, port, &blk)
213
+ def self.open_udp_service_with_sockets(sockets, &blk)
214
+ res_chan = Chan.new(1)
215
+ service = Service.send :new
216
+ routine = go! do
217
+ service.send :type=, :udp
218
+ service.send :host=, sockets.first.local_address.ip_address
219
+ service.send :port=, sockets.first.local_address.ip_port
220
+ service.task = blk
221
+ service.send :sockets=, sockets
222
+ res_chan << service
223
+ begin
224
+ Socket.udp_server_loop_on(sockets) do |msg, msg_src|
225
+ go do
226
+ service.task&.call(msg, msg_src)
227
+ end
228
+ end
229
+ rescue Exception => ex
230
+ Rbgo.logger&.error('Rbgo') { "#{ex.message}\n#{ex.backtrace}" }
231
+ end
232
+ end
233
+ service.send :service_routine=, routine
234
+ res_chan.deq
235
+ service
236
+ end
237
+
238
+ def self.open_udp_service(host = nil, port, &blk)
82
239
 
83
240
  res_chan = Chan.new(1)
84
241
  service = Service.send :new
@@ -96,7 +253,7 @@ module Rbgo
96
253
  begin
97
254
  Socket.udp_server_loop_on(sockets) do |msg, msg_src|
98
255
  go do
99
- service.task.call(msg, msg_src) unless service.task.nil?
256
+ service.task&.call(msg, msg_src)
100
257
  end
101
258
  end
102
259
  rescue Exception => ex
@@ -112,8 +269,5 @@ module Rbgo
112
269
  res_chan.deq
113
270
  service
114
271
  end
115
-
116
- module_function :open_tcp_service, :open_udp_service
117
- public :open_tcp_service, :open_udp_service
118
272
  end
119
273
  end
@@ -0,0 +1,69 @@
1
+ require 'thread'
2
+ require_relative 'synchronized_collection'
3
+ require_relative 'corun'
4
+
5
+ module Rbgo
6
+ module Observable
7
+ @mutex = Mutex.new
8
+
9
+ def add_observer(observer, func = :update)
10
+ unless defined? @observer_peers
11
+ Observable.instance_variable_get(:@mutex).synchronize do
12
+ @observer_peers = SyncHash.new unless defined? @observer_peers
13
+ end
14
+ end
15
+
16
+ unless observer.respond_to? func
17
+ raise NoMethodError, "observer does not respond to `#{func}'"
18
+ end
19
+ @observer_peers[observer] = func
20
+ end
21
+
22
+ def delete_observer(observer)
23
+ @observer_peers.delete observer if defined? @observer_peers
24
+ end
25
+
26
+ def delete_observers
27
+ @observer_peers.clear if defined? @observer_peers
28
+ end
29
+
30
+ def count_observers
31
+ if defined? @observer_peers
32
+ @observer_peers.size
33
+ else
34
+ 0
35
+ end
36
+ end
37
+
38
+ def changed(state = true)
39
+ Observable.instance_variable_get(:@mutex).synchronize do
40
+ @observer_state = state
41
+ end
42
+ end
43
+
44
+ def changed?
45
+ if defined? @observer_state and @observer_state
46
+ true
47
+ else
48
+ false
49
+ end
50
+ end
51
+
52
+ def notify_observers(*arg)
53
+ if defined? @observer_state and @observer_state
54
+ if defined? @observer_peers
55
+ Observable.instance_variable_get(:@mutex).synchronize do
56
+ if @observer_state
57
+ @observer_peers.each do |k, v|
58
+ CoRun::Routine.new(new_thread: false, queue_tag: :default) do
59
+ k.send v, *arg
60
+ end
61
+ end
62
+ @observer_state = false
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,4 +1,5 @@
1
1
  require 'thread'
2
+ require 'set'
2
3
 
3
4
  module Rbgo
4
5
  module Channel
@@ -29,25 +30,35 @@ module Rbgo
29
30
  end
30
31
  end
31
32
 
32
- def self.after(seconds)
33
+ def self.after(seconds, &blk)
33
34
  ch = new
34
35
  CoRun::Routine.new(new_thread: true, queue_tag: :none) do
35
- sleep seconds
36
- ch << Time.now rescue nil
37
- ch.close
36
+ begin
37
+ sleep seconds
38
+ v = blk.nil? ? Time.now : blk.call
39
+ ch << v rescue nil
40
+ ensure
41
+ ch.close
42
+ end
38
43
  end
39
44
  ch
40
45
  end
41
46
 
42
- def self.tick(every_seconds)
47
+ def self.tick(every_seconds, &blk)
43
48
  ch = new
44
49
  CoRun::Routine.new(new_thread: true, queue_tag: :none) do
45
- loop do
46
- sleep every_seconds
47
- begin
48
- ch.enq(Time.now, true)
49
- rescue ThreadError
50
+ begin
51
+ loop do
52
+ break if ch.closed?
53
+ sleep every_seconds
54
+ v = blk.nil? ? Time.now : blk.call
55
+ begin
56
+ ch.enq(v, true)
57
+ rescue ThreadError
58
+ end
50
59
  end
60
+ ensure
61
+ ch.close
51
62
  end
52
63
  end
53
64
  ch
@@ -57,9 +68,11 @@ module Rbgo
57
68
  ch = new
58
69
  CoRun::Routine.new(new_thread: false, queue_tag: :default) do
59
70
  begin
71
+ res = nil
60
72
  Timeout::timeout(timeout) do
61
- blk.call
73
+ res = blk.call
62
74
  end
75
+ ch << res rescue nil
63
76
  rescue Timeout::Error
64
77
  ensure
65
78
  ch.close
@@ -75,11 +88,16 @@ module Rbgo
75
88
 
76
89
  def register(io)
77
90
  register_mutex.synchronize do
78
- ios.delete_if { |io| io.closed? }
79
91
  ios << io
80
92
  end
81
93
  end
82
94
 
95
+ def unregister(io)
96
+ register_mutex.synchronize do
97
+ ios.delete(io)
98
+ end
99
+ end
100
+
83
101
  def notify
84
102
  register_mutex.synchronize do
85
103
  ios.each do |io|
@@ -110,7 +128,7 @@ module Rbgo
110
128
  self.have_enq_waiting_flag = false
111
129
  self.have_deq_waiting_flag = false
112
130
 
113
- self.ios = []
131
+ self.ios = Set.new
114
132
  self.register_mutex = Mutex.new
115
133
  end
116
134
 
@@ -241,12 +259,12 @@ module Rbgo
241
259
  alias_method :queue_max, :max
242
260
  alias_method :queue_max=, :max=
243
261
  include Chan
244
-
262
+
245
263
  def initialize(max)
246
264
  super(max)
247
265
  @mutex = Mutex.new
248
266
  @cond = ConditionVariable.new
249
- self.ios = []
267
+ self.ios = Set.new
250
268
  self.register_mutex = Mutex.new
251
269
  end
252
270
 
@@ -331,10 +349,10 @@ module Rbgo
331
349
 
332
350
  io_hash = {}
333
351
  close_io_blk = proc do
334
- io_hash.each_pair.flat_map do |k, v|
335
- [k, v[1]]
336
- end.each do |io|
337
- io.close rescue nil
352
+ io_hash.each_pair do |io_r, (op, io_w)|
353
+ io_r.close rescue nil
354
+ io_w.close rescue nil
355
+ op.unregister(io_w)
338
356
  end
339
357
  end
340
358
 
@@ -392,6 +410,9 @@ module Rbgo
392
410
  op.define_singleton_method(:register) do |io_w|
393
411
  chan.send :register, io_w
394
412
  end
413
+ op.define_singleton_method(:unregister) do|io_w|
414
+ chan.send :unregister, io_w
415
+ end
395
416
  op
396
417
  end
397
418
 
@@ -411,6 +432,9 @@ module Rbgo
411
432
  op.define_singleton_method(:register) do |io_w|
412
433
  chan.send :register, io_w
413
434
  end
435
+ op.define_singleton_method(:unregister) do|io_w|
436
+ chan.send :unregister, io_w
437
+ end
414
438
  op
415
439
  end
416
440
 
@@ -2,73 +2,44 @@ require 'monitor'
2
2
  require 'set'
3
3
 
4
4
  module Rbgo
5
- class SyncArray
6
- def self.[](*args)
7
- SyncArray.new(Array.[](*args))
8
- end
9
-
10
- def self.try_convert(obj)
11
- a = Array.try_convert(obj)
12
- a.nil? ? nil : SyncArray.new(a)
13
- end
5
+ class SyncArray < Array
6
+ include MonitorMixin
14
7
 
15
- def initialize(*args, &blk)
16
- @a = Array.new(*args, &blk)
17
- @a.extend(MonitorMixin)
8
+ def initialize(*args)
9
+ super(*args)
18
10
  end
19
11
 
20
- Array.public_instance_methods.each do |m|
12
+ Array.public_methods.each do |m|
21
13
  define_method(m) do |*args, &blk|
22
- @a.synchronize do
23
- @a.send m, *args, &blk
24
- end
14
+ synchronize { super(*args, &blk) }
25
15
  end
26
16
  end
27
17
  end
28
18
 
29
- class SyncHash
30
- def self.[](*args)
31
- h = SyncHash.new
32
- h.instance_eval do
33
- @h = Hash.[](*args)
34
- @h.extend(MonitorMixin)
35
- end
36
- end
37
-
38
- def self.try_convert(obj)
39
- h = Hash.try_convert(obj)
40
- h.nil? ? nil : SyncHash.[](h)
41
- end
19
+ class SyncHash < Hash
20
+ include MonitorMixin
42
21
 
43
- def initialize(*args, &blk)
44
- @h = Hash.new(*args, &blk)
45
- @h.extend(MonitorMixin)
22
+ def initialize(*args)
23
+ super(*args)
46
24
  end
47
25
 
48
- Hash.public_instance_methods.each do |m|
26
+ Hash.public_methods.each do |m|
49
27
  define_method(m) do |*args, &blk|
50
- @h.synchronize do
51
- @h.send m, *args, &blk
52
- end
28
+ synchronize { super(*args, &blk) }
53
29
  end
54
30
  end
55
31
  end
56
32
 
57
- class SyncSet
58
- def self.[](*args)
59
- SyncSet.new(Set.[](*args))
60
- end
33
+ class SyncSet < Set
34
+ include MonitorMixin
61
35
 
62
- def initialize(enum = nil)
63
- @s = Set.new(enum)
64
- @s.extend(MonitorMixin)
36
+ def initialize(*args)
37
+ super(*args)
65
38
  end
66
39
 
67
- Set.public_instance_methods.each do |m|
40
+ Set.public_methods.each do |m|
68
41
  define_method(m) do |*args, &blk|
69
- @s.synchronize do
70
- @s.send m, *args, &blk
71
- end
42
+ synchronize { super(*args, &blk) }
72
43
  end
73
44
  end
74
45
  end
@@ -1,3 +1,3 @@
1
1
  module Rbgo
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbgo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wang Yin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-27 00:00:00.000000000 Z
11
+ date: 2020-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: system
@@ -53,7 +53,9 @@ files:
53
53
  - lib/rbgo/actor.rb
54
54
  - lib/rbgo/corun.rb
55
55
  - lib/rbgo/io_machine.rb
56
+ - lib/rbgo/io_receipt.rb
56
57
  - lib/rbgo/network_service.rb
58
+ - lib/rbgo/observer.rb
57
59
  - lib/rbgo/once.rb
58
60
  - lib/rbgo/reentrant_mutex.rb
59
61
  - lib/rbgo/reentrant_rw_mutex.rb