zmachine 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +1 -0
- data/{echo_client.rb → examples/echo_client.rb} +0 -0
- data/{echo_server.rb → examples/echo_server.rb} +0 -0
- data/lib/zmachine.rb +3 -115
- data/lib/zmachine/acceptor.rb +1 -1
- data/lib/zmachine/channel.rb +38 -5
- data/lib/zmachine/connection.rb +57 -152
- data/lib/zmachine/connection_manager.rb +34 -25
- data/lib/zmachine/hashed_wheel.rb +6 -5
- data/lib/zmachine/jeromq-0.3.2-SNAPSHOT.jar +0 -0
- data/lib/zmachine/reactor.rb +9 -7
- data/lib/zmachine/tcp_channel.rb +13 -40
- data/lib/zmachine/timers.rb +15 -43
- data/lib/zmachine/zmq_channel.rb +52 -60
- data/spec/channel_spec.rb +178 -0
- data/spec/connection_spec.rb +36 -11
- data/spec/hashed_wheel_spec.rb +15 -15
- data/spec/support/echo_mock.rb +32 -0
- data/zmachine.gemspec +1 -1
- metadata +9 -9
- data/lib/zmachine/jeromq-0.3.0-SNAPSHOT.jar +0 -0
- data/spec/tcp_channel_spec.rb +0 -109
- data/spec/zmq_channel_spec.rb +0 -113
@@ -19,7 +19,7 @@ module ZMachine
|
|
19
19
|
|
20
20
|
def idle?
|
21
21
|
@new_connections.size == 0 and
|
22
|
-
@zmq_connections.none? {|c| c.channel.
|
22
|
+
@zmq_connections.none? {|c| c.channel.can_recv? } # see comment in #process
|
23
23
|
end
|
24
24
|
|
25
25
|
def shutdown
|
@@ -30,18 +30,17 @@ module ZMachine
|
|
30
30
|
|
31
31
|
def bind(address, port_or_type, handler, *args, &block)
|
32
32
|
ZMachine.logger.debug("zmachine:connection_manager:#{__method__}", address: address, port_or_type: port_or_type) if ZMachine.debug
|
33
|
-
connection = build_connection(handler, *args
|
34
|
-
connection.bind(address, port_or_type)
|
33
|
+
connection = build_connection(handler, *args)
|
34
|
+
connection.bind(address, port_or_type, &block)
|
35
35
|
@new_connections << connection
|
36
36
|
connection
|
37
37
|
end
|
38
38
|
|
39
39
|
def connect(address, port_or_type, handler, *args, &block)
|
40
40
|
ZMachine.logger.debug("zmachine:connection_manager:#{__method__}", address: address, port_or_type: port_or_type) if ZMachine.debug
|
41
|
-
connection = build_connection(handler, *args
|
42
|
-
connection.connect(address, port_or_type)
|
41
|
+
connection = build_connection(handler, *args)
|
42
|
+
connection.connect(address, port_or_type, &block)
|
43
43
|
@new_connections << connection
|
44
|
-
yield connection if block_given?
|
45
44
|
connection
|
46
45
|
rescue java.nio.channels.UnresolvedAddressException
|
47
46
|
raise ZMachine::ConnectionError.new('unable to resolve server address')
|
@@ -55,26 +54,30 @@ module ZMachine
|
|
55
54
|
process_connection(it.next.attachment)
|
56
55
|
it.remove
|
57
56
|
end
|
58
|
-
# super ugly, but ZMQ only triggers the FD if and only if you
|
59
|
-
# every message from the socket. under load however
|
60
|
-
# new messages in the mailbox between last
|
61
|
-
# causes the FD never to be
|
62
|
-
#
|
57
|
+
# super ugly, but ZMQ only triggers the FD if and only if you
|
58
|
+
# have read every message from the socket. under load however
|
59
|
+
# there will always be new messages in the mailbox between last
|
60
|
+
# recv and next select, which causes the FD never to be
|
61
|
+
# triggered again.
|
62
|
+
# the only mitigation strategy i came up with is iterating over all
|
63
|
+
# channels. performance impact shouldn't be too huge, since ZMQ takes
|
64
|
+
# care of all the multiplexing and we only have a small amount of ZMQ
|
65
|
+
# connections in the reactor
|
63
66
|
@zmq_connections.each do |connection|
|
64
|
-
connection.readable! if connection.channel.
|
67
|
+
connection.readable! if connection.channel.can_recv?
|
65
68
|
end
|
66
69
|
end
|
67
70
|
|
68
71
|
def process_connection(connection)
|
69
72
|
new_connection = connection.process_events
|
70
73
|
@new_connections << new_connection if new_connection
|
71
|
-
rescue IOException
|
72
|
-
close_connection(connection)
|
74
|
+
rescue IOException => e
|
75
|
+
close_connection(connection, e)
|
73
76
|
end
|
74
77
|
|
75
|
-
def close_connection(connection)
|
76
|
-
ZMachine.logger.debug("zmachine:connection_manager:#{__method__}", connection: connection) if ZMachine.debug
|
77
|
-
@unbound_connections << connection
|
78
|
+
def close_connection(connection, reason = nil)
|
79
|
+
ZMachine.logger.debug("zmachine:connection_manager:#{__method__}", connection: connection, reason: reason.inspect) if ZMachine.debug
|
80
|
+
@unbound_connections << [connection, reason]
|
78
81
|
end
|
79
82
|
|
80
83
|
def add_new_connections
|
@@ -83,10 +86,12 @@ module ZMachine
|
|
83
86
|
begin
|
84
87
|
connection.register(@selector)
|
85
88
|
@connections << connection
|
86
|
-
|
89
|
+
if connection.channel.is_a?(ZMQChannel)
|
90
|
+
@zmq_connections << connection
|
91
|
+
connection.connection_completed
|
92
|
+
end
|
87
93
|
rescue ClosedChannelException => e
|
88
|
-
|
89
|
-
@unbound_connections << connection
|
94
|
+
@unbound_connections << [connection, e]
|
90
95
|
end
|
91
96
|
end
|
92
97
|
@new_connections.clear
|
@@ -101,7 +106,11 @@ module ZMachine
|
|
101
106
|
begin
|
102
107
|
@connections.delete(connection)
|
103
108
|
@zmq_connections.delete(connection)
|
104
|
-
connection.unbind
|
109
|
+
if connection.method(:unbind).arity != 0
|
110
|
+
connection.unbind(reason)
|
111
|
+
else
|
112
|
+
connection.unbind
|
113
|
+
end
|
105
114
|
connection.close
|
106
115
|
rescue Exception => e
|
107
116
|
ZMachine.logger.exception(e, "failed to unbind connection") if ZMachine.debug
|
@@ -112,16 +121,16 @@ module ZMachine
|
|
112
121
|
|
113
122
|
private
|
114
123
|
|
115
|
-
def build_connection(handler, *args
|
124
|
+
def build_connection(handler, *args)
|
116
125
|
if handler and handler.is_a?(Class)
|
117
|
-
handler.new(*args
|
126
|
+
handler.new(*args)
|
118
127
|
elsif handler and handler.is_a?(Connection)
|
119
128
|
# already initialized connection on reconnect
|
120
129
|
handler
|
121
130
|
elsif handler
|
122
|
-
connection_from_module(handler).new(*args
|
131
|
+
connection_from_module(handler).new(*args)
|
123
132
|
else
|
124
|
-
Connection.new(*args
|
133
|
+
Connection.new(*args)
|
125
134
|
end
|
126
135
|
end
|
127
136
|
|
@@ -27,13 +27,13 @@ module ZMachine
|
|
27
27
|
|
28
28
|
def initialize(number_of_slots, tick_length, start_time = System.nano_time)
|
29
29
|
@slots = Array.new(number_of_slots) { [] }
|
30
|
-
@tick_length = tick_length *
|
30
|
+
@tick_length = tick_length * 1_000_000_000
|
31
31
|
@last = start_time
|
32
32
|
@current_tick = 0
|
33
33
|
end
|
34
34
|
|
35
35
|
def add(timeout, &block)
|
36
|
-
timeout *=
|
36
|
+
timeout *= 1_000_000_000 # s to ns
|
37
37
|
ticks = timeout / @tick_length
|
38
38
|
slot = (@current_tick + ticks) % @slots.length
|
39
39
|
HashedWheelTimeout.new(System.nano_time + timeout, &block).tap do |hwt|
|
@@ -41,14 +41,15 @@ module ZMachine
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def reset(time =
|
44
|
+
def reset(time = nil)
|
45
45
|
@slots = Array.new(@slots.length) { [] }
|
46
46
|
@current_tick = 0
|
47
|
-
@last = time
|
47
|
+
@last = time || System.nano_time
|
48
48
|
end
|
49
49
|
|
50
50
|
# returns all timeouts
|
51
|
-
def advance(now =
|
51
|
+
def advance(now = nil)
|
52
|
+
now ||= System.nano_time
|
52
53
|
passed_ticks = (now - @last) / @tick_length
|
53
54
|
result = []
|
54
55
|
begin
|
Binary file
|
data/lib/zmachine/reactor.rb
CHANGED
@@ -40,7 +40,7 @@ module ZMachine
|
|
40
40
|
@next_tick_queue = ConcurrentLinkedQueue.new
|
41
41
|
@running = false
|
42
42
|
@shutdown_hooks = []
|
43
|
-
@wheel = HashedWheel.new(512,
|
43
|
+
@wheel = HashedWheel.new(512, 0.01)
|
44
44
|
end
|
45
45
|
|
46
46
|
def add_shutdown_hook(&block)
|
@@ -53,7 +53,7 @@ module ZMachine
|
|
53
53
|
callback = args.shift || block
|
54
54
|
ZMachine.logger.debug("zmachine:reactor:#{__method__}", interval: interval, callback: callback) if ZMachine.debug
|
55
55
|
return unless callback
|
56
|
-
@wheel.add(
|
56
|
+
@wheel.add(interval, &callback)
|
57
57
|
end
|
58
58
|
|
59
59
|
def bind(server, port_or_type=nil, handler=nil, *args, &block)
|
@@ -62,8 +62,9 @@ module ZMachine
|
|
62
62
|
@connection_manager.bind(server, port_or_type, handler, *args, &block)
|
63
63
|
end
|
64
64
|
|
65
|
-
def close_connection(connection)
|
66
|
-
@connection_manager
|
65
|
+
def close_connection(connection, reason = nil)
|
66
|
+
return true unless @connection_manager
|
67
|
+
@connection_manager.close_connection(connection, reason)
|
67
68
|
end
|
68
69
|
|
69
70
|
def connect(server, port_or_type=nil, handler=nil, *args, &block)
|
@@ -129,9 +130,9 @@ module ZMachine
|
|
129
130
|
def run_reactor
|
130
131
|
ZMachine.logger.debug("zmachine:reactor:#{__method__}") if ZMachine.debug
|
131
132
|
run_deferred_callbacks
|
132
|
-
|
133
|
+
return unless @run_reactor
|
133
134
|
run_timers
|
134
|
-
|
135
|
+
return unless @run_reactor
|
135
136
|
@connection_manager.cleanup
|
136
137
|
if @connection_manager.idle?
|
137
138
|
ZMachine.logger.debug("zmachine:reactor:#{__method__}", select: @heartbeat_interval) if ZMachine.debug
|
@@ -149,6 +150,7 @@ module ZMachine
|
|
149
150
|
|
150
151
|
def stop_event_loop
|
151
152
|
@run_reactor = false
|
153
|
+
@connection_manager.shutdown
|
152
154
|
wakeup
|
153
155
|
end
|
154
156
|
|
@@ -173,7 +175,7 @@ module ZMachine
|
|
173
175
|
def run_timers
|
174
176
|
ZMachine.logger.debug("zmachine:reactor:#{__method__}") if ZMachine.debug
|
175
177
|
@wheel.advance.each do |timeout|
|
176
|
-
ZMachine.logger.
|
178
|
+
ZMachine.logger.info("zmachine:reactor:#{__method__}", callback: timeout.callback) if ZMachine.debug
|
177
179
|
timeout.callback.call
|
178
180
|
end
|
179
181
|
end
|
data/lib/zmachine/tcp_channel.rb
CHANGED
@@ -13,6 +13,7 @@ module ZMachine
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def bind(address, port)
|
16
|
+
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
|
16
17
|
address = InetSocketAddress.new(address, port)
|
17
18
|
@socket = ServerSocketChannel.open
|
18
19
|
@socket.configure_blocking(false)
|
@@ -20,10 +21,11 @@ module ZMachine
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def bound?
|
23
|
-
@socket.is_a?(ServerSocketChannel)
|
24
|
+
@socket.is_a?(ServerSocketChannel) && @socket.bound?
|
24
25
|
end
|
25
26
|
|
26
27
|
def accept
|
28
|
+
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
|
27
29
|
client_socket = @socket.accept
|
28
30
|
return unless client_socket
|
29
31
|
client_socket.configure_blocking(false)
|
@@ -33,6 +35,7 @@ module ZMachine
|
|
33
35
|
end
|
34
36
|
|
35
37
|
def connect(address, port)
|
38
|
+
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
|
36
39
|
address = InetSocketAddress.new(address, port)
|
37
40
|
@socket = SocketChannel.open
|
38
41
|
@socket.configure_blocking(false)
|
@@ -51,9 +54,9 @@ module ZMachine
|
|
51
54
|
end
|
52
55
|
|
53
56
|
def finish_connecting
|
57
|
+
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
|
54
58
|
return unless connection_pending?
|
55
|
-
@socket.finish_connect
|
56
|
-
return true
|
59
|
+
@socket.finish_connect
|
57
60
|
end
|
58
61
|
|
59
62
|
def connected?
|
@@ -61,50 +64,20 @@ module ZMachine
|
|
61
64
|
end
|
62
65
|
|
63
66
|
def read_inbound_data
|
67
|
+
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
|
64
68
|
buffer = @inbound_buffer
|
65
69
|
buffer.clear
|
66
70
|
raise IOException.new("EOF") if @socket.read(buffer) == -1
|
67
71
|
buffer.flip
|
68
72
|
return if buffer.limit == 0
|
69
|
-
|
73
|
+
data = buffer.array[buffer.position...buffer.limit]
|
74
|
+
data = String.from_java_bytes(data) unless @raw
|
75
|
+
data
|
70
76
|
end
|
71
77
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
-
data = data.to_java_bytes if data.is_a?(String) # EM compat
|
76
|
-
buffer = ByteBuffer.wrap(data)
|
77
|
-
if buffer.has_remaining
|
78
|
-
@outbound_queue << buffer
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def write_outbound_data
|
83
|
-
while can_send?
|
84
|
-
buffer = @outbound_queue.first
|
85
|
-
@socket.write(buffer) if buffer.has_remaining
|
86
|
-
# Did we consume the whole outbound buffer? If yes,
|
87
|
-
# pop it off and keep looping. If no, the outbound network
|
88
|
-
# buffers are full, so break out of here.
|
89
|
-
if buffer.remaining == 0
|
90
|
-
@outbound_queue.shift
|
91
|
-
else
|
92
|
-
break
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
if can_send?
|
97
|
-
# network buffers are full
|
98
|
-
return false
|
99
|
-
end
|
100
|
-
|
101
|
-
close if @close_scheduled
|
102
|
-
return true
|
103
|
-
end
|
104
|
-
|
105
|
-
def close(after_writing = false)
|
106
|
-
super
|
107
|
-
@socket.close unless can_send?
|
78
|
+
def close!
|
79
|
+
ZMachine.logger.debug("zmachine:tcp_channel:#{__method__}", channel: self) if ZMachine.debug
|
80
|
+
@socket.close
|
108
81
|
end
|
109
82
|
|
110
83
|
def closed?
|
data/lib/zmachine/timers.rb
CHANGED
@@ -1,61 +1,33 @@
|
|
1
1
|
module ZMachine
|
2
|
-
# Creates a one-time timer
|
3
|
-
#
|
4
|
-
# timer = ZMachine::Timer.new(5) do
|
5
|
-
# # this will never fire because we cancel it
|
6
|
-
# end
|
7
|
-
# timer.cancel
|
8
|
-
#
|
9
2
|
class Timer
|
10
|
-
# Create a new timer that fires after a given number of seconds
|
11
|
-
def initialize(interval, callback=nil, &block)
|
12
|
-
@signature = ZMachine.add_timer(interval, callback || block)
|
13
|
-
end
|
14
3
|
|
15
|
-
|
16
|
-
def cancel
|
17
|
-
ZMachine.cancel_timer(@signature)
|
18
|
-
end
|
19
|
-
end
|
4
|
+
attr_accessor :interval
|
20
5
|
|
21
|
-
# Creates a periodic timer
|
22
|
-
#
|
23
|
-
# @example
|
24
|
-
# n = 0
|
25
|
-
# timer = ZMachine::PeriodicTimer.new(5) do
|
26
|
-
# puts "the time is #{Time.now}"
|
27
|
-
# timer.cancel if (n+=1) > 5
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
class PeriodicTimer
|
31
|
-
# Create a new periodic timer that executes every interval seconds
|
32
6
|
def initialize(interval, callback=nil, &block)
|
33
7
|
@interval = interval
|
34
|
-
@
|
35
|
-
@cancelled = false
|
36
|
-
@work = method(:fire)
|
8
|
+
@callback = callback || block
|
37
9
|
schedule
|
38
10
|
end
|
39
11
|
|
40
|
-
|
41
|
-
|
42
|
-
@cancelled = true
|
12
|
+
def schedule
|
13
|
+
@timer = ZMachine.add_timer(@interval, method(:fire))
|
43
14
|
end
|
44
15
|
|
45
|
-
|
46
|
-
|
16
|
+
def fire
|
17
|
+
@callback.call
|
18
|
+
end
|
47
19
|
|
48
|
-
|
49
|
-
|
50
|
-
ZMachine.add_timer(@interval, @work)
|
20
|
+
def cancel
|
21
|
+
@timer.cancel
|
51
22
|
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class PeriodicTimer < Timer
|
52
26
|
|
53
|
-
# @private
|
54
27
|
def fire
|
55
|
-
|
56
|
-
|
57
|
-
schedule
|
58
|
-
end
|
28
|
+
super
|
29
|
+
schedule
|
59
30
|
end
|
31
|
+
|
60
32
|
end
|
61
33
|
end
|
data/lib/zmachine/zmq_channel.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require 'zmachine/jeromq-0.3.
|
1
|
+
require 'zmachine/jeromq-0.3.2-SNAPSHOT.jar'
|
2
|
+
java_import org.zeromq.ZMsg
|
2
3
|
java_import org.zeromq.ZMQ
|
3
4
|
java_import org.zeromq.ZMQException
|
4
5
|
|
@@ -9,35 +10,39 @@ class ZMQ
|
|
9
10
|
class Socket
|
10
11
|
# for performance reason we alias the method here (otherwise it uses reflections all the time!)
|
11
12
|
# super ugly, since we need to dynamically infer the java class of byte[]
|
13
|
+
java_alias :send_byte_buffer, :sendByteBuffer, [Java::JavaNio::ByteBuffer.java_class, Java::int]
|
12
14
|
java_alias :send_byte_array, :send, [[].to_java(:byte).java_class, Java::int]
|
13
15
|
java_alias :recv_byte_array, :recv, [Java::int]
|
16
|
+
|
17
|
+
def write(buffer)
|
18
|
+
bytes = send_byte_buffer(buffer, 0)
|
19
|
+
buffer.position(buffer.position + bytes)
|
20
|
+
end
|
14
21
|
end
|
15
22
|
end
|
16
23
|
|
17
24
|
module ZMachine
|
18
25
|
class ZMQChannel < Channel
|
19
26
|
|
20
|
-
|
21
|
-
super()
|
22
|
-
@socket = ZMachine.context.create_socket(type)
|
23
|
-
@bound = false
|
24
|
-
@connected = false
|
25
|
-
@closed = false
|
26
|
-
end
|
27
|
+
extend Forwardable
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
def
|
32
|
-
|
29
|
+
def_delegator :@socket, :identity
|
30
|
+
def_delegator :@socket, :identity=
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
super
|
34
|
+
@raw = true
|
33
35
|
end
|
34
36
|
|
35
37
|
def selectable_fd
|
36
38
|
@socket.fd
|
37
39
|
end
|
38
40
|
|
39
|
-
def bind(address,
|
41
|
+
def bind(address, type)
|
42
|
+
ZMachine.logger.debug("zmachine:zmq_channel:#{__method__}", channel: self) if ZMachine.debug
|
40
43
|
@bound = true
|
44
|
+
@connected = true
|
45
|
+
@socket = ZMachine.context.create_socket(type)
|
41
46
|
@socket.bind(address)
|
42
47
|
end
|
43
48
|
|
@@ -45,13 +50,26 @@ module ZMachine
|
|
45
50
|
@bound
|
46
51
|
end
|
47
52
|
|
48
|
-
def
|
49
|
-
|
53
|
+
def accept
|
54
|
+
ZMachine.logger.debug("zmachine:zmq_channel:#{__method__}", channel: self) if ZMachine.debug
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def connect(address, type)
|
59
|
+
ZMachine.logger.debug("zmachine:zmq_channel:#{__method__}", channel: self) if ZMachine.debug
|
60
|
+
@connection_pending = true
|
61
|
+
@socket = ZMachine.context.create_socket(type)
|
50
62
|
@socket.connect(address)
|
51
63
|
end
|
52
64
|
|
53
65
|
def connection_pending?
|
54
|
-
|
66
|
+
@connection_pending
|
67
|
+
end
|
68
|
+
|
69
|
+
def finish_connecting
|
70
|
+
ZMachine.logger.debug("zmachine:zmq_channel:#{__method__}", channel: self) if ZMachine.debug
|
71
|
+
return unless connection_pending?
|
72
|
+
@connected = true
|
55
73
|
end
|
56
74
|
|
57
75
|
def connected?
|
@@ -59,71 +77,40 @@ module ZMachine
|
|
59
77
|
end
|
60
78
|
|
61
79
|
def read_inbound_data
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
80
|
+
ZMachine.logger.debug("zmachine:zmq_channel:#{__method__}", channel: self) if ZMachine.debug
|
81
|
+
data = ZMsg.recv_msg(@socket)
|
82
|
+
data = String.from_java_bytes(data.first.data) unless @raw
|
66
83
|
data
|
67
84
|
end
|
68
85
|
|
69
|
-
def send_data(data)
|
70
|
-
parts, last = data[0..-2], data.last
|
71
|
-
parts.each do |part|
|
72
|
-
@socket.send_byte_array(part, ZMQ::SNDMORE | ZMQ::DONTWAIT)
|
73
|
-
end
|
74
|
-
@socket.send_byte_array(last, ZMQ::DONTWAIT)
|
75
|
-
rescue ZMQException
|
76
|
-
@outbound_queue << data
|
77
|
-
end
|
78
|
-
|
79
|
-
# to get around iterating over an array in #send_data we pass message parts
|
80
|
-
# as arguments
|
81
86
|
def send1(a)
|
82
87
|
@socket.send_byte_array(a, ZMQ::DONTWAIT)
|
83
88
|
end
|
84
89
|
|
85
90
|
def send2(a, b)
|
86
|
-
@socket.send_byte_array(a, ZMQ::SNDMORE | ZMQ::DONTWAIT)
|
91
|
+
@socket.send_byte_array(a, ZMQ::SNDMORE | ZMQ::DONTWAIT) and
|
87
92
|
@socket.send_byte_array(b, ZMQ::DONTWAIT)
|
88
93
|
end
|
89
94
|
|
90
95
|
def send3(a, b, c)
|
91
|
-
@socket.send_byte_array(a, ZMQ::SNDMORE | ZMQ::DONTWAIT)
|
92
|
-
@socket.send_byte_array(b, ZMQ::SNDMORE | ZMQ::DONTWAIT)
|
96
|
+
@socket.send_byte_array(a, ZMQ::SNDMORE | ZMQ::DONTWAIT) and
|
97
|
+
@socket.send_byte_array(b, ZMQ::SNDMORE | ZMQ::DONTWAIT) and
|
93
98
|
@socket.send_byte_array(c, ZMQ::DONTWAIT)
|
94
99
|
end
|
95
100
|
|
96
101
|
def send4(a, b, c, d)
|
97
|
-
@socket.send_byte_array(a, ZMQ::SNDMORE | ZMQ::DONTWAIT)
|
98
|
-
@socket.send_byte_array(b, ZMQ::SNDMORE | ZMQ::DONTWAIT)
|
99
|
-
@socket.send_byte_array(c, ZMQ::SNDMORE | ZMQ::DONTWAIT)
|
102
|
+
@socket.send_byte_array(a, ZMQ::SNDMORE | ZMQ::DONTWAIT) and
|
103
|
+
@socket.send_byte_array(b, ZMQ::SNDMORE | ZMQ::DONTWAIT) and
|
104
|
+
@socket.send_byte_array(c, ZMQ::SNDMORE | ZMQ::DONTWAIT) and
|
100
105
|
@socket.send_byte_array(d, ZMQ::DONTWAIT)
|
101
106
|
end
|
102
107
|
|
103
|
-
def
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
|
-
def can_send?
|
108
|
-
super and (@socket.events & ZMQ::Poller::POLLOUT == ZMQ::Poller::POLLOUT)
|
109
|
-
end
|
110
|
-
|
111
|
-
def write_outbound_data
|
112
|
-
while can_send?
|
113
|
-
data = @outbound_queue.shift
|
114
|
-
send_data(data)
|
115
|
-
end
|
116
|
-
|
117
|
-
close if @close_scheduled
|
118
|
-
return true
|
119
|
-
end
|
120
|
-
|
121
|
-
def close(after_writing = false)
|
122
|
-
super
|
108
|
+
def close!
|
109
|
+
ZMachine.logger.debug("zmachine:zmq_channel:#{__method__}", channel: self) if ZMachine.debug
|
123
110
|
@closed = true
|
124
111
|
@connected = false
|
125
112
|
@bound = false
|
126
|
-
ZMachine.context.destroySocket(@socket)
|
113
|
+
ZMachine.context.destroySocket(@socket)
|
127
114
|
end
|
128
115
|
|
129
116
|
def closed?
|
@@ -134,5 +121,10 @@ module ZMachine
|
|
134
121
|
raise RuntimeError.new("ZMQChannel has no peer")
|
135
122
|
end
|
136
123
|
|
124
|
+
# see comment in ConnectionManager#process
|
125
|
+
def can_recv?
|
126
|
+
@socket.events & ZMQ::Poller::POLLIN == ZMQ::Poller::POLLIN
|
127
|
+
end
|
128
|
+
|
137
129
|
end
|
138
130
|
end
|