qpid_proton 0.22.0 → 0.23.0
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/{LICENSE → LICENSE.txt} +0 -0
- data/examples/broker.rb +3 -4
- data/examples/direct_recv.rb +1 -1
- data/examples/direct_send.rb +1 -1
- data/examples/example_test.rb +15 -15
- data/examples/{ssl_certs → ssl-certs}/README.txt +0 -0
- data/examples/{ssl_certs → ssl-certs}/tclient-certificate.p12 +0 -0
- data/examples/{ssl_certs → ssl-certs}/tclient-certificate.pem +0 -0
- data/examples/{ssl_certs → ssl-certs}/tclient-full.p12 +0 -0
- data/examples/{ssl_certs → ssl-certs}/tclient-private-key.pem +0 -0
- data/examples/{ssl_certs → ssl-certs}/tserver-certificate.p12 +0 -0
- data/examples/{ssl_certs → ssl-certs}/tserver-certificate.pem +0 -0
- data/examples/{ssl_certs → ssl-certs}/tserver-full.p12 +0 -0
- data/examples/{ssl_certs → ssl-certs}/tserver-private-key.pem +0 -0
- data/ext/cproton/cproton.c +42 -1
- data/lib/core/container.rb +75 -110
- data/lib/core/disposition.rb +24 -6
- data/lib/core/exceptions.rb +4 -0
- data/lib/core/listener.rb +10 -4
- data/lib/core/transfer.rb +1 -20
- data/lib/core/work_queue.rb +54 -33
- data/lib/util/schedule.rb +21 -37
- data/tests/{old_examples → old-examples}/broker.rb +0 -0
- data/tests/{old_examples → old-examples}/client.rb +0 -0
- data/tests/{old_examples → old-examples}/direct_recv.rb +0 -0
- data/tests/{old_examples → old-examples}/direct_send.rb +0 -0
- data/tests/{old_examples → old-examples}/helloworld.rb +0 -0
- data/tests/{old_examples → old-examples}/helloworld_direct.rb +0 -0
- data/tests/{old_examples → old-examples}/lib/debugging.rb +0 -0
- data/tests/{old_examples → old-examples}/lib/driver.rb +0 -0
- data/tests/{old_examples → old-examples}/lib/qpid_examples.rb +0 -0
- data/tests/{old_examples → old-examples}/lib/selectable.rb +0 -0
- data/tests/{old_examples → old-examples}/lib/send_and_receive.rb +0 -0
- data/tests/{old_examples → old-examples}/old_example_test.rb +0 -0
- data/tests/{old_examples → old-examples}/server.rb +0 -0
- data/tests/{old_examples → old-examples}/simple_recv.rb +0 -0
- data/tests/{old_examples → old-examples}/simple_send.rb +0 -0
- data/tests/test_container.rb +97 -29
- data/tests/test_delivery.rb +8 -0
- data/tests/test_interop.rb +1 -1
- data/tests/test_tools.rb +3 -3
- data/tests/test_utils.rb +63 -0
- metadata +28 -29
- data/ChangeLog +0 -185
- data/TODO +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e42bf4b912dd9ac683d708d1f495f930524ae050
|
4
|
+
data.tar.gz: 88efa2086f91726b70d22ec26335c4199bd937e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb46d347def13c8622f75d4a5db0f5263a3ea0659cdf140a6cbf2e7a1f3dd6a8ec4152313c0c7d61651530ca64beecc451a00926b176901ff018268fc867033a
|
7
|
+
data.tar.gz: 275ada30ae20a91a49cba9ae86352da2aaca5240294899165971d2cfb8540fcfefda5956dc9862fb6743eb26620c12e7a9af15c6afbd4acc589a087db990e34e
|
data/{LICENSE → LICENSE.txt}
RENAMED
File without changes
|
data/examples/broker.rb
CHANGED
@@ -70,7 +70,6 @@ class MessageQueue
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
73
|
# Handler for broker connections. In a multi-threaded application you should
|
75
74
|
# normally create a separate handler instance for each connection.
|
76
75
|
class BrokerHandler < Qpid::Proton::MessagingHandler
|
@@ -136,9 +135,9 @@ class Broker < Qpid::Proton::Listener::Handler
|
|
136
135
|
ssl = Qpid::Proton::SSLDomain.new(Qpid::Proton::SSLDomain::MODE_SERVER)
|
137
136
|
cert_passsword = "tserverpw"
|
138
137
|
if Gem.win_platform? # Use P12 certs for windows schannel
|
139
|
-
ssl.credentials("
|
138
|
+
ssl.credentials("ssl-certs/tserver-certificate.p12", "", cert_passsword)
|
140
139
|
else
|
141
|
-
ssl.credentials("
|
140
|
+
ssl.credentials("ssl-certs/tserver-certificate.pem", "ssl-certs/tserver-private-key.pem", cert_passsword)
|
142
141
|
end
|
143
142
|
ssl.allow_unsecured_client # SSL is optional, this is not secure.
|
144
143
|
@connection_options[:ssl_domain] = ssl if ssl
|
@@ -147,7 +146,7 @@ class Broker < Qpid::Proton::Listener::Handler
|
|
147
146
|
end
|
148
147
|
|
149
148
|
def on_open(l)
|
150
|
-
STDOUT.puts "Listening on #{l}\n"; STDOUT.flush
|
149
|
+
STDOUT.puts "Listening on #{l.port}\n"; STDOUT.flush
|
151
150
|
end
|
152
151
|
|
153
152
|
# Create a new BrokerHandler instance for each connection we accept
|
data/examples/direct_recv.rb
CHANGED
@@ -31,7 +31,7 @@ class DirectReceive < Qpid::Proton::MessagingHandler
|
|
31
31
|
end
|
32
32
|
|
33
33
|
class ListenOnce < Qpid::Proton::Listener::Handler
|
34
|
-
def on_open(l) STDOUT.puts "Listening\n"; STDOUT.flush; end
|
34
|
+
def on_open(l) STDOUT.puts "Listening on #{l.port}\n"; STDOUT.flush; end
|
35
35
|
def on_accept(l) l.close; end
|
36
36
|
end
|
37
37
|
|
data/examples/direct_send.rb
CHANGED
@@ -32,7 +32,7 @@ class DirectSend < Qpid::Proton::MessagingHandler
|
|
32
32
|
end
|
33
33
|
|
34
34
|
class ListenOnce < Qpid::Proton::Listener::Handler
|
35
|
-
def on_open(l) STDOUT.puts "Listening\n"; STDOUT.flush; end
|
35
|
+
def on_open(l) STDOUT.puts "Listening on #{l.port}\n"; STDOUT.flush; end
|
36
36
|
def on_accept(l) l.close; end
|
37
37
|
end
|
38
38
|
|
data/examples/example_test.rb
CHANGED
@@ -29,11 +29,13 @@ rescue NameError # For older versions of MiniTest
|
|
29
29
|
MiniTest::Test = MiniTest::Unit::TestCase
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
"amqp://:#{TCPServer.open(0) { |s| s.addr[1] }}"
|
32
|
+
def listening_port(s)
|
33
|
+
/Listening on ([0-9]+)/.match(s)[1]
|
35
34
|
end
|
36
35
|
|
36
|
+
def listening_url(s)
|
37
|
+
":#{listening_port s}"
|
38
|
+
end
|
37
39
|
|
38
40
|
class ExampleTest < MiniTest::Test
|
39
41
|
|
@@ -80,18 +82,16 @@ EOS
|
|
80
82
|
end
|
81
83
|
|
82
84
|
def test_direct_recv
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
assert_equal(want.strip, p.read.strip)
|
85
|
+
p = run_script("direct_recv.rb", ":0", "examples")
|
86
|
+
url = listening_url(p.readline) # Wait till ready
|
87
|
+
assert_output("All 10 messages confirmed!", "simple_send.rb", url, "examples")
|
88
|
+
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
89
|
+
assert_equal(want.strip, p.read.strip)
|
89
90
|
end
|
90
91
|
|
91
92
|
def test_direct_send
|
92
|
-
|
93
|
-
|
94
|
-
p.readline # Wait till ready
|
93
|
+
p = run_script("direct_send.rb", ":0", "examples")
|
94
|
+
url = listening_url(p.readline) # Wait till ready
|
95
95
|
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
96
96
|
assert_output(want.strip, "simple_recv.rb", url, "examples")
|
97
97
|
assert_equal("All 10 messages confirmed!", p.read.strip)
|
@@ -99,9 +99,9 @@ EOS
|
|
99
99
|
end
|
100
100
|
|
101
101
|
# Start the broker before all tests.
|
102
|
-
$
|
103
|
-
|
104
|
-
$
|
102
|
+
$broker = IO.popen([RbConfig.ruby, 'broker.rb', ":0"])
|
103
|
+
l = $broker.readline
|
104
|
+
$url = listening_url(l)
|
105
105
|
|
106
106
|
# Kill the broker after all tests
|
107
107
|
MiniTest.after_run do
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/ext/cproton/cproton.c
CHANGED
@@ -14790,6 +14790,46 @@ fail:
|
|
14790
14790
|
}
|
14791
14791
|
|
14792
14792
|
|
14793
|
+
SWIGINTERN VALUE
|
14794
|
+
_wrap_pn_message_send(int argc, VALUE *argv, VALUE self) {
|
14795
|
+
pn_message_t *arg1 = (pn_message_t *) 0 ;
|
14796
|
+
pn_link_t *arg2 = (pn_link_t *) 0 ;
|
14797
|
+
pn_rwbytes_t *arg3 = (pn_rwbytes_t *) 0 ;
|
14798
|
+
void *argp1 = 0 ;
|
14799
|
+
int res1 = 0 ;
|
14800
|
+
void *argp2 = 0 ;
|
14801
|
+
int res2 = 0 ;
|
14802
|
+
void *argp3 = 0 ;
|
14803
|
+
int res3 = 0 ;
|
14804
|
+
ssize_t result;
|
14805
|
+
VALUE vresult = Qnil;
|
14806
|
+
|
14807
|
+
if ((argc < 3) || (argc > 3)) {
|
14808
|
+
rb_raise(rb_eArgError, "wrong # of arguments(%d for 3)",argc); SWIG_fail;
|
14809
|
+
}
|
14810
|
+
res1 = SWIG_ConvertPtr(argv[0], &argp1,SWIGTYPE_p_pn_message_t, 0 | 0 );
|
14811
|
+
if (!SWIG_IsOK(res1)) {
|
14812
|
+
SWIG_exception_fail(SWIG_ArgError(res1), Ruby_Format_TypeError( "", "pn_message_t *","pn_message_send", 1, argv[0] ));
|
14813
|
+
}
|
14814
|
+
arg1 = (pn_message_t *)(argp1);
|
14815
|
+
res2 = SWIG_ConvertPtr(argv[1], &argp2,SWIGTYPE_p_pn_link_t, 0 | 0 );
|
14816
|
+
if (!SWIG_IsOK(res2)) {
|
14817
|
+
SWIG_exception_fail(SWIG_ArgError(res2), Ruby_Format_TypeError( "", "pn_link_t *","pn_message_send", 2, argv[1] ));
|
14818
|
+
}
|
14819
|
+
arg2 = (pn_link_t *)(argp2);
|
14820
|
+
res3 = SWIG_ConvertPtr(argv[2], &argp3,SWIGTYPE_p_pn_rwbytes_t, 0 | 0 );
|
14821
|
+
if (!SWIG_IsOK(res3)) {
|
14822
|
+
SWIG_exception_fail(SWIG_ArgError(res3), Ruby_Format_TypeError( "", "pn_rwbytes_t *","pn_message_send", 3, argv[2] ));
|
14823
|
+
}
|
14824
|
+
arg3 = (pn_rwbytes_t *)(argp3);
|
14825
|
+
result = (ssize_t)pn_message_send(arg1,arg2,arg3);
|
14826
|
+
vresult = SWIG_From_int((int)(result));
|
14827
|
+
return vresult;
|
14828
|
+
fail:
|
14829
|
+
return Qnil;
|
14830
|
+
}
|
14831
|
+
|
14832
|
+
|
14793
14833
|
SWIGINTERN VALUE
|
14794
14834
|
_wrap_pn_message_data(int argc, VALUE *argv, VALUE self) {
|
14795
14835
|
pn_message_t *arg1 = (pn_message_t *) 0 ;
|
@@ -23711,7 +23751,7 @@ SWIGEXPORT void Init_cproton(void) {
|
|
23711
23751
|
rb_define_module_function(mCproton, "pni_connection_driver", _wrap_pni_connection_driver, -1);
|
23712
23752
|
rb_define_const(mCproton, "PROTON_IMPORT_EXPORT_H", SWIG_From_int((int)(1)));
|
23713
23753
|
rb_define_const(mCproton, "PN_VERSION_MAJOR", SWIG_From_int((int)(0)));
|
23714
|
-
rb_define_const(mCproton, "PN_VERSION_MINOR", SWIG_From_int((int)(
|
23754
|
+
rb_define_const(mCproton, "PN_VERSION_MINOR", SWIG_From_int((int)(23)));
|
23715
23755
|
rb_define_const(mCproton, "PN_VERSION_POINT", SWIG_From_int((int)(0)));
|
23716
23756
|
rb_define_const(mCproton, "PROTON_TYPES_H", SWIG_From_int((int)(1)));
|
23717
23757
|
rb_define_const(mCproton, "PN_MILLIS_MAX", SWIG_From_unsigned_SS_int((unsigned int)((~0U))));
|
@@ -24221,6 +24261,7 @@ SWIGEXPORT void Init_cproton(void) {
|
|
24221
24261
|
rb_define_module_function(mCproton, "pn_message_properties", _wrap_pn_message_properties, -1);
|
24222
24262
|
rb_define_module_function(mCproton, "pn_message_body", _wrap_pn_message_body, -1);
|
24223
24263
|
rb_define_module_function(mCproton, "pn_message_decode", _wrap_pn_message_decode, -1);
|
24264
|
+
rb_define_module_function(mCproton, "pn_message_send", _wrap_pn_message_send, -1);
|
24224
24265
|
rb_define_module_function(mCproton, "pn_message_data", _wrap_pn_message_data, -1);
|
24225
24266
|
rb_define_const(mCproton, "PROTON_SASL_H", SWIG_From_int((int)(1)));
|
24226
24267
|
rb_define_const(mCproton, "PN_SASL_NONE", SWIG_From_int((int)(PN_SASL_NONE)));
|
data/lib/core/container.rb
CHANGED
@@ -35,8 +35,8 @@ module Qpid::Proton
|
|
35
35
|
include TimeCompare
|
36
36
|
|
37
37
|
# Error raised if the container is used after {#stop} has been called.
|
38
|
-
class StoppedError <
|
39
|
-
def initialize(
|
38
|
+
class StoppedError < Qpid::Proton::StoppedError
|
39
|
+
def initialize() super("container has been stopped"); end
|
40
40
|
end
|
41
41
|
|
42
42
|
# Create a new Container
|
@@ -53,7 +53,7 @@ module Qpid::Proton
|
|
53
53
|
# concurrently.
|
54
54
|
#
|
55
55
|
def initialize(*args)
|
56
|
-
@handler, @id
|
56
|
+
@handler, @id = nil
|
57
57
|
case args.size
|
58
58
|
when 2 then @handler, @id = args
|
59
59
|
when 1 then
|
@@ -66,19 +66,13 @@ module Qpid::Proton
|
|
66
66
|
@adapter = Handler::Adapter.adapt(@handler) || Handler::MessagingAdapter.new(nil)
|
67
67
|
@id = (@id || SecureRandom.uuid).freeze
|
68
68
|
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# - #run threads take work items from @work, process them, and rearm them for select
|
72
|
-
# - work items are: ConnectionTask, ListenTask, :start, :select, :schedule
|
73
|
-
# - nil on the @work queue makes a #run thread exit
|
74
|
-
|
69
|
+
# Threading and implementation notes: see comment on #run_one
|
75
70
|
@work = Queue.new
|
76
71
|
@work << :start
|
77
72
|
@work << :select
|
78
73
|
@wake = SelectWaker.new # Wakes #run thread in IO.select
|
79
74
|
@auto_stop = true # Stop when @active drops to 0
|
80
|
-
@
|
81
|
-
@schedule_working = false # True if :schedule is on the work queue
|
75
|
+
@work_queue = WorkQueue.new(self) # work scheduled by other threads for :select context
|
82
76
|
|
83
77
|
# Following instance variables protected by lock
|
84
78
|
@lock = Mutex.new
|
@@ -87,6 +81,7 @@ module Qpid::Proton
|
|
87
81
|
@running = 0 # Count of #run threads
|
88
82
|
@stopped = false # #stop called
|
89
83
|
@stop_err = nil # Optional error to pass to tasks, from #stop
|
84
|
+
@panic = nil # Exception caught in a run thread, to be raised by all run threads
|
90
85
|
end
|
91
86
|
|
92
87
|
# @return [MessagingHandler] The container-wide handler
|
@@ -95,6 +90,9 @@ module Qpid::Proton
|
|
95
90
|
# @return [String] unique identifier for this container
|
96
91
|
attr_reader :id
|
97
92
|
|
93
|
+
def to_s() "#<#{self.class} id=#{id.inspect}>"; end
|
94
|
+
def inspect() to_s; end
|
95
|
+
|
98
96
|
# Auto-stop flag.
|
99
97
|
#
|
100
98
|
# True (the default) means that the container will stop automatically, as if {#stop}
|
@@ -165,7 +163,7 @@ module Qpid::Proton
|
|
165
163
|
not_stopped
|
166
164
|
l = ListenTask.new(io, handler, self)
|
167
165
|
add(l)
|
168
|
-
l
|
166
|
+
l.listener
|
169
167
|
end
|
170
168
|
|
171
169
|
# Run the container: wait for IO activity, dispatch events to handlers.
|
@@ -198,12 +196,13 @@ module Qpid::Proton
|
|
198
196
|
while task = @work.pop
|
199
197
|
run_one(task, Time.now)
|
200
198
|
end
|
201
|
-
raise @panic if @panic
|
199
|
+
@lock.synchronize { raise @panic if @panic }
|
202
200
|
ensure
|
203
201
|
@lock.synchronize do
|
204
202
|
if (@running -= 1) > 0
|
205
203
|
work_wake nil # Signal the next thread
|
206
204
|
else
|
205
|
+
# This is the last thread, no need to do maybe_panic around this final handler call.
|
207
206
|
@adapter.on_container_stop(self) if @adapter.respond_to? :on_container_stop
|
208
207
|
end
|
209
208
|
end
|
@@ -217,15 +216,13 @@ module Qpid::Proton
|
|
217
216
|
# is finished.
|
218
217
|
#
|
219
218
|
# The container can no longer be used, using a stopped container raises
|
220
|
-
# {StoppedError}
|
221
|
-
# resume activity.
|
219
|
+
# {StoppedError}. Create a new container if you want to resume activity.
|
222
220
|
#
|
223
221
|
# @param error [Condition] Optional error condition passed to
|
224
222
|
# {MessagingHandler#on_transport_error} for each connection and
|
225
223
|
# {Listener::Handler::on_error} for each listener.
|
226
224
|
#
|
227
|
-
# @param panic [Exception] Optional exception
|
228
|
-
# to run()
|
225
|
+
# @param panic [Exception] Optional exception to raise from all calls to run()
|
229
226
|
#
|
230
227
|
def stop(error=nil, panic=nil)
|
231
228
|
@lock.synchronize do
|
@@ -239,25 +236,22 @@ module Qpid::Proton
|
|
239
236
|
# - no more select calls after next wakeup
|
240
237
|
# - once @active == 0, all threads will be stopped with nil
|
241
238
|
end
|
242
|
-
|
239
|
+
wake
|
243
240
|
end
|
244
241
|
|
245
|
-
#
|
246
|
-
#
|
247
|
-
#
|
248
|
-
#
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
@wake.wake
|
254
|
-
end
|
242
|
+
# Get the {WorkQueue} that can be used to schedule code to be run by the container.
|
243
|
+
#
|
244
|
+
# Note: to run code that affects a {Connection} or it's associated objects,
|
245
|
+
# use {Connection#work_queue}
|
246
|
+
def work_queue() @work_queue; end
|
247
|
+
|
248
|
+
# (see WorkQueue#schedule)
|
249
|
+
def schedule(at, &block) @work_queue.schedule(at, &block) end
|
255
250
|
|
256
251
|
private
|
257
252
|
|
258
253
|
def wake() @wake.wake; end
|
259
254
|
|
260
|
-
# Container driver applies options and adds container context to events
|
261
255
|
class ConnectionTask < Qpid::Proton::HandlerDriver
|
262
256
|
include TimeCompare
|
263
257
|
|
@@ -266,23 +260,23 @@ module Qpid::Proton
|
|
266
260
|
transport.set_server if server
|
267
261
|
transport.apply opts
|
268
262
|
connection.apply opts
|
269
|
-
@work_queue = WorkQueue.new
|
263
|
+
@work_queue = WorkQueue.new(container)
|
270
264
|
connection.instance_variable_set(:@work_queue, @work_queue)
|
271
265
|
end
|
272
|
-
def next_tick() earliest(super, @work_queue.
|
273
|
-
def process(now) @work_queue.
|
266
|
+
def next_tick() earliest(super, @work_queue.next_tick); end
|
267
|
+
def process(now) @work_queue.process(now); super(); end
|
274
268
|
|
275
269
|
def dispatch # Intercept dispatch to close work_queue
|
276
270
|
super
|
277
|
-
@work_queue.
|
271
|
+
@work_queue.close if read_closed? && write_closed?
|
278
272
|
end
|
279
273
|
end
|
280
274
|
|
281
275
|
class ListenTask < Listener
|
282
276
|
|
283
277
|
def initialize(io, handler, container)
|
284
|
-
|
285
|
-
@
|
278
|
+
@io, @handler = io, handler
|
279
|
+
@listener = Listener.new(io, container)
|
286
280
|
env = ENV['PN_TRACE_EVT']
|
287
281
|
if env && ["true", "1", "yes", "on"].include?(env.downcase)
|
288
282
|
@log_prefix = "[0x#{object_id.to_s(16)}](PN_LISTENER_"
|
@@ -292,28 +286,33 @@ module Qpid::Proton
|
|
292
286
|
dispatch(:on_open);
|
293
287
|
end
|
294
288
|
|
289
|
+
attr_reader :listener
|
290
|
+
def closing?() @listener.instance_variable_get(:@closing); end
|
291
|
+
def condition() @listener.instance_variable_get(:@condition); end
|
292
|
+
def closed?() @io.closed?; end
|
293
|
+
|
295
294
|
def process
|
296
|
-
return if
|
297
|
-
unless
|
295
|
+
return if closed?
|
296
|
+
unless closing?
|
298
297
|
begin
|
299
298
|
return @io.accept, dispatch(:on_accept)
|
300
299
|
rescue IO::WaitReadable, Errno::EINTR
|
301
|
-
rescue
|
302
|
-
close
|
300
|
+
rescue StandardError => e
|
301
|
+
@listener.close(e)
|
303
302
|
end
|
304
303
|
end
|
305
304
|
ensure
|
306
|
-
if
|
305
|
+
if closing?
|
307
306
|
@io.close rescue nil
|
308
|
-
@closed
|
309
|
-
dispatch(:on_error,
|
307
|
+
@listener.instance_variable_set(:@closed, true)
|
308
|
+
dispatch(:on_error, condition) if condition
|
310
309
|
dispatch(:on_close)
|
311
310
|
end
|
312
311
|
end
|
313
312
|
|
314
313
|
def can_read?() !finished?; end
|
315
314
|
def can_write?() false; end
|
316
|
-
def finished?()
|
315
|
+
def finished?() closed?; end
|
317
316
|
|
318
317
|
def dispatch(method, *args)
|
319
318
|
# TODO aconway 2017-11-27: better logging
|
@@ -322,6 +321,12 @@ module Qpid::Proton
|
|
322
321
|
end
|
323
322
|
|
324
323
|
def next_tick() nil; end
|
324
|
+
|
325
|
+
# Close listener and force immediate close of socket
|
326
|
+
def close(e=nil)
|
327
|
+
@listener.close(e)
|
328
|
+
@io.close rescue nil
|
329
|
+
end
|
325
330
|
end
|
326
331
|
|
327
332
|
# Selectable object that can be used to wake IO.select from another thread
|
@@ -338,14 +343,14 @@ module Qpid::Proton
|
|
338
343
|
@lock.synchronize do
|
339
344
|
return if @set # Don't write if already has data
|
340
345
|
@set = true
|
341
|
-
|
346
|
+
@wr.write_nonblock('x') rescue nil
|
342
347
|
end
|
343
348
|
end
|
344
349
|
|
345
350
|
def reset
|
346
351
|
@lock.synchronize do
|
347
352
|
return unless @set
|
348
|
-
|
353
|
+
@rd.read_nonblock(1) rescue nil
|
349
354
|
@set = false
|
350
355
|
end
|
351
356
|
end
|
@@ -357,49 +362,58 @@ module Qpid::Proton
|
|
357
362
|
end
|
358
363
|
|
359
364
|
# Handle a single item from the @work queue, this is the heart of the #run loop.
|
365
|
+
# Take one task from @work, process it, and rearm for select
|
366
|
+
# Tasks are: ConnectionTask, ListenTask, :start, :select
|
367
|
+
# - ConnectionTask/ListenTask have #can_read, #can_write, #next_tick to set up IO.select
|
368
|
+
# and #process to run handlers and process relevant work_queue
|
369
|
+
# - nil means exit from the #run thread exit (handled by #run)
|
370
|
+
# - :select does IO.select and processes Container#work_queue
|
360
371
|
def run_one(task, now)
|
361
372
|
case task
|
362
373
|
|
363
374
|
when :start
|
364
|
-
@adapter.on_container_start(self) if @adapter.respond_to? :on_container_start
|
375
|
+
maybe_panic { @adapter.on_container_start(self) } if @adapter.respond_to? :on_container_start
|
365
376
|
|
366
377
|
when :select
|
367
378
|
# Compute read/write select sets and minimum next_tick for select timeout
|
368
379
|
r, w = [@wake], []
|
369
|
-
next_tick = @
|
380
|
+
next_tick = @work_queue.next_tick
|
370
381
|
@lock.synchronize do
|
371
382
|
@selectable.each do |s|
|
372
|
-
r << s if s.
|
373
|
-
w << s if s.
|
383
|
+
r << s if s.can_read?
|
384
|
+
w << s if s.can_write?
|
374
385
|
next_tick = earliest(s.next_tick, next_tick)
|
375
386
|
end
|
376
387
|
end
|
377
388
|
|
378
389
|
timeout = ((next_tick > now) ? next_tick - now : 0) if next_tick
|
379
390
|
r, w = IO.select(r, w, nil, timeout)
|
380
|
-
now = Time.now unless timeout == 0
|
381
391
|
@wake.reset if r && r.delete(@wake)
|
392
|
+
now = Time.now unless timeout == 0 # Update now if we may have blocked
|
382
393
|
|
383
394
|
# selected is a Set to eliminate duplicates between r, w and next_tick due.
|
384
395
|
selected = Set.new
|
385
396
|
selected.merge(r) if r
|
386
397
|
selected.merge(w) if w
|
387
|
-
@lock.synchronize do
|
388
|
-
if @stopped
|
398
|
+
stopped = @lock.synchronize do
|
399
|
+
if @stopped # close everything
|
389
400
|
@selectable.each { |s| s.close @stop_err; @work << s }
|
390
401
|
@selectable.clear
|
402
|
+
@work_queue.close
|
391
403
|
@wake.close
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
@
|
396
|
-
@work << :schedule
|
404
|
+
else
|
405
|
+
@selectable -= selected # Remove already-selected tasks from @selectable
|
406
|
+
# Also select and remove items with next_tick before now
|
407
|
+
@selectable.delete_if { |s| before_eq(s.next_tick, now) and selected << s }
|
397
408
|
end
|
398
|
-
|
399
|
-
@selectable -= selected # Remove selected tasks from @selectable
|
409
|
+
@stopped
|
400
410
|
end
|
401
411
|
selected.each { |s| @work << s } # Queue up tasks needing #process
|
402
|
-
@
|
412
|
+
maybe_panic { @work_queue.process(now) } # Process current work queue items
|
413
|
+
@work_queue.clear if stopped
|
414
|
+
@lock.synchronize { check_stop_lh } if @work_queue.empty?
|
415
|
+
|
416
|
+
@work << :select unless stopped # Enable next select
|
403
417
|
|
404
418
|
when ConnectionTask then
|
405
419
|
maybe_panic { task.process now }
|
@@ -409,56 +423,7 @@ module Qpid::Proton
|
|
409
423
|
io, opts = maybe_panic { task.process }
|
410
424
|
add(connection_driver(io, opts, true)) if io
|
411
425
|
rearm task
|
412
|
-
|
413
|
-
when :schedule then
|
414
|
-
if maybe_panic { @schedule.process now }
|
415
|
-
@lock.synchronize { @active -= 1; check_stop_lh }
|
416
|
-
else
|
417
|
-
@lock.synchronize { @schedule_working = false }
|
418
|
-
end
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
def do_select
|
423
|
-
# Compute the sets to select for read and write, and the minimum next_tick for the timeout
|
424
|
-
r, w = [@wake], []
|
425
|
-
next_tick = nil
|
426
|
-
@lock.synchronize do
|
427
|
-
@selectable.each do |s|
|
428
|
-
r << s if s.can_read?
|
429
|
-
w << s if s.can_write?
|
430
|
-
next_tick = earliest(s.next_tick, next_tick)
|
431
|
-
end
|
432
426
|
end
|
433
|
-
next_tick = earliest(@schedule.next_tick, next_tick)
|
434
|
-
|
435
|
-
# Do the select and queue up all resulting work
|
436
|
-
now = Time.now
|
437
|
-
timeout = next_tick - now if next_tick
|
438
|
-
r, w = (timeout.nil? || timeout > 0) && IO.select(r, w, nil, timeout)
|
439
|
-
@wake.reset
|
440
|
-
selected = Set.new
|
441
|
-
@lock.synchronize do
|
442
|
-
if @stopped
|
443
|
-
@selectable.each { |s| s.close @stop_err; @work << s }
|
444
|
-
@wake.close
|
445
|
-
return
|
446
|
-
end
|
447
|
-
# Check if schedule has items due and is not already working
|
448
|
-
if !@schedule_working && before_eq(@schedule.next_tick, now)
|
449
|
-
@work << :schedule
|
450
|
-
@schedule_working = true
|
451
|
-
end
|
452
|
-
# Eliminate duplicates between r, w and next_tick due.
|
453
|
-
selected.merge(r) if r
|
454
|
-
selected.delete(@wake)
|
455
|
-
selected.merge(w) if w
|
456
|
-
@selectable -= selected
|
457
|
-
selected.merge(@selectable.select { |s| before_eq(s.next_tick, now) })
|
458
|
-
@selectable -= selected
|
459
|
-
end
|
460
|
-
selected.each { |s| @work << s } # Queue up tasks needing #process
|
461
|
-
@work << :select
|
462
427
|
end
|
463
428
|
|
464
429
|
# Rescue any exception raised by the block and stop the container.
|
@@ -510,7 +475,7 @@ module Qpid::Proton
|
|
510
475
|
end
|
511
476
|
|
512
477
|
def check_stop_lh
|
513
|
-
if @active.zero? && (@auto_stop || @stopped)
|
478
|
+
if @active.zero? && (@auto_stop || @stopped) && @work_queue.empty?
|
514
479
|
@stopped = true
|
515
480
|
work_wake nil # Signal threads to stop
|
516
481
|
true
|