ffi-rzmq 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.bnsignore +22 -0
- data/History.txt +36 -0
- data/README.rdoc +18 -22
- data/Rakefile +22 -5
- data/examples/local_lat_poll.rb +54 -0
- data/ffi-rzmq.gemspec +9 -9
- data/lib/ffi-rzmq/context.rb +1 -1
- data/lib/ffi-rzmq/poll.rb +7 -1
- data/lib/ffi-rzmq/socket.rb +75 -21
- data/lib/ffi-rzmq/wrapper.rb +8 -6
- data/lib/ffi-rzmq/zmq.rb +27 -1
- data/spec/context_spec.rb +7 -34
- data/spec/pushpull_spec.rb +16 -19
- data/spec/reqrep_spec.rb +5 -0
- data/spec/socket_spec.rb +249 -109
- data/spec/spec_helper.rb +3 -13
- data/version.txt +1 -1
- metadata +10 -10
- data/.gitignore +0 -2
- data/examples/xreqxrep_poll.rb +0 -82
data/.bnsignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# The list of files that should be ignored by Mr Bones.
|
2
|
+
# Lines that start with '#' are comments.
|
3
|
+
#
|
4
|
+
# A .gitignore file can be used instead by setting it as the ignore
|
5
|
+
# file in your Rakefile:
|
6
|
+
#
|
7
|
+
# Bones {
|
8
|
+
# ignore_file '.gitignore'
|
9
|
+
# }
|
10
|
+
#
|
11
|
+
# For a project with a C extension, the following would be a good set of
|
12
|
+
# exclude patterns (uncomment them if you want to use them):
|
13
|
+
# *.[oa]
|
14
|
+
# *~
|
15
|
+
announcement.txt
|
16
|
+
coverage
|
17
|
+
doc
|
18
|
+
pkg
|
19
|
+
*.tmproj
|
20
|
+
*.gem
|
21
|
+
*.rbc
|
22
|
+
*.html
|
data/History.txt
CHANGED
@@ -1,3 +1,39 @@
|
|
1
|
+
== 0.7.0 / 20101222
|
2
|
+
* Improved performance of calls to Socket#getsockopt. There are usually
|
3
|
+
a lot of calls passing RCVMORE, so we now cache those buffers instead
|
4
|
+
of reallocating them every time.
|
5
|
+
|
6
|
+
* Updated the docs on Poller#poll to warn about a possible busy-loop
|
7
|
+
condition.
|
8
|
+
|
9
|
+
* Fixed some more specs to conform with the 0mq 2.1 requirement that
|
10
|
+
all sockets must be closed explicitly otherwise the program may
|
11
|
+
hang on exit.
|
12
|
+
|
13
|
+
== 0.6.1 / 20101127
|
14
|
+
* API Change!
|
15
|
+
Moved the #version method from the Util module and made it a class
|
16
|
+
method instead. Invoke as ZMQ::Util.version. Used for conditionally
|
17
|
+
enabling certain features based upon the 0mq version that is loaded.
|
18
|
+
|
19
|
+
* Preliminary support for the Windows platform. Patches supplied
|
20
|
+
by arvicco.
|
21
|
+
|
22
|
+
* Added support for FD and EVENTS socket options. These were added
|
23
|
+
in 0mq 2.1.0. Patches + specs supplied by andrewvc.
|
24
|
+
|
25
|
+
* Added support for LINGER, RECONNECT_IVL, BACKLOG and
|
26
|
+
RECOVERY_IVL_MSEC socket options.
|
27
|
+
|
28
|
+
* Conditionally re-enable the socket finalizer when we are running
|
29
|
+
with 0mq 2.1.0 or later.
|
30
|
+
|
31
|
+
* Drop support for MRI 1.8.x since the 'ffi' gem has dropped it as a
|
32
|
+
supported Ruby runtime with its 1.0 release. No action is taken to
|
33
|
+
prevent running with MRI 1.8.x but it won't be supported.
|
34
|
+
|
35
|
+
* Misc. spec fixes. Need more specs!
|
36
|
+
|
1
37
|
== 0.6.0 / 20100911
|
2
38
|
* API Change! Modified ZMQ::Message by removing automatic memory
|
3
39
|
management. While doing some performance tests I saw that
|
data/README.rdoc
CHANGED
@@ -7,10 +7,10 @@ ffi-rzmq
|
|
7
7
|
This gem wraps the ZeroMQ networking library using the ruby FFI (foreign
|
8
8
|
function interface). It's a pure ruby wrapper so this gem can be loaded
|
9
9
|
and run by any ruby runtime that supports FFI. That's all of them:
|
10
|
-
MRI 1.
|
10
|
+
MRI 1.9.x, Rubinius and JRuby.
|
11
11
|
|
12
12
|
The impetus behind this library was to provide support for ZeroMQ in
|
13
|
-
JRuby which has native threads. Unlike MRI,
|
13
|
+
JRuby which has native threads. Unlike MRI, IronRuby and
|
14
14
|
Rubinius which all have a GIL, JRuby allows for threaded access to ruby
|
15
15
|
code from outside extensions. ZeroMQ is heavily threaded, so until the
|
16
16
|
other runtimes remove their GIL, JRuby will likely be the best
|
@@ -28,18 +28,9 @@ This gem needs more tests. I'm certain there are a
|
|
28
28
|
ton of bugs, so please open issues for them here or fork this project,
|
29
29
|
fix them, and send me a pull request.
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
Ruby FFI project) so tread carefully.
|
35
|
-
|
36
|
-
Running this gem with MRI 1.9.x may also exhibit some hangs particularly at
|
37
|
-
shutdown. This is due to a signaling interaction between the 0mq library
|
38
|
-
and MRI. If the 0mq library is blocked on a call and the program receives
|
39
|
-
a signal (e.g. SIGINT), the Ruby runtime has no opportunity to run its signal
|
40
|
-
handler and process it. The 2.1.x branch of 0mq resolves this problem by
|
41
|
-
interrupting the blocking call and returning EINTR. The 2.0.x branch will
|
42
|
-
not get this fix because the API change breaks backward compatibility.
|
31
|
+
The 'ffi' gem has dropped support for MRI 1.8.x. Since this project relies
|
32
|
+
on that gem to load and run this code, then this project also no longer
|
33
|
+
supports MRI 1.8.x.
|
43
34
|
|
44
35
|
All features are implemented with the exception of the 0mq devices
|
45
36
|
(forwarder, queue, streamer). For implementations of these devices, see
|
@@ -104,10 +95,18 @@ Server code:
|
|
104
95
|
msg = s.recv_string 0
|
105
96
|
raise "Message size doesn't match, expected [#{message_size}] but received [#{msg.size}]" if message_size != msg.size
|
106
97
|
end
|
98
|
+
|
99
|
+
== Better Examples
|
100
|
+
|
101
|
+
I highly recommend visiting the Learn Ruby 0mq project for a bunch of good code examples.
|
102
|
+
|
103
|
+
http://github.com/andrewvc/learn-ruby-zeromq
|
104
|
+
|
105
|
+
|
107
106
|
|
108
107
|
== REQUIREMENTS:
|
109
108
|
|
110
|
-
* 0mq 2.0.
|
109
|
+
* 0mq 2.0.10 or 2.1+
|
111
110
|
|
112
111
|
The ZeroMQ library must be installed on your system in a well-known location
|
113
112
|
like /usr/local/lib. This is the default for new ZeroMQ installs.
|
@@ -115,15 +114,12 @@ like /usr/local/lib. This is the default for new ZeroMQ installs.
|
|
115
114
|
Future releases may include the library as a C extension built at
|
116
115
|
time of installation.
|
117
116
|
|
118
|
-
* ffi (
|
117
|
+
* ffi (>= 1.0.0)
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
Code and installation instructions can be found on github:
|
119
|
+
This is a requirement for MRI only. Both Rubinius and JRuby have FFI support built
|
120
|
+
in as a standard component. Do *not* run this gem under MRI with an old 'ffi' gem.
|
121
|
+
It will crash randomly and you will be sad.
|
125
122
|
|
126
|
-
http://github.com/ffi/ffi
|
127
123
|
|
128
124
|
== INSTALL:
|
129
125
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
begin
|
3
2
|
require 'bones'
|
4
3
|
rescue LoadError
|
@@ -8,12 +7,30 @@ end
|
|
8
7
|
task :default => 'test:run'
|
9
8
|
task 'gem:release' => 'test:run'
|
10
9
|
|
10
|
+
namespace :win do
|
11
|
+
|
12
|
+
desc 'Build and install gem under Windows. Mr Bones just has to break things using tar.'
|
13
|
+
task :install do
|
14
|
+
PKG_PATH = File.join(File.dirname(__FILE__), 'pkg')
|
15
|
+
NAME = File.basename(File.dirname(__FILE__))
|
16
|
+
rm_rf PKG_PATH
|
17
|
+
system "gem build #{NAME}.gemspec"
|
18
|
+
mkdir_p PKG_PATH
|
19
|
+
mv "#{NAME}-0.6.0.gem", PKG_PATH
|
20
|
+
system "gem install #{PKG_PATH}/#{NAME}-0.6.0.gem"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
11
24
|
Bones {
|
12
|
-
name
|
13
|
-
authors
|
14
|
-
email
|
15
|
-
url
|
25
|
+
name 'ffi-rzmq'
|
26
|
+
authors 'Chuck Remes'
|
27
|
+
email 'cremes@mac.com'
|
28
|
+
url 'http://github.com/chuckremes/ffi-rzmq'
|
16
29
|
readme_file 'README.rdoc'
|
17
30
|
ruby_opts.clear # turn off warnings
|
31
|
+
|
32
|
+
# necessary for MRI; unnecessary for JRuby and RBX
|
33
|
+
# can't enable this until JRuby & RBX have a way of dealing with it cleanly
|
34
|
+
#depend_on 'ffi', '>= 1.0.0'
|
18
35
|
}
|
19
36
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ffi-rzmq'
|
3
|
+
|
4
|
+
if ARGV.length < 3
|
5
|
+
puts "usage: local_lat <connect-to> <message-size> <roundtrip-count>"
|
6
|
+
exit
|
7
|
+
end
|
8
|
+
|
9
|
+
link = ARGV[0]
|
10
|
+
message_size = ARGV[1].to_i
|
11
|
+
roundtrip_count = ARGV[2].to_i
|
12
|
+
|
13
|
+
#link = "tcp://127.0.0.1:5555"
|
14
|
+
|
15
|
+
ctx = ZMQ::Context.new
|
16
|
+
s1 = ctx.socket ZMQ::REQ
|
17
|
+
s2 = ctx.socket ZMQ::REP
|
18
|
+
|
19
|
+
s1.connect link
|
20
|
+
s2.bind link
|
21
|
+
|
22
|
+
poller = ZMQ::Poller.new
|
23
|
+
poller.register_readable s2
|
24
|
+
poller.register_readable s1
|
25
|
+
|
26
|
+
|
27
|
+
start_time = Time.now
|
28
|
+
|
29
|
+
# kick it off
|
30
|
+
message = ZMQ::Message.new("a" * message_size)
|
31
|
+
s1.send message, ZMQ::NOBLOCK
|
32
|
+
i = roundtrip_count
|
33
|
+
|
34
|
+
until i.zero?
|
35
|
+
i -= 1
|
36
|
+
|
37
|
+
begin
|
38
|
+
poller.poll_nonblock
|
39
|
+
rescue ZMQ::PollError => e
|
40
|
+
puts "efault? [#{e.efault?}]"
|
41
|
+
raise
|
42
|
+
end
|
43
|
+
|
44
|
+
poller.readables.each do |socket|
|
45
|
+
received_message = socket.recv_string ZMQ::NOBLOCK
|
46
|
+
socket.send ZMQ::Message.new(received_message), ZMQ::NOBLOCK
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
elapsed_usecs = (Time.now.to_f - start_time.to_f) * 1_000_000
|
51
|
+
latency = elapsed_usecs / roundtrip_count / 2
|
52
|
+
|
53
|
+
puts "mean latency: %.3f [us]" % latency
|
54
|
+
puts "received all messages in %.3f seconds" % (elapsed_usecs / 1_000_000)
|
data/ffi-rzmq.gemspec
CHANGED
@@ -2,42 +2,42 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{ffi-rzmq}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.7.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Chuck Remes"]
|
9
|
-
s.date = %q{2010-
|
9
|
+
s.date = %q{2010-12-22}
|
10
10
|
s.description = %q{This gem wraps the ZeroMQ networking library using the ruby FFI (foreign
|
11
11
|
function interface). It's a pure ruby wrapper so this gem can be loaded
|
12
12
|
and run by any ruby runtime that supports FFI. That's all of them:
|
13
|
-
MRI 1.
|
13
|
+
MRI 1.9.x, Rubinius and JRuby.
|
14
14
|
|
15
15
|
The impetus behind this library was to provide support for ZeroMQ in
|
16
|
-
JRuby which has native threads. Unlike MRI,
|
16
|
+
JRuby which has native threads. Unlike MRI, IronRuby and
|
17
17
|
Rubinius which all have a GIL, JRuby allows for threaded access to ruby
|
18
18
|
code from outside extensions. ZeroMQ is heavily threaded, so until the
|
19
19
|
other runtimes remove their GIL, JRuby will likely be the best
|
20
20
|
environment to run this library.}
|
21
21
|
s.email = %q{cremes@mac.com}
|
22
22
|
s.extra_rdoc_files = ["History.txt", "README.rdoc", "examples/README.rdoc", "version.txt"]
|
23
|
-
s.files = [".
|
23
|
+
s.files = [".bnsignore", "History.txt", "README.rdoc", "Rakefile", "examples/README.rdoc", "examples/local_lat.rb", "examples/local_lat_poll.rb", "examples/local_lat_zerocopy.rb", "examples/local_throughput.rb", "examples/publish_subscribe.rb", "examples/remote_lat.rb", "examples/remote_lat_zerocopy.rb", "examples/remote_throughput.rb", "examples/reqrep_poll.rb", "examples/request_response.rb", "ffi-rzmq.gemspec", "lib/ffi-rzmq.rb", "lib/ffi-rzmq/context.rb", "lib/ffi-rzmq/exceptions.rb", "lib/ffi-rzmq/message.rb", "lib/ffi-rzmq/poll.rb", "lib/ffi-rzmq/poll_items.rb", "lib/ffi-rzmq/socket.rb", "lib/ffi-rzmq/wrapper.rb", "lib/ffi-rzmq/zmq.rb", "spec/context_spec.rb", "spec/message_spec.rb", "spec/pushpull_spec.rb", "spec/reqrep_spec.rb", "spec/socket_spec.rb", "spec/spec_helper.rb", "version.txt"]
|
24
24
|
s.homepage = %q{http://github.com/chuckremes/ffi-rzmq}
|
25
25
|
s.rdoc_options = ["--main", "README.rdoc"]
|
26
26
|
s.require_paths = ["lib"]
|
27
27
|
s.rubyforge_project = %q{ffi-rzmq}
|
28
28
|
s.rubygems_version = %q{1.3.7}
|
29
|
-
s.summary = %q{This gem wraps the ZeroMQ networking library using the ruby FFI (foreign function interface)}
|
29
|
+
s.summary = %q{This gem wraps the ZeroMQ networking library using the ruby FFI (foreign function interface).}
|
30
30
|
|
31
31
|
if s.respond_to? :specification_version then
|
32
32
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
33
33
|
s.specification_version = 3
|
34
34
|
|
35
35
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
36
|
-
s.add_development_dependency(%q<bones>, [">= 3.4
|
36
|
+
s.add_development_dependency(%q<bones>, [">= 3.5.4"])
|
37
37
|
else
|
38
|
-
s.add_dependency(%q<bones>, [">= 3.4
|
38
|
+
s.add_dependency(%q<bones>, [">= 3.5.4"])
|
39
39
|
end
|
40
40
|
else
|
41
|
-
s.add_dependency(%q<bones>, [">= 3.4
|
41
|
+
s.add_dependency(%q<bones>, [">= 3.5.4"])
|
42
42
|
end
|
43
43
|
end
|
data/lib/ffi-rzmq/context.rb
CHANGED
data/lib/ffi-rzmq/poll.rb
CHANGED
@@ -28,6 +28,12 @@ module ZMQ
|
|
28
28
|
# registered sockets belongs to an application thread in another
|
29
29
|
# Context.
|
30
30
|
#
|
31
|
+
# This method will return *immediately* when there are no registered
|
32
|
+
# sockets. In that case, the +timeout+ parameter is not honored. To
|
33
|
+
# prevent a CPU busy-loop, the caller of this method should detect
|
34
|
+
# this possible condition (via #size) and throttle the call
|
35
|
+
# frequency.
|
36
|
+
#
|
31
37
|
def poll timeout = :blocking
|
32
38
|
unless @items.empty?
|
33
39
|
timeout = adjust timeout
|
@@ -178,7 +184,7 @@ module ZMQ
|
|
178
184
|
if :blocking == timeout || -1 == timeout
|
179
185
|
-1
|
180
186
|
else
|
181
|
-
timeout
|
187
|
+
(timeout * 1000).to_i
|
182
188
|
end
|
183
189
|
end
|
184
190
|
end
|
data/lib/ffi-rzmq/socket.rb
CHANGED
@@ -27,7 +27,7 @@ module ZMQ
|
|
27
27
|
#
|
28
28
|
# sock = Socket.new(Context.new, ZMQ::REQ, :receiver_class => ZMQ::ManagedMessage)
|
29
29
|
#
|
30
|
-
# Advanced users may want to replace the receiver class with their
|
30
|
+
# Advanced users may want to replace the receiver class with their
|
31
31
|
# own custom class. The custom class must conform to the same public API
|
32
32
|
# as ZMQ::Message.
|
33
33
|
#
|
@@ -43,13 +43,19 @@ module ZMQ
|
|
43
43
|
|
44
44
|
unless context_ptr.null?
|
45
45
|
@socket = LibZMQ.zmq_socket context_ptr, type
|
46
|
-
|
47
|
-
|
46
|
+
if @socket
|
47
|
+
error_check ZMQ_SOCKET_STR, @socket.null? ? 1 : 0
|
48
|
+
@name = SocketTypeNameMap[type]
|
49
|
+
else
|
50
|
+
raise ContextError.new ZMQ_SOCKET_STR, 0, ETERM, "Socket pointer was null"
|
51
|
+
end
|
48
52
|
else
|
49
53
|
raise ContextError.new ZMQ_SOCKET_STR, 0, ETERM, "Context pointer was null"
|
50
54
|
end
|
51
55
|
|
52
|
-
|
56
|
+
@sockopt_cache = {}
|
57
|
+
|
58
|
+
define_finalizer
|
53
59
|
end
|
54
60
|
|
55
61
|
# Set the queue options on this socket.
|
@@ -61,6 +67,10 @@ module ZMQ
|
|
61
67
|
# ZMQ::RATE
|
62
68
|
# ZMQ::RECOVERY_IVL
|
63
69
|
# ZMQ::MCAST_LOOP
|
70
|
+
# ZMQ::LINGER
|
71
|
+
# ZMQ::RECONNECT_IVL
|
72
|
+
# ZMQ::BACKLOG
|
73
|
+
# ZMQ::RECOVER_IVL_MSEC
|
64
74
|
#
|
65
75
|
# Valid +option_name+ values that take a string +option_value+ are:
|
66
76
|
# ZMQ::IDENTITY
|
@@ -75,13 +85,18 @@ module ZMQ
|
|
75
85
|
def setsockopt option_name, option_value, option_len = nil
|
76
86
|
option_value = sanitize_value option_name, option_value
|
77
87
|
option_len ||= option_value.size
|
78
|
-
|
88
|
+
|
79
89
|
begin
|
80
90
|
case option_name
|
81
|
-
when HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, MCAST_LOOP, SNDBUF, RCVBUF
|
91
|
+
when HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, MCAST_LOOP, SNDBUF, RCVBUF, RECOVERY_IVL_MSEC
|
82
92
|
option_value_ptr = LibC.malloc option_len
|
83
93
|
option_value_ptr.write_long option_value
|
84
94
|
|
95
|
+
when LINGER, RECONNECT_IVL, BACKLOG
|
96
|
+
option_len = 4 # hard-code "int" length to 4 bytes
|
97
|
+
option_value_ptr = LibC.malloc option_len
|
98
|
+
option_value_ptr.write_int option_value
|
99
|
+
|
85
100
|
when IDENTITY, SUBSCRIBE, UNSUBSCRIBE
|
86
101
|
# note: not checking errno for failed memory allocations :(
|
87
102
|
option_value_ptr = LibC.malloc option_len
|
@@ -114,6 +129,12 @@ module ZMQ
|
|
114
129
|
# ZMQ::MCAST_LOOP - boolean
|
115
130
|
# ZMQ::SNDBUF - integer
|
116
131
|
# ZMQ::RCVBUF - integer
|
132
|
+
# ZMQ::FD - fd in an integer
|
133
|
+
# ZMQ::EVENTS - bitmap integer
|
134
|
+
# ZMQ::LINGER - integer measured in milliseconds
|
135
|
+
# ZMQ::RECONNECT_IVL - integer measured in milliseconds
|
136
|
+
# ZMQ::BACKLOG - integer
|
137
|
+
# ZMQ::RECOVER_IVL_MSEC - integer measured in milliseconds
|
117
138
|
#
|
118
139
|
# Can raise two kinds of exceptions depending on the error.
|
119
140
|
# ContextError:: Raised when a socket operation is attempted on a terminated
|
@@ -125,8 +146,10 @@ module ZMQ
|
|
125
146
|
option_value = FFI::MemoryPointer.new :pointer
|
126
147
|
option_length = FFI::MemoryPointer.new :size_t
|
127
148
|
|
128
|
-
unless [
|
129
|
-
|
149
|
+
unless [
|
150
|
+
RCVMORE, HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, MCAST_LOOP, IDENTITY,
|
151
|
+
SNDBUF, RCVBUF, FD, EVENTS, LINGER, RECONNECT_IVL, BACKLOG, RECOVERY_IVL_MSEC
|
152
|
+
].include? option_name
|
130
153
|
# we didn't understand the passed option argument
|
131
154
|
# will force a raise
|
132
155
|
error_check ZMQ_SETSOCKOPT_STR, -1
|
@@ -142,8 +165,10 @@ module ZMQ
|
|
142
165
|
when RCVMORE, MCAST_LOOP
|
143
166
|
# boolean return
|
144
167
|
ret = option_value.read_long_long != 0
|
145
|
-
when HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, SNDBUF, RCVBUF
|
168
|
+
when HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, SNDBUF, RCVBUF, RECOVERY_IVL_MSEC
|
146
169
|
ret = option_value.read_long_long
|
170
|
+
when LINGER, RECONNECT_IVL, BACKLOG, FD, EVENTS
|
171
|
+
ret = option_value.read_int
|
147
172
|
when IDENTITY
|
148
173
|
ret = option_value.read_string(option_length.read_long_long)
|
149
174
|
end
|
@@ -192,12 +217,16 @@ module ZMQ
|
|
192
217
|
error_check ZMQ_CONNECT_STR, result_code
|
193
218
|
end
|
194
219
|
|
195
|
-
# Closes the socket. Any unprocessed messages in queue are dropped
|
220
|
+
# Closes the socket. Any unprocessed messages in queue are sent or dropped
|
221
|
+
# depending upon the value of the socket option ZMQ::LINGER.
|
196
222
|
#
|
197
223
|
def close
|
198
|
-
|
199
|
-
|
200
|
-
|
224
|
+
if @socket
|
225
|
+
remove_finalizer
|
226
|
+
result_code = LibZMQ.zmq_close @socket
|
227
|
+
error_check ZMQ_CLOSE_STR, result_code
|
228
|
+
@socket = nil
|
229
|
+
end
|
201
230
|
end
|
202
231
|
|
203
232
|
# Queues the message for transmission. Message is assumed to conform to the
|
@@ -326,21 +355,37 @@ module ZMQ
|
|
326
355
|
flags != NOBLOCK ? error_check(ZMQ_RECV_STR, result_code) : error_check_nonblock(result_code)
|
327
356
|
end
|
328
357
|
|
358
|
+
# Calls to ZMQ.getsockopt require us to pass in some pointers. We can cache and save those buffers
|
359
|
+
# for subsequent calls. This is a big perf win for calling RCVMORE which happens quite often.
|
360
|
+
# Cannot save the buffer for the IDENTITY.
|
329
361
|
def alloc_temp_sockopt_buffers option_name
|
330
|
-
length = FFI::MemoryPointer.new :int64
|
331
|
-
|
332
362
|
case option_name
|
333
|
-
when RCVMORE, MCAST_LOOP, HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, SNDBUF, RCVBUF
|
363
|
+
when RCVMORE, MCAST_LOOP, HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, SNDBUF, RCVBUF, RECOVERY_IVL_MSEC
|
334
364
|
# int64_t
|
335
|
-
|
336
|
-
|
365
|
+
unless @sockopt_cache[:int64]
|
366
|
+
length = FFI::MemoryPointer.new :int64
|
367
|
+
length.write_long_long 8
|
368
|
+
@sockopt_cache[:int64] = [FFI::MemoryPointer.new(:int64), length]
|
369
|
+
end
|
370
|
+
@sockopt_cache[:int64]
|
371
|
+
|
372
|
+
when LINGER, RECONNECT_IVL, BACKLOG, FD, EVENTS
|
373
|
+
# int, 0mq assumes int is 4-bytes
|
374
|
+
unless @sockopt_cache[:int32]
|
375
|
+
length = FFI::MemoryPointer.new :int32
|
376
|
+
length.write_int 4
|
377
|
+
@sockopt_cache[:int32] = [FFI::MemoryPointer.new(:int32), length]
|
378
|
+
end
|
379
|
+
@sockopt_cache[:int32]
|
380
|
+
|
337
381
|
when IDENTITY
|
382
|
+
length = FFI::MemoryPointer.new :int64
|
338
383
|
# could be a string of up to 255 bytes
|
339
384
|
length.write_long_long 255
|
340
385
|
[FFI::MemoryPointer.new(255), length]
|
341
386
|
end
|
342
387
|
end
|
343
|
-
|
388
|
+
|
344
389
|
def sanitize_value option_name, option_value
|
345
390
|
case option_name
|
346
391
|
when HWM, AFFINITY, SNDBUF, RCVBUF
|
@@ -352,8 +397,17 @@ module ZMQ
|
|
352
397
|
end
|
353
398
|
end
|
354
399
|
|
355
|
-
|
356
|
-
|
400
|
+
# require a minimum of 0mq 2.1.0 to support socket finalizers; it contains important
|
401
|
+
# fixes for sockets and threads so that a garbage collector thread can successfully
|
402
|
+
# reap this resource without crashing
|
403
|
+
if Util.minimum_api?([2, 1, 0])
|
404
|
+
def define_finalizer
|
405
|
+
ObjectSpace.define_finalizer(self, self.class.close(@socket))
|
406
|
+
end
|
407
|
+
else
|
408
|
+
def define_finalizer
|
409
|
+
# no op
|
410
|
+
end
|
357
411
|
end
|
358
412
|
|
359
413
|
def remove_finalizer
|