ffi-rzmq 0.5.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.
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'ffi-rzmq'
3
+
4
+ if ARGV.length < 3
5
+ puts "usage: remote_lat <connect-to> <message-size> <roundtrip-count>"
6
+ exit
7
+ end
8
+
9
+ connect_to = ARGV[0]
10
+ message_size = ARGV[1].to_i
11
+ roundtrip_count = ARGV[2].to_i
12
+
13
+ ctx = ZMQ::Context.new 1
14
+ s = ctx.socket ZMQ::REQ
15
+ s.connect connect_to
16
+
17
+ msg = ZMQ::Message.new "#{'3'*message_size}"
18
+
19
+ start_time = Time.now
20
+
21
+ roundtrip_count.times do
22
+ s.send msg, 0
23
+ result = s.recv msg, 0
24
+ raise "Message size doesn't match, expected [#{message_size}] but received [#{msg.size}]" if message_size != msg.size
25
+ end
26
+
27
+ end_time = Time.now
28
+ elapsed_secs = (end_time.to_f - start_time.to_f)
29
+ elapsed_usecs = elapsed_secs * 1000000
30
+ latency = elapsed_usecs / roundtrip_count / 2
31
+
32
+ puts "message size: %i [B]" % message_size
33
+ puts "roundtrip count: %i" % roundtrip_count
34
+ puts "throughput (msgs/s): %i" % (roundtrip_count / elapsed_secs)
35
+ puts "mean latency: %.3f [us]" % latency
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'ffi-rzmq'
3
+
4
+
5
+ link = "tcp://127.0.0.1:5555"
6
+
7
+ ctx = ZMQ::Context.new 1
8
+ s1 = ctx.socket ZMQ::REQ
9
+ s2 = ctx.socket ZMQ::REP
10
+
11
+ s1.connect link
12
+ s2.bind link
13
+
14
+ poller = ZMQ::Poller.new
15
+ poller.register_readable s2
16
+ poller.register_writable s1
17
+
18
+ start_time = Time.now
19
+ @unsent = true
20
+
21
+ until @done do
22
+ begin
23
+ poller.poll_nonblock
24
+ rescue ZMQ::PollError => e
25
+ puts "efault? [#{e.efault?}]"
26
+ raise
27
+ end
28
+
29
+ # send the message after 5 seconds
30
+ if Time.now - start_time > 5 && @unsent
31
+ payload = "#{ '3' * 1024 }"
32
+
33
+ puts "sending payload nonblocking"
34
+ s1.send_string payload, ZMQ::NOBLOCK
35
+ @unsent = false
36
+ end
37
+
38
+ # check for messages after 1 second
39
+ if Time.now - start_time > 1
40
+ poller.readables.each do |sock|
41
+ received_msg = sock.recv_string ZMQ::NOBLOCK
42
+
43
+ puts "message received [#{received_msg}]"
44
+ @done = true
45
+ end
46
+ end
47
+ end
48
+
49
+ puts "executed in [#{Time.now - start_time}] seconds"
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'ffi-rzmq'
3
+
4
+
5
+ link = "tcp://127.0.0.1:5555"
6
+
7
+ ctx = ZMQ::Context.new 1
8
+ s1 = ctx.socket ZMQ::REQ
9
+ s2 = ctx.socket ZMQ::REP
10
+
11
+ s2.bind link
12
+ s1.connect link
13
+
14
+ payload = "#{ '3' * 2048 }"
15
+ sent_msg = ZMQ::Message.new payload
16
+ received_msg = ZMQ::Message.new
17
+
18
+ s1.send sent_msg
19
+ s2.recv received_msg
20
+
21
+ result = payload == received_msg.copy_out_string ? "Request received" : "Received wrong payload"
22
+
23
+ p result
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ffi-rzmq}
5
+ s.version = "0.5.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Chuck Remes"]
9
+ s.date = %q{2010-06-06}
10
+ s.description = %q{This gem wraps the ZeroMQ networking library using the ruby FFI (foreign
11
+ function interface). It's a pure ruby wrapper so this gem can be loaded
12
+ and run by any ruby runtime that supports FFI. Right now that means
13
+ MRI 1.8.7, 1.9.1 and JRuby.
14
+
15
+ The impetus behind this library was to provide support for ZeroMQ in
16
+ JRuby which has native threads. Unlike MRI, MacRuby, 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.}
21
+ s.email = %q{cremes@mac.com}
22
+ s.extra_rdoc_files = ["History.txt", "README.rdoc", "version.txt"]
23
+ s.files = ["History.txt", "README.rdoc", "Rakefile", "examples/local_lat.rb", "examples/local_lat_zerocopy.rb", "examples/publish_subscribe.rb", "examples/remote_lat.rb", "examples/remote_lat_zerocopy.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/reqrep_spec.rb", "spec/socket_spec.rb", "spec/spec_helper.rb", "version.txt"]
24
+ s.homepage = %q{http://github.com/chuckremes/ffi-rzmq}
25
+ s.rdoc_options = ["--main", "README.rdoc"]
26
+ s.require_paths = ["lib"]
27
+ s.rubyforge_project = %q{ffi-rzmq}
28
+ s.rubygems_version = %q{1.3.6}
29
+ s.summary = %q{This gem wraps the ZeroMQ networking library using the ruby FFI (foreign function interface)}
30
+
31
+ if s.respond_to? :specification_version then
32
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
33
+ s.specification_version = 3
34
+
35
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
36
+ s.add_development_dependency(%q<bones>, [">= 3.4.3"])
37
+ else
38
+ s.add_dependency(%q<bones>, [">= 3.4.3"])
39
+ end
40
+ else
41
+ s.add_dependency(%q<bones>, [">= 3.4.3"])
42
+ end
43
+ end
@@ -0,0 +1,71 @@
1
+
2
+ module ZMQ
3
+
4
+ # :stopdoc:
5
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
+ # :startdoc:
8
+
9
+ # Returns the version string for the library.
10
+ #
11
+ def self.version
12
+ @version ||= File.read(path('version.txt')).strip
13
+ end
14
+
15
+ # Returns the library path for the module. If any arguments are given,
16
+ # they will be joined to the end of the libray path using
17
+ # <tt>File.join</tt>.
18
+ #
19
+ def self.libpath( *args, &block )
20
+ rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
21
+ if block
22
+ begin
23
+ $LOAD_PATH.unshift LIBPATH
24
+ rv = block.call
25
+ ensure
26
+ $LOAD_PATH.shift
27
+ end
28
+ end
29
+ return rv
30
+ end
31
+
32
+ # Returns the lpath for the module. If any arguments are given,
33
+ # they will be joined to the end of the path using
34
+ # <tt>File.join</tt>.
35
+ #
36
+ def self.path( *args, &block )
37
+ rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
38
+ if block
39
+ begin
40
+ $LOAD_PATH.unshift PATH
41
+ rv = block.call
42
+ ensure
43
+ $LOAD_PATH.shift
44
+ end
45
+ end
46
+ return rv
47
+ end
48
+
49
+ # Utility method used to require all files ending in .rb that lie in the
50
+ # directory below this file that has the same name as the filename passed
51
+ # in. Optionally, a specific _directory_ name can be passed in such that
52
+ # the _filename_ does not have to be equivalent to the directory.
53
+ #
54
+ def self.require_all_libs_relative_to( fname, dir = nil )
55
+ dir ||= ::File.basename(fname, '.*')
56
+ search_me = ::File.expand_path(
57
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
58
+
59
+ Dir.glob(search_me).sort.each {|rb| require rb}
60
+ end
61
+
62
+ end # module ZMQ
63
+
64
+ # some code is conditionalized based upon what ruby engine we are
65
+ # executing
66
+ RBX = RUBY_ENGINE =~ /rbx/ ? true : false
67
+
68
+ # the order of files is important
69
+ %w(wrapper zmq exceptions context message socket poll_items poll).each do |file|
70
+ require ZMQ.libpath(['ffi-rzmq', file])
71
+ end
@@ -0,0 +1,99 @@
1
+
2
+ module ZMQ
3
+
4
+ ZMQ_INIT_STR = 'zmq_init'.freeze
5
+ ZMQ_TERM_STR = 'zmq_term'.freeze
6
+ ZMQ_SOCKET_STR = 'zmq_socket'.freeze unless defined? ZMQ_SOCKET_STR
7
+
8
+
9
+ class Context
10
+ include ZMQ::Util
11
+
12
+ attr_reader :context, :pointer
13
+
14
+ # Recommended to just pass 1 for +io_threads+
15
+ # since most programs are not heavily threaded. The rule of thumb
16
+ # is to make +io_threads+ equal to the number of application
17
+ # threads that will be accessing 0mq sockets within this context.
18
+ # The +io_threads+ number specifies the size of the thread pool
19
+ # allocated by 0mq for processing incoming/outgoing messages.
20
+ #
21
+ # Returns a context object. It's necessary for passing to the
22
+ # #Socket constructor when allocating new sockets. All sockets
23
+ # live within a context. Sockets in one context may not be accessed
24
+ # from another context; doing so raises an exception.
25
+ #
26
+ # To connect sockets between contexts, use +inproc+ or +ipc+
27
+ # transport and set up a 0mq socket between them.
28
+ #
29
+ # May raise a #ContextError.
30
+ #
31
+ def initialize io_threads
32
+ @sockets ||= []
33
+ @context = LibZMQ.zmq_init io_threads
34
+ @pointer = @context
35
+ error_check ZMQ_INIT_STR, @context.null? ? 1 : 0
36
+
37
+ define_finalizer
38
+ end
39
+
40
+ # Call to release the context and any remaining data associated
41
+ # with past sockets. This will close any sockets that remain
42
+ # open; further calls to those sockets will raise failure
43
+ # exceptions.
44
+ #
45
+ # Returns nil.
46
+ #
47
+ # May raise a #ContextError.
48
+ #
49
+ def terminate
50
+ unless @context.nil? || @context.null?
51
+ result_code = LibZMQ.zmq_term @context
52
+ error_check ZMQ_TERM_STR, result_code
53
+ @context = nil
54
+ @sockets = nil
55
+ remove_finalizer
56
+ end
57
+ nil
58
+ end
59
+
60
+ # Short-cut to allocate a socket for a specific context.
61
+ #
62
+ # Takes several +type+ values:
63
+ # #ZMQ::REQ
64
+ # #ZMQ::REP
65
+ # #ZMQ::PUB
66
+ # #ZMQ::SUB
67
+ # #ZMQ::PAIR
68
+ # #ZMQ::UPSTREAM
69
+ # #ZMQ::DOWNSTREAM
70
+ # #ZMQ::XREQ
71
+ # #ZMQ::XREP
72
+ #
73
+ # Returns a #ZMQ::Socket.
74
+ #
75
+ # May raise a #ContextError or #SocketError.
76
+ #
77
+ def socket type
78
+ sock = Socket.new @context, type
79
+ error_check ZMQ_SOCKET_STR, sock.nil? ? 1 : 0
80
+ sock
81
+ end
82
+
83
+
84
+ private
85
+
86
+ def define_finalizer
87
+ ObjectSpace.define_finalizer(self, self.class.close(@context))
88
+ end
89
+
90
+ def remove_finalizer
91
+ ObjectSpace.undefine_finalizer self
92
+ end
93
+
94
+ def self.close context
95
+ Proc.new { LibZMQ.zmq_term context unless context.null? }
96
+ end
97
+ end
98
+
99
+ end # module ZMQ
@@ -0,0 +1,145 @@
1
+
2
+ module ZMQ
3
+
4
+ class ZeroMQError < StandardError
5
+ attr_reader :source, :result_code, :error_code, :message
6
+
7
+ def initialize source, result_code, error_code, message
8
+ @source = source
9
+ @result_code = result_code
10
+ @error_code = error_code
11
+ @message = message
12
+ super message
13
+ end
14
+ end # call ZeroMQError
15
+
16
+
17
+ class ContextError < ZeroMQError
18
+ # True when the exception was raised due to the library
19
+ # returning EINVAL.
20
+ #
21
+ # Occurs when he number of app_threads requested is less
22
+ # than one, or the number of io_threads requested is
23
+ # negative.
24
+ #
25
+ def einval?() EINVAL == @error_code; end
26
+
27
+ # True when the exception was raised due to the library
28
+ # returning ETERM.
29
+ #
30
+ # The associated context was terminated.
31
+ #
32
+ def eterm?() ETERM == @error_code; end
33
+
34
+ end # class ContextError
35
+
36
+
37
+ class PollError < ZeroMQError
38
+ # True when the exception was raised due to the library
39
+ # returning EMTHREAD.
40
+ #
41
+ # At least one of the members of the items array refers
42
+ # to a socket belonging to a different application
43
+ # thread.
44
+ #
45
+ def efault?() EFAULT == @error_code; end
46
+
47
+ end # class PollError
48
+
49
+
50
+ class SocketError < ZeroMQError
51
+ # True when the exception was raised due to the library
52
+ # returning EMTHREAD.
53
+ #
54
+ # Occurs for #send and #recv operations.
55
+ # * When calling #send, non-blocking mode was requested
56
+ # and the message cannot be queued at the moment.
57
+ # * When calling #recv, non-blocking mode was requested
58
+ # and no messages are available at the moment.
59
+ #
60
+ def egain?() EAGAIN == @error_code; end
61
+
62
+ # True when the exception was raised due to the library
63
+ # returning ENOCOMPATPROTO.
64
+ #
65
+ # The requested transport protocol is not compatible
66
+ # with the socket type.
67
+ #
68
+ def enocompatproto?() ENOCOMPATPROTO == @error_code; end
69
+
70
+ # True when the exception was raised due to the library
71
+ # returning EPROTONOSUPPORT.
72
+ #
73
+ # The requested transport protocol is not supported.
74
+ #
75
+ def eprotonosupport?() EPROTONOSUPPORT == @error_code; end
76
+
77
+ # True when the exception was raised due to the library
78
+ # returning EADDRINUSE.
79
+ #
80
+ # The given address is already in use.
81
+ #
82
+ def eaddrinuse?() EADDRINUSE == @error_code; end
83
+
84
+ # True when the exception was raised due to the library
85
+ # returning EADDRNOTAVAIL.
86
+ #
87
+ # A nonexistent interface was requested or the
88
+ # requested address was not local.
89
+ #
90
+ def eaddrnotavail?() EADDRNOTAVAIL == @error_code; end
91
+
92
+ # True when the exception was raised due to the library
93
+ # returning EMTHREAD.
94
+ #
95
+ # Occurs under 2 conditions.
96
+ # * When creating a new #Socket, the requested socket
97
+ # type is invalid.
98
+ #
99
+ # * When setting socket options with #setsockopt, the
100
+ # requested option +option_name+ is unknown, or the
101
+ # requested +option_len+ or +option_value+ is invalid.
102
+ #
103
+ def einval?() EINVAL == @error_code; end
104
+
105
+ # True when the exception was raised due to the library
106
+ # returning EMTHREAD.
107
+ #
108
+ # The send or recv operation cannot be performed on this
109
+ # socket at the moment due to the socket not being in
110
+ # the appropriate state. This error may occur with socket
111
+ # types that switch between several states, such as ZMQ::REP.
112
+ #
113
+ def efsm?() EFSM == @error_code; end
114
+
115
+ # True when the exception was raised due to the library
116
+ # returning ENOTSUP.
117
+ #
118
+ # The send or recv operation is not supported by this socket
119
+ # type.
120
+ #
121
+ def enotsup?() super; end
122
+
123
+ # True when the exception was raised due to the library
124
+ # returning EMTHREAD.
125
+ #
126
+ # The number of application threads using sockets within
127
+ # this context has been exceeded. See the +app_threads+
128
+ # parameter of #Context.
129
+ #
130
+ def emthread?() EMTHREAD == @error_code; end
131
+
132
+ end # class SocketError
133
+
134
+
135
+ class MessageError < ZeroMQError
136
+ # True when the exception was raised due to the library
137
+ # returning ENOMEM.
138
+ #
139
+ # Only ever raised by the #Message class when it fails
140
+ # to allocate sufficient memory to send a message.
141
+ #
142
+ def enomem?() ENOMEM == @error_code; end
143
+ end
144
+
145
+ end # module ZMQ