ffi-rzmq 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +52 -32
- data/ffi-rzmq.gemspec +3 -10
- data/lib/ffi-rzmq.rb +1 -1
- data/lib/ffi-rzmq/context.rb +2 -2
- data/lib/ffi-rzmq/device.rb +15 -0
- data/lib/ffi-rzmq/message.rb +7 -1
- data/lib/ffi-rzmq/poll.rb +19 -6
- data/lib/ffi-rzmq/poll_items.rb +20 -1
- data/lib/ffi-rzmq/socket.rb +27 -15
- data/lib/ffi-rzmq/wrapper.rb +4 -1
- data/lib/ffi-rzmq/zmq.rb +16 -11
- data/spec/device_spec.rb +68 -0
- data/spec/socket_spec.rb +2 -2
- data/version.txt +1 -1
- metadata +8 -13
data/History.txt
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
== 0.8.0 / 20110307
|
2
|
+
* API change!
|
3
|
+
Socket#send_message no longer automatically calls
|
4
|
+
Message#close on behalf of the user. The user is completely
|
5
|
+
responsible for the lifecycle management of all buffers associated
|
6
|
+
with the ZMQ::Message objects.
|
7
|
+
This is a breaking change.
|
8
|
+
If you want the old behavior (auto-close messages on send) then
|
9
|
+
use the new Socket#send_and_close method which does as its name
|
10
|
+
implies.
|
11
|
+
* Fixed bug with type :size_t on Windows (thank you to arvicco)
|
12
|
+
|
13
|
+
== 0.7.3 / 20110304
|
14
|
+
* Fixed a bug where we had a small memory leak. When closing a socket
|
15
|
+
I forgot to release a small amount of native memory used as a cache
|
16
|
+
for doing #getsockopt calls.
|
17
|
+
* Util.minimum_api? didn't work. Fixed.
|
18
|
+
* Added ROUTER/DEALER constants to reflect new naming for XREQ/XREP.
|
19
|
+
XREQ and XREP remain aliased for backward compatibility.
|
20
|
+
|
1
21
|
== 0.7.2 / 20110224
|
2
22
|
* Several minor refactorings to make the code intent clearer and to allow
|
3
23
|
for better testing. In particular, the error condition checking for
|
@@ -12,10 +32,10 @@
|
|
12
32
|
* Improved performance of calls to Socket#getsockopt. There are usually
|
13
33
|
a lot of calls passing RCVMORE, so we now cache those buffers instead
|
14
34
|
of reallocating them every time.
|
15
|
-
|
35
|
+
|
16
36
|
* Updated the docs on Poller#poll to warn about a possible busy-loop
|
17
37
|
condition.
|
18
|
-
|
38
|
+
|
19
39
|
* Fixed some more specs to conform with the 0mq 2.1 requirement that
|
20
40
|
all sockets must be closed explicitly otherwise the program may
|
21
41
|
hang on exit.
|
@@ -28,26 +48,26 @@
|
|
28
48
|
|
29
49
|
* Preliminary support for the Windows platform. Patches supplied
|
30
50
|
by arvicco.
|
31
|
-
|
51
|
+
|
32
52
|
* Added support for FD and EVENTS socket options. These were added
|
33
53
|
in 0mq 2.1.0. Patches + specs supplied by andrewvc.
|
34
|
-
|
54
|
+
|
35
55
|
* Added support for LINGER, RECONNECT_IVL, BACKLOG and
|
36
56
|
RECOVERY_IVL_MSEC socket options.
|
37
|
-
|
57
|
+
|
38
58
|
* Conditionally re-enable the socket finalizer when we are running
|
39
59
|
with 0mq 2.1.0 or later.
|
40
|
-
|
60
|
+
|
41
61
|
* Drop support for MRI 1.8.x since the 'ffi' gem has dropped it as a
|
42
62
|
supported Ruby runtime with its 1.0 release. No action is taken to
|
43
63
|
prevent running with MRI 1.8.x but it won't be supported.
|
44
|
-
|
64
|
+
|
45
65
|
* Misc. spec fixes. Need more specs!
|
46
66
|
|
47
67
|
== 0.6.0 / 20100911
|
48
68
|
* API Change! Modified ZMQ::Message by removing automatic memory
|
49
69
|
management. While doing some performance tests I saw that
|
50
|
-
defining/undefining the finalizer added 15-30% processing
|
70
|
+
defining/undefining the finalizer added 15-30% processing
|
51
71
|
overhead on the latency test. So, I split this functionality
|
52
72
|
out to a subclass called ZMQ::ManagedMemory. Any existing code
|
53
73
|
that relies on the default Message class to clean up after itself
|
@@ -57,7 +77,7 @@
|
|
57
77
|
|
58
78
|
* Rubinius/rbx compatibility! Requires an rbx code pull from git
|
59
79
|
from 20100911 or later to get the necessary code fixes.
|
60
|
-
|
80
|
+
|
61
81
|
* Modify Message to use the @pointer directly rather than indirectly
|
62
82
|
via the @struct object. Provides better compatibility for rbx
|
63
83
|
since rbx does not yet support the FFI pointer protocol for structs
|
@@ -76,38 +96,38 @@
|
|
76
96
|
a pointer to the free function.
|
77
97
|
|
78
98
|
* Modify FFI wrapper to remove the FFI::Function callback used
|
79
|
-
by Message. It's no longer necessary since we now use free
|
99
|
+
by Message. It's no longer necessary since we now use free
|
80
100
|
directly.
|
81
101
|
|
82
102
|
== 0.5.1 / 20100830
|
83
103
|
* Works with 0mq 2.0.8 release.
|
84
|
-
|
104
|
+
|
85
105
|
* Removed the socket finalizer. The current 0mq framework cannot
|
86
106
|
handle the case where zmq_close is called on a socket that was
|
87
107
|
created from another thread. Therefore, the garbage collection
|
88
108
|
thread causes the framework to break. Version 2.1 (or later)
|
89
109
|
should fix this 0mq limitation.
|
90
|
-
|
110
|
+
|
91
111
|
* Misc fixes. See commits.
|
92
112
|
|
93
113
|
== 0.5.0 / 20100606
|
94
114
|
* Updated the bindings to conform to the 0mq 2.0.7 release.
|
95
115
|
Several parts of the API changed.
|
96
|
-
|
116
|
+
|
97
117
|
* Updated all examples to use the new Context api.
|
98
|
-
|
118
|
+
|
99
119
|
* Added Socket#getsockopt.
|
100
|
-
|
120
|
+
|
101
121
|
* Added a Socket#identity and Socket#identity= method pair to
|
102
122
|
allow for easy get/put on socket identities. Useful for async
|
103
123
|
request/reply using XREQ/XREP sockets.
|
104
|
-
|
124
|
+
|
105
125
|
* Added more specs (slowly but surely).
|
106
|
-
|
126
|
+
|
107
127
|
* Support multi-part messages (new as of 2.0.7). I am unsure how
|
108
128
|
to best support multi-part messages so the Message (and related)
|
109
129
|
API may change in the future. Added Socket#more_parts?.
|
110
|
-
|
130
|
+
|
111
131
|
* Lots of fixes. Many classes use finalizers to deallocate native
|
112
132
|
memory when they go out of scope; be sure to use JRuby 1.5.1 or
|
113
133
|
later to get important finalizer fixes.
|
@@ -120,41 +140,41 @@
|
|
120
140
|
== 0.4.0 / 20100510
|
121
141
|
* Changed the Socket#recv method signature to take an optional
|
122
142
|
message object as its first argument. This allows the library
|
123
|
-
user to allocate and pass in their own message object for the
|
143
|
+
user to allocate and pass in their own message object for the
|
124
144
|
purposes of zero-copy. Original behavior was for the library to
|
125
145
|
*always* allocate a new message object to receive a message into.
|
126
146
|
Hopefully this is the last change required.
|
127
|
-
|
147
|
+
|
128
148
|
* Modified the Socket constructor to take an optional hash as its
|
129
149
|
final argument. It honors two keys; :receiver_klass and
|
130
150
|
:sender_klass. Passing in a new constant for either (or both) keys
|
131
151
|
will override the class used by Socket for allocating new
|
132
|
-
Message objects.
|
152
|
+
Message objects.
|
133
153
|
|
134
154
|
== 0.3.1 / 20100509
|
135
155
|
* Modified ZMQ::Message so we have both an UnmanagedMessage where
|
136
156
|
memory management is manual via the #close method, and Message where
|
137
157
|
memory management is automated via a finalizer method run during
|
138
158
|
garbage collection.
|
139
|
-
|
159
|
+
|
140
160
|
* Updated ZMQ::Message docs to make it clearer how to use a subclass
|
141
161
|
and FFI::Struct to lazily access the message buffer. This gets us as
|
142
162
|
close to zero-copy as possible for performance.
|
143
|
-
|
163
|
+
|
144
164
|
* Fixed a memory leak in Message where the FFI::Struct backing the
|
145
165
|
C struct was not being freed.
|
146
|
-
|
166
|
+
|
147
167
|
* Tested the FFI code against MRI 1.8.x and 1.9.x. It works!
|
148
|
-
|
168
|
+
|
149
169
|
* Patched a potential problem in LibZMQ::MessageDeallocator. It was
|
150
170
|
crashing under MRI because it complained that FFI::Pointer did not
|
151
|
-
have a free method. It now checks for :free before calling it.
|
171
|
+
have a free method. It now checks for :free before calling it.
|
152
172
|
Need to investigate this further because it never happened under
|
153
173
|
JRuby.
|
154
|
-
|
174
|
+
|
155
175
|
* Modified the Socket constructor slightly to allow for using
|
156
176
|
unmanaged or managed messages.
|
157
|
-
|
177
|
+
|
158
178
|
* Changed the /examples to print a throughput (msgs/s) number upon
|
159
179
|
completion.
|
160
180
|
|
@@ -164,20 +184,20 @@
|
|
164
184
|
However, to do so requires lots of copying to and from buffers which
|
165
185
|
greatly impacts performance. These methods now return a ZMQ::Message
|
166
186
|
object which can be subclassed to do lazy evaluation of the buffer.
|
167
|
-
|
187
|
+
|
168
188
|
* Added ZMQ::Socket#send_string and ZMQ::Socket#recv_string. They
|
169
189
|
automatically convert the messages to strings just like the official
|
170
190
|
0mq ruby bindings.
|
171
191
|
|
172
192
|
* Fixed bug in ZMQ::Util#error_string
|
173
|
-
|
193
|
+
|
174
194
|
* Split the ZMQ::Message class into two classes. The base class called
|
175
195
|
UnmanagedMessage requires manual memory management. The Message
|
176
196
|
class (used by default by Socket) has a finalizer defined to
|
177
197
|
automatically release memory when the message object gets garbage
|
178
198
|
collected.
|
179
|
-
|
180
|
-
|
199
|
+
|
200
|
+
|
181
201
|
== 0.2.0 / 20100505
|
182
202
|
|
183
203
|
* 1 major enhancement
|
data/ffi-rzmq.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{ffi-rzmq}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.8.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"]
|
@@ -10,17 +10,10 @@ Gem::Specification.new do |s|
|
|
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.9.x, Rubinius and JRuby.
|
14
|
-
|
15
|
-
The impetus behind this library was to provide support for ZeroMQ in
|
16
|
-
JRuby which has native threads. Unlike MRI, IronRuby and
|
17
|
-
Rubinius which all have a GIL, JRuby allows for threaded access to ruby
|
18
|
-
code from outside extensions. ZeroMQ is heavily threaded, so until the
|
19
|
-
other runtimes remove their GIL, JRuby will likely be the best
|
20
|
-
environment to run this library.}
|
13
|
+
MRI 1.9.x, Rubinius and JRuby.}
|
21
14
|
s.email = %q{cremes@mac.com}
|
22
15
|
s.extra_rdoc_files = ["History.txt", "README.rdoc", "examples/README.rdoc", "version.txt"]
|
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"]
|
16
|
+
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/device.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/device_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
17
|
s.homepage = %q{http://github.com/chuckremes/ffi-rzmq}
|
25
18
|
s.rdoc_options = ["--main", "README.rdoc"]
|
26
19
|
s.require_paths = ["lib"]
|
data/lib/ffi-rzmq.rb
CHANGED
@@ -67,6 +67,6 @@ end # module ZMQ
|
|
67
67
|
RBX = defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ ? true : false
|
68
68
|
|
69
69
|
# the order of files is important
|
70
|
-
%w(wrapper zmq exceptions context message socket poll_items poll).each do |file|
|
70
|
+
%w(wrapper zmq exceptions context message socket poll_items poll device).each do |file|
|
71
71
|
require ZMQ.libpath(['ffi-rzmq', file])
|
72
72
|
end
|
data/lib/ffi-rzmq/context.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
module ZMQ
|
2
|
+
class Device
|
3
|
+
attr_reader :device
|
4
|
+
|
5
|
+
def initialize(device_type,frontend,backend)
|
6
|
+
[["frontend", frontend],["backend", backend]].each do |name,socket|
|
7
|
+
unless socket.is_a?(ZMQ::Socket)
|
8
|
+
raise ArgumentError, "Expected a ZMQ::Socket, not a #{socket.class} as the #{name}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
LibZMQ.zmq_device(device_type, frontend.socket, backend.socket)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/ffi-rzmq/message.rb
CHANGED
@@ -189,8 +189,14 @@ module ZMQ
|
|
189
189
|
# Manually release the message struct and its associated data
|
190
190
|
# buffer.
|
191
191
|
#
|
192
|
+
# Only releases the buffer a single time. Subsequent calls are
|
193
|
+
# no ops.
|
194
|
+
#
|
192
195
|
def close
|
193
|
-
|
196
|
+
if @pointer
|
197
|
+
LibZMQ.zmq_msg_close @pointer
|
198
|
+
@pointer = nil
|
199
|
+
end
|
194
200
|
end
|
195
201
|
|
196
202
|
|
data/lib/ffi-rzmq/poll.rb
CHANGED
@@ -67,7 +67,6 @@ module ZMQ
|
|
67
67
|
def register sock, events = ZMQ::POLLIN | ZMQ::POLLOUT, fd = 0
|
68
68
|
return false if (sock.nil? && fd.zero?) || events.zero?
|
69
69
|
|
70
|
-
@poll_items_dirty = true
|
71
70
|
item = @items.get(@sockets.index(sock))
|
72
71
|
|
73
72
|
unless item
|
@@ -78,7 +77,7 @@ module ZMQ
|
|
78
77
|
item[:socket] = sock.socket
|
79
78
|
item[:fd] = 0
|
80
79
|
else
|
81
|
-
item[:socket] = 0
|
80
|
+
item[:socket] = FFI::MemoryPointer.new(0)
|
82
81
|
item[:fd] = fd
|
83
82
|
end
|
84
83
|
|
@@ -132,14 +131,28 @@ module ZMQ
|
|
132
131
|
|
133
132
|
# Deletes the +sock+ for all subscribed events.
|
134
133
|
#
|
134
|
+
# def delete sock
|
135
|
+
# removed = false
|
136
|
+
#
|
137
|
+
# if index = @sockets.index(sock)
|
138
|
+
# removed = @items.delete_at(index) and @sockets.delete(sock) and @raw_to_socket.delete(sock.socket.address)
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# removed
|
142
|
+
# end
|
135
143
|
def delete sock
|
136
144
|
removed = false
|
145
|
+
size = @sockets.size
|
146
|
+
@sockets.delete_if { |socket| socket.socket.address == sock.socket.address }
|
147
|
+
socket_deleted = size != @sockets.size
|
137
148
|
|
138
|
-
|
139
|
-
|
140
|
-
|
149
|
+
item_deleted = @items.delete sock
|
150
|
+
|
151
|
+
size = @raw_to_socket.size
|
152
|
+
@raw_to_socket.delete(sock.socket.address)
|
153
|
+
raw_deleted = size != @raw_to_socket.size
|
141
154
|
|
142
|
-
|
155
|
+
socket_deleted && item_deleted && raw_deleted
|
143
156
|
end
|
144
157
|
|
145
158
|
def size(); @items.size; end
|
data/lib/ffi-rzmq/poll_items.rb
CHANGED
@@ -37,6 +37,25 @@ module ZMQ
|
|
37
37
|
end
|
38
38
|
alias :push :<<
|
39
39
|
|
40
|
+
def delete sock
|
41
|
+
address = sock.socket.address
|
42
|
+
found = false
|
43
|
+
|
44
|
+
each_with_index do |item, index|
|
45
|
+
if address == item[:socket].address
|
46
|
+
@items.delete_at index
|
47
|
+
found = true
|
48
|
+
@dirty = true
|
49
|
+
clean
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# these semantics are different from the usual Array#delete; returns a
|
55
|
+
# boolean instead of the actual item or nil
|
56
|
+
found
|
57
|
+
end
|
58
|
+
|
40
59
|
def delete_at index
|
41
60
|
value = nil
|
42
61
|
unless @items.empty?
|
@@ -84,7 +103,7 @@ module ZMQ
|
|
84
103
|
# it is garbage collected that native memory should be automatically freed.
|
85
104
|
def clean
|
86
105
|
if @dirty
|
87
|
-
@store = FFI::MemoryPointer.new @element_size, @items.size,
|
106
|
+
@store = FFI::MemoryPointer.new @element_size, @items.size, true
|
88
107
|
|
89
108
|
# copy over
|
90
109
|
offset = 0
|
data/lib/ffi-rzmq/socket.rb
CHANGED
@@ -19,7 +19,7 @@ module ZMQ
|
|
19
19
|
#
|
20
20
|
# +type+ can be one of ZMQ::REQ, ZMQ::REP, ZMQ::PUB,
|
21
21
|
# ZMQ::SUB, ZMQ::PAIR, ZMQ::PULL, ZMQ::PUSH,
|
22
|
-
# ZMQ::
|
22
|
+
# ZMQ::DEALER or ZMQ::ROUTER.
|
23
23
|
#
|
24
24
|
# By default, this class uses ZMQ::Message for manual
|
25
25
|
# memory management. For automatic garbage collection of received messages,
|
@@ -144,7 +144,7 @@ module ZMQ
|
|
144
144
|
def getsockopt option_name
|
145
145
|
begin
|
146
146
|
option_value = FFI::MemoryPointer.new :pointer
|
147
|
-
option_length = FFI::MemoryPointer.new :
|
147
|
+
option_length = FFI::MemoryPointer.new(:size_t) rescue FFI::MemoryPointer.new(:ulong)
|
148
148
|
|
149
149
|
unless [
|
150
150
|
RCVMORE, HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, MCAST_LOOP, IDENTITY,
|
@@ -226,6 +226,7 @@ module ZMQ
|
|
226
226
|
result_code = LibZMQ.zmq_close @socket
|
227
227
|
error_check ZMQ_CLOSE_STR, result_code
|
228
228
|
@socket = nil
|
229
|
+
release_cache
|
229
230
|
end
|
230
231
|
end
|
231
232
|
|
@@ -242,13 +243,8 @@ module ZMQ
|
|
242
243
|
# 1. The message could not be enqueued
|
243
244
|
# 2. When +flags+ is set with ZMQ::NOBLOCK and the socket returned EAGAIN.
|
244
245
|
#
|
245
|
-
# The application code is
|
246
|
-
# lifecycle when #send returns
|
247
|
-
# #send method takes ownership of the +message+ and its associated buffers.
|
248
|
-
# Both successful and failed calls will release the +message+ data buffer.
|
249
|
-
#
|
250
|
-
# Again, once a +message+ object has been passed to this method,
|
251
|
-
# do not try to access its #data buffer anymore. The 0mq library now owns it.
|
246
|
+
# The application code is responsible for handling the +message+ object
|
247
|
+
# lifecycle when #send returns.
|
252
248
|
#
|
253
249
|
# Can raise two kinds of exceptions depending on the error.
|
254
250
|
# ContextError:: Raised when a socket operation is attempted on a terminated
|
@@ -262,8 +258,6 @@ module ZMQ
|
|
262
258
|
# when the flag isn't set, do a normal error check
|
263
259
|
# when set, check to see if the message was successfully queued
|
264
260
|
queued = flags != NOBLOCK ? error_check(ZMQ_SEND_STR, result_code) : error_check_nonblock(result_code)
|
265
|
-
ensure
|
266
|
-
message.close
|
267
261
|
end
|
268
262
|
|
269
263
|
# true if sent, false if failed/EAGAIN
|
@@ -281,10 +275,24 @@ module ZMQ
|
|
281
275
|
# SocketError:: See all of the possibilities in the docs for #SocketError.
|
282
276
|
#
|
283
277
|
def send_string message_string, flags = 0
|
284
|
-
message = Message.new
|
285
|
-
message
|
286
|
-
|
287
|
-
|
278
|
+
message = Message.new message_string
|
279
|
+
result_code = send_and_close message, flags
|
280
|
+
|
281
|
+
result_code
|
282
|
+
end
|
283
|
+
|
284
|
+
# Sends a message. This will automatically close the +message+ for both successful
|
285
|
+
# and failed sends.
|
286
|
+
#
|
287
|
+
# Raises the same exceptions as Socket#send
|
288
|
+
#
|
289
|
+
def send_and_close message, flags = 0
|
290
|
+
begin
|
291
|
+
result_code = send message, flags
|
292
|
+
ensure
|
293
|
+
message.close
|
294
|
+
end
|
295
|
+
result_code
|
288
296
|
end
|
289
297
|
|
290
298
|
# Dequeues a message from the underlying queue. By default, this is a blocking operation.
|
@@ -404,6 +412,10 @@ module ZMQ
|
|
404
412
|
option_value
|
405
413
|
end
|
406
414
|
end
|
415
|
+
|
416
|
+
def release_cache
|
417
|
+
@sockopt_cache.clear
|
418
|
+
end
|
407
419
|
|
408
420
|
# require a minimum of 0mq 2.1.0 to support socket finalizers; it contains important
|
409
421
|
# fixes for sockets and threads so that a garbage collector thread can successfully
|
data/lib/ffi-rzmq/wrapper.rb
CHANGED
@@ -78,6 +78,9 @@ module LibZMQ
|
|
78
78
|
attach_function :zmq_recv, [:pointer, :pointer, :int], :int
|
79
79
|
attach_function :zmq_close, [:pointer], :int
|
80
80
|
|
81
|
+
#experimental zmq_devices support
|
82
|
+
attach_function :zmq_device, [:int, :pointer, :pointer], :int
|
83
|
+
|
81
84
|
# Poll api
|
82
85
|
@blocking = true
|
83
86
|
attach_function :zmq_poll, [:pointer, :int, :long], :int
|
@@ -117,4 +120,4 @@ module LibZMQ
|
|
117
120
|
def to_s; inspect; end
|
118
121
|
end # class PollItem
|
119
122
|
|
120
|
-
end # module
|
123
|
+
end # module LibZMQ
|
data/lib/ffi-rzmq/zmq.rb
CHANGED
@@ -7,19 +7,19 @@ module ZMQ
|
|
7
7
|
SUB = 2
|
8
8
|
REQ = 3
|
9
9
|
REP = 4
|
10
|
-
XREQ = 5
|
11
|
-
XREP = 6
|
10
|
+
ROUTER = XREQ = 5
|
11
|
+
DEALER = XREP = 6
|
12
12
|
PULL = UPSTREAM = 7
|
13
13
|
PUSH = DOWNSTREAM = 8
|
14
|
-
|
14
|
+
|
15
15
|
SocketTypeNameMap = {
|
16
16
|
PAIR => "PAIR",
|
17
17
|
PUB => "PUB",
|
18
18
|
SUB => "SUB",
|
19
19
|
REQ => "REQ",
|
20
20
|
REP => "REP",
|
21
|
-
|
22
|
-
|
21
|
+
ROUTER => "ROUTER",
|
22
|
+
DEALER => "DEALER",
|
23
23
|
PULL => "PULL",
|
24
24
|
PUSH => "PUSH"
|
25
25
|
}
|
@@ -63,6 +63,11 @@ module ZMQ
|
|
63
63
|
ENODEV = Errno::ENODEV::Errno
|
64
64
|
EFAULT = Errno::EFAULT::Errno
|
65
65
|
|
66
|
+
# Device Types
|
67
|
+
STREAMER = 1
|
68
|
+
FORWARDER = 2
|
69
|
+
QUEUE = 3
|
70
|
+
|
66
71
|
# ZMQ errors
|
67
72
|
HAUSNUMERO = 156384712
|
68
73
|
EMTHREAD = (HAUSNUMERO + 50)
|
@@ -114,7 +119,7 @@ module ZMQ
|
|
114
119
|
LibZMQ.zmq_version major, minor, patch
|
115
120
|
[major.read_int, minor.read_int, patch.read_int]
|
116
121
|
end
|
117
|
-
|
122
|
+
|
118
123
|
# Compares the 0mq library API version to a minimal version tuple. Returns
|
119
124
|
# true if it meets the minimum requirement, false otherwise.
|
120
125
|
#
|
@@ -125,11 +130,11 @@ module ZMQ
|
|
125
130
|
#
|
126
131
|
def self.minimum_api? tuple
|
127
132
|
api_version = Util.version
|
128
|
-
|
133
|
+
|
129
134
|
# call #to_i to convert nil entries to 0 so the comparison is valid
|
130
|
-
tuple[0].to_i
|
131
|
-
tuple[1].to_i
|
132
|
-
tuple[2].to_i
|
135
|
+
result = tuple[0].to_i <= api_version[0] &&
|
136
|
+
tuple[1].to_i <= api_version[1] &&
|
137
|
+
tuple[2].to_i <= api_version[2]
|
133
138
|
end
|
134
139
|
|
135
140
|
|
@@ -180,7 +185,7 @@ module ZMQ
|
|
180
185
|
when ZMQ_MSG_INIT_STR, ZMQ_MSG_INIT_DATA_STR, ZMQ_MSG_COPY_STR, ZMQ_MSG_MOVE_STR
|
181
186
|
raise MessageError.new source, result_code, errno, error_string
|
182
187
|
else
|
183
|
-
raise ZeroMQError.new source, result_code, -1,
|
188
|
+
raise ZeroMQError.new source, result_code, -1,
|
184
189
|
"Source [#{source}] does not match any zmq_* strings, rc [#{result_code}], errno [#{errno}], error_string [#{error_string}]"
|
185
190
|
end
|
186
191
|
end
|
data/spec/device_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
3
|
+
|
4
|
+
module ZMQ
|
5
|
+
describe Device do
|
6
|
+
include APIHelper
|
7
|
+
|
8
|
+
def create_streamer
|
9
|
+
@back_addr = "tcp://127.0.0.1:#{random_port}"
|
10
|
+
@front_addr = "tcp://127.0.0.1:#{random_port}"
|
11
|
+
Thread.new do
|
12
|
+
back = SPEC_CTX.socket(ZMQ::PULL)
|
13
|
+
back.bind(@back_addr)
|
14
|
+
front = SPEC_CTX.socket(ZMQ::PUSH)
|
15
|
+
front.bind(@front_addr)
|
16
|
+
Device.new(ZMQ::STREAMER, back, front)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should create a streamer device without error given valid opts" do
|
21
|
+
create_streamer
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be able to send messages through the device" do
|
25
|
+
create_streamer
|
26
|
+
|
27
|
+
pusher = SPEC_CTX.socket(ZMQ::PUSH)
|
28
|
+
pusher.connect(@back_addr)
|
29
|
+
puller = SPEC_CTX.socket(ZMQ::PULL)
|
30
|
+
puller.connect(@front_addr)
|
31
|
+
|
32
|
+
pusher.send_string("hello")
|
33
|
+
sleep 0.5
|
34
|
+
res = puller.recv_string(ZMQ::NOBLOCK)
|
35
|
+
res.should == "hello"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise an ArgumentError when trying to pass non-socket objects into the device" do
|
39
|
+
lambda {
|
40
|
+
Device.new(ZMQ::STREAMER, 1,2)
|
41
|
+
}.should raise_exception(ArgumentError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be able to create a forwarder device without error" do
|
45
|
+
back_addr = "tcp://127.0.0.1:#{random_port}"
|
46
|
+
front_addr = "tcp://127.0.0.1:#{random_port}"
|
47
|
+
Thread.new do
|
48
|
+
back = SPEC_CTX.socket(ZMQ::SUB)
|
49
|
+
back.bind(back_addr)
|
50
|
+
front = SPEC_CTX.socket(ZMQ::PUB)
|
51
|
+
front.bind(front_addr)
|
52
|
+
Device.new(ZMQ::FORWARDER, back, front)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be able to create a queue device without error" do
|
57
|
+
back_addr = "tcp://127.0.0.1:#{random_port}"
|
58
|
+
front_addr = "tcp://127.0.0.1:#{random_port}"
|
59
|
+
Thread.new do
|
60
|
+
back = SPEC_CTX.socket(ZMQ::ROUTER)
|
61
|
+
back.bind(back_addr)
|
62
|
+
front = SPEC_CTX.socket(ZMQ::DEALER)
|
63
|
+
front.bind(front_addr)
|
64
|
+
Device.new(ZMQ::QUEUE, back, front)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/socket_spec.rb
CHANGED
@@ -15,7 +15,7 @@ module ZMQ
|
|
15
15
|
lambda { Socket.new(FFI::Pointer.new(0), ZMQ::REQ) }.should raise_exception(ZMQ::ContextError)
|
16
16
|
end
|
17
17
|
|
18
|
-
[ZMQ::REQ, ZMQ::REP, ZMQ::
|
18
|
+
[ZMQ::REQ, ZMQ::REP, ZMQ::DEALER, ZMQ::ROUTER, ZMQ::PUB, ZMQ::SUB, ZMQ::PUSH, ZMQ::PULL, ZMQ::PAIR].each do |socket_type|
|
19
19
|
|
20
20
|
it "should not raise an error for a #{ZMQ::SocketTypeNameMap[socket_type]} socket type" do
|
21
21
|
sock = nil
|
@@ -99,7 +99,7 @@ module ZMQ
|
|
99
99
|
end # context identity=
|
100
100
|
|
101
101
|
|
102
|
-
[ZMQ::REQ, ZMQ::REP, ZMQ::
|
102
|
+
[ZMQ::REQ, ZMQ::REP, ZMQ::DEALER, ZMQ::ROUTER, ZMQ::PUB, ZMQ::SUB, ZMQ::PUSH, ZMQ::PULL, ZMQ::PAIR].each do |socket_type|
|
103
103
|
|
104
104
|
context "#setsockopt for a #{ZMQ::SocketTypeNameMap[socket_type]} socket" do
|
105
105
|
before(:all) { @ctx = Context.new }
|
data/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-rzmq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 63
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 8
|
9
|
+
- 0
|
10
|
+
version: 0.8.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Chuck Remes
|
@@ -39,13 +39,6 @@ description: |-
|
|
39
39
|
function interface). It's a pure ruby wrapper so this gem can be loaded
|
40
40
|
and run by any ruby runtime that supports FFI. That's all of them:
|
41
41
|
MRI 1.9.x, Rubinius and JRuby.
|
42
|
-
|
43
|
-
The impetus behind this library was to provide support for ZeroMQ in
|
44
|
-
JRuby which has native threads. Unlike MRI, IronRuby and
|
45
|
-
Rubinius which all have a GIL, JRuby allows for threaded access to ruby
|
46
|
-
code from outside extensions. ZeroMQ is heavily threaded, so until the
|
47
|
-
other runtimes remove their GIL, JRuby will likely be the best
|
48
|
-
environment to run this library.
|
49
42
|
email: cremes@mac.com
|
50
43
|
executables: []
|
51
44
|
|
@@ -75,6 +68,7 @@ files:
|
|
75
68
|
- ffi-rzmq.gemspec
|
76
69
|
- lib/ffi-rzmq.rb
|
77
70
|
- lib/ffi-rzmq/context.rb
|
71
|
+
- lib/ffi-rzmq/device.rb
|
78
72
|
- lib/ffi-rzmq/exceptions.rb
|
79
73
|
- lib/ffi-rzmq/message.rb
|
80
74
|
- lib/ffi-rzmq/poll.rb
|
@@ -83,6 +77,7 @@ files:
|
|
83
77
|
- lib/ffi-rzmq/wrapper.rb
|
84
78
|
- lib/ffi-rzmq/zmq.rb
|
85
79
|
- spec/context_spec.rb
|
80
|
+
- spec/device_spec.rb
|
86
81
|
- spec/message_spec.rb
|
87
82
|
- spec/pushpull_spec.rb
|
88
83
|
- spec/reqrep_spec.rb
|
@@ -120,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
115
|
requirements: []
|
121
116
|
|
122
117
|
rubyforge_project: ffi-rzmq
|
123
|
-
rubygems_version: 1.
|
118
|
+
rubygems_version: 1.5.2
|
124
119
|
signing_key:
|
125
120
|
specification_version: 3
|
126
121
|
summary: This gem wraps the ZeroMQ networking library using the ruby FFI (foreign function interface).
|