qpid_proton 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|