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