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 +4 -4
- data/.gitignore +2 -0
- data/README.md +23 -1
- data/lib/rbgo.rb +1 -0
- data/lib/rbgo/actor.rb +1 -1
- data/lib/rbgo/corun.rb +64 -10
- data/lib/rbgo/io_machine.rb +17 -43
- data/lib/rbgo/io_receipt.rb +35 -0
- data/lib/rbgo/network_service.rb +160 -6
- data/lib/rbgo/observer.rb +69 -0
- data/lib/rbgo/select_chan.rb +43 -19
- data/lib/rbgo/synchronized_collection.rb +18 -47
- data/lib/rbgo/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17553429e36bb85945fd70a9f0a5e1e77e0987d2c202d32f1c2c5e6cba2690b5
|
4
|
+
data.tar.gz: 11b5fa246822d7e8612046cd68465f13d838d7b86ea60bce80e4a89d6d6f7d28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13cd9e6735154aca3a0c539044fca29edf3fe84a97969b9c2dc05e55eed3976e019bf5f7ccd6c3d6408ee7ea388d4cc4d0789cc73516ae35a142a7d93643b900
|
7
|
+
data.tar.gz: 42222f0c07f7e2932c1815b0b75b0eb043553793f454238d12857819b67116bff6083078eb4fd3d9a17ea0c5d2301df4b3a472ec0c4c5a3de06169695db261c7
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@ but not statically typed in my implementation.
|
|
9
9
|
example:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
|
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
|
data/lib/rbgo.rb
CHANGED
@@ -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'
|
data/lib/rbgo/actor.rb
CHANGED
data/lib/rbgo/corun.rb
CHANGED
@@ -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
|
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
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
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&.
|
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&.
|
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
|
data/lib/rbgo/io_machine.rb
CHANGED
@@ -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
|
-
|
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.
|
654
|
-
n =
|
655
|
-
|
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 =
|
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
|
data/lib/rbgo/network_service.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
data/lib/rbgo/select_chan.rb
CHANGED
@@ -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
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
335
|
-
|
336
|
-
|
337
|
-
|
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
|
-
|
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
|
16
|
-
|
17
|
-
@a.extend(MonitorMixin)
|
8
|
+
def initialize(*args)
|
9
|
+
super(*args)
|
18
10
|
end
|
19
11
|
|
20
|
-
Array.
|
12
|
+
Array.public_methods.each do |m|
|
21
13
|
define_method(m) do |*args, &blk|
|
22
|
-
|
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
|
-
|
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
|
44
|
-
|
45
|
-
@h.extend(MonitorMixin)
|
22
|
+
def initialize(*args)
|
23
|
+
super(*args)
|
46
24
|
end
|
47
25
|
|
48
|
-
Hash.
|
26
|
+
Hash.public_methods.each do |m|
|
49
27
|
define_method(m) do |*args, &blk|
|
50
|
-
|
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
|
-
|
59
|
-
SyncSet.new(Set.[](*args))
|
60
|
-
end
|
33
|
+
class SyncSet < Set
|
34
|
+
include MonitorMixin
|
61
35
|
|
62
|
-
def initialize(
|
63
|
-
|
64
|
-
@s.extend(MonitorMixin)
|
36
|
+
def initialize(*args)
|
37
|
+
super(*args)
|
65
38
|
end
|
66
39
|
|
67
|
-
Set.
|
40
|
+
Set.public_methods.each do |m|
|
68
41
|
define_method(m) do |*args, &blk|
|
69
|
-
|
70
|
-
@s.send m, *args, &blk
|
71
|
-
end
|
42
|
+
synchronize { super(*args, &blk) }
|
72
43
|
end
|
73
44
|
end
|
74
45
|
end
|
data/lib/rbgo/version.rb
CHANGED
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.
|
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:
|
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
|