ffi-rzmq 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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).
|