rbgo 0.3.2 → 0.3.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
  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