ffi-rzmq 0.8.2 → 0.9.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.
Files changed (56) hide show
  1. data/AUTHORS.txt +1 -0
  2. data/History.txt +35 -0
  3. data/README.rdoc +48 -15
  4. data/Rakefile +7 -2
  5. data/examples/README.rdoc +21 -76
  6. data/examples/{local_lat.rb → v2api/local_lat.rb} +27 -12
  7. data/examples/v2api/local_lat_poll.rb +66 -0
  8. data/examples/{local_throughput.rb → v2api/local_throughput.rb} +24 -9
  9. data/examples/v2api/publish_subscribe.rb +82 -0
  10. data/examples/{remote_lat.rb → v2api/remote_lat.rb} +26 -8
  11. data/examples/v2api/remote_throughput.rb +39 -0
  12. data/examples/v2api/reqrep_poll.rb +62 -0
  13. data/examples/v2api/request_response.rb +40 -0
  14. data/examples/v2api/throughput_measurement.rb +138 -0
  15. data/examples/v3api/local_lat.rb +59 -0
  16. data/examples/v3api/local_lat_poll.rb +66 -0
  17. data/examples/v3api/local_throughput.rb +65 -0
  18. data/examples/v3api/publish_subscribe.rb +82 -0
  19. data/examples/v3api/remote_lat.rb +71 -0
  20. data/examples/v3api/remote_throughput.rb +47 -0
  21. data/examples/v3api/reqrep_poll.rb +62 -0
  22. data/examples/v3api/request_response.rb +40 -0
  23. data/examples/v3api/throughput_measurement.rb +166 -0
  24. data/ext/README +5 -0
  25. data/ffi-rzmq.gemspec +4 -4
  26. data/lib/ffi-rzmq.rb +4 -1
  27. data/lib/ffi-rzmq/constants.rb +178 -0
  28. data/lib/ffi-rzmq/context.rb +61 -45
  29. data/lib/ffi-rzmq/device.rb +22 -9
  30. data/lib/ffi-rzmq/exceptions.rb +0 -98
  31. data/lib/ffi-rzmq/libc.rb +19 -0
  32. data/lib/ffi-rzmq/libzmq.rb +188 -0
  33. data/lib/ffi-rzmq/message.rb +33 -40
  34. data/lib/ffi-rzmq/poll.rb +49 -52
  35. data/lib/ffi-rzmq/socket.rb +902 -392
  36. data/lib/ffi-rzmq/util.rb +101 -0
  37. data/spec/context_spec.rb +47 -21
  38. data/spec/device_spec.rb +78 -58
  39. data/spec/message_spec.rb +90 -12
  40. data/spec/multipart_spec.rb +162 -0
  41. data/spec/nonblocking_recv_spec.rb +325 -0
  42. data/spec/pushpull_spec.rb +95 -34
  43. data/spec/reqrep_spec.rb +55 -20
  44. data/spec/socket_spec.rb +353 -204
  45. data/spec/spec_helper.rb +46 -3
  46. data/version.txt +1 -1
  47. metadata +91 -66
  48. data/examples/local_lat_poll.rb +0 -54
  49. data/examples/local_lat_zerocopy.rb +0 -24
  50. data/examples/publish_subscribe.rb +0 -52
  51. data/examples/remote_lat_zerocopy.rb +0 -35
  52. data/examples/remote_throughput.rb +0 -27
  53. data/examples/reqrep_poll.rb +0 -49
  54. data/examples/request_response.rb +0 -23
  55. data/lib/ffi-rzmq/wrapper.rb +0 -121
  56. data/lib/ffi-rzmq/zmq.rb +0 -198
@@ -0,0 +1,40 @@
1
+
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
3
+
4
+
5
+ def assert(rc)
6
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
7
+ end
8
+
9
+ link = "tcp://127.0.0.1:5555"
10
+
11
+ begin
12
+ ctx = ZMQ::Context.new
13
+ s1 = ctx.socket(ZMQ::REQ)
14
+ s2 = ctx.socket(ZMQ::REP)
15
+ rescue ContextError => e
16
+ STDERR.puts "Failed to allocate context or socket"
17
+ raise
18
+ end
19
+
20
+ assert(s1.setsockopt(ZMQ::LINGER, 100))
21
+ assert(s2.setsockopt(ZMQ::LINGER, 100))
22
+
23
+ assert(s2.bind(link))
24
+ assert(s1.connect(link))
25
+
26
+ payload = "#{ '3' * 2048 }"
27
+ sent_msg = ZMQ::Message.new(payload)
28
+ received_msg = ZMQ::Message.new
29
+
30
+ assert(s1.sendmsg(sent_msg))
31
+ assert(s2.recvmsg(received_msg))
32
+
33
+ result = payload == received_msg.copy_out_string ? "Request received" : "Received wrong payload"
34
+
35
+ p result
36
+
37
+ assert(s1.close)
38
+ assert(s2.close)
39
+
40
+ ctx.terminate
@@ -0,0 +1,166 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
2
+ require 'thread'
3
+
4
+ # Within a single process, we start up five threads. Main thread has a PUB (publisher)
5
+ # socket and the secondary threads have SUB (subscription) sockets. We measure the
6
+ # *throughput* between these sockets. A high-water mark (HWM) is *not* set, so the
7
+ # publisher queue is free to grow to the size of memory without dropping packets.
8
+ #
9
+ # This example also illustrates how a single context can be shared amongst several
10
+ # threads. Sharing a single context also allows a user to specify the "inproc"
11
+ # transport in addition to "tcp" and "ipc".
12
+ #
13
+ # % ruby throughput_measurement.rb tcp://127.0.0.1:5555 1024 1_000_000
14
+ #
15
+ # % ruby throughput_measurement.rb inproc://lm_sock 1024 1_000_000
16
+ #
17
+
18
+ if ARGV.length < 3
19
+ puts "usage: ruby throughput_measurement.rb <connect-to> <message-size> <roundtrip-count>"
20
+ exit
21
+ end
22
+
23
+ link = ARGV[0]
24
+ message_size = ARGV[1].to_i
25
+ count = ARGV[2].to_i
26
+
27
+ def assert(rc)
28
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
29
+ end
30
+
31
+ begin
32
+ master_context = ZMQ::Context.new
33
+ rescue ContextError => e
34
+ STDERR.puts "Failed to allocate context or socket!"
35
+ raise
36
+ end
37
+
38
+
39
+ class Receiver
40
+ def initialize context, link, size, count, stats
41
+ @context = context
42
+ @link = link
43
+ @size = size
44
+ @count = count
45
+ @stats = stats
46
+
47
+ begin
48
+ @socket = @context.socket(ZMQ::SUB)
49
+ rescue ContextError => e
50
+ STDERR.puts "Failed to allocate SUB socket!"
51
+ raise
52
+ end
53
+
54
+ assert(@socket.setsockopt(ZMQ::LINGER, 100))
55
+ assert(@socket.setsockopt(ZMQ::SUBSCRIBE, ""))
56
+
57
+ assert(@socket.connect(@link))
58
+ end
59
+
60
+ def run
61
+ msg = ZMQ::Message.new
62
+ assert(@socket.recvmsg(msg))
63
+
64
+ elapsed = elapsed_microseconds do
65
+ (@count - 1).times do
66
+ assert(@socket.recvmsg(msg))
67
+ end
68
+ end
69
+
70
+ @stats.record_elapsed(elapsed)
71
+ assert(@socket.close)
72
+ end
73
+
74
+ def elapsed_microseconds(&blk)
75
+ start = Time.now
76
+ yield
77
+ ((Time.now - start) * 1_000_000)
78
+ end
79
+ end
80
+
81
+ class Transmitter
82
+ def initialize context, link, size, count
83
+ @context = context
84
+ @link = link
85
+ @size = size
86
+ @count = count
87
+
88
+ begin
89
+ @socket = @context.socket(ZMQ::PUB)
90
+ rescue ContextError => e
91
+ STDERR.puts "Failed to allocate PUB socket!"
92
+ raise
93
+ end
94
+
95
+ assert(@socket.setsockopt(ZMQ::LINGER, 100))
96
+ assert(@socket.bind(@link))
97
+ end
98
+
99
+ def run
100
+ sleep 1
101
+ contents = "#{'0' * @size}"
102
+
103
+ i = 0
104
+ while i < @count
105
+ msg = ZMQ::Message.new(contents)
106
+ assert(@socket.sendmsg(msg))
107
+ i += 1
108
+ end
109
+
110
+ end
111
+
112
+ def close
113
+ assert(@socket.close)
114
+ end
115
+ end
116
+
117
+ class Stats
118
+ def initialize size, count
119
+ @size = size
120
+ @count = count
121
+
122
+ @mutex = Mutex.new
123
+ @elapsed = []
124
+ end
125
+
126
+ def record_elapsed(elapsed)
127
+ @mutex.synchronize do
128
+ @elapsed << elapsed
129
+ end
130
+ end
131
+
132
+ def output
133
+ @elapsed.each do |elapsed|
134
+ throughput = @count * 1000000 / elapsed
135
+ megabits = throughput * @size * 8 / 1000000
136
+
137
+ puts "message size: %i [B]" % @size
138
+ puts "message count: %i" % @count
139
+ puts "mean throughput: %i [msg/s]" % throughput
140
+ puts "mean throughput: %.3f [Mb/s]" % megabits
141
+ puts
142
+ end
143
+ end
144
+ end
145
+
146
+ threads = []
147
+ stats = Stats.new message_size, count
148
+ transmitter = Transmitter.new(master_context, link, message_size, count)
149
+
150
+ threads << Thread.new do
151
+ transmitter.run
152
+ end
153
+
154
+ 1.times do
155
+ threads << Thread.new do
156
+ receiver = Receiver.new(master_context, link, message_size, count, stats)
157
+ receiver.run
158
+ end
159
+ end
160
+
161
+
162
+ threads.each {|t| t.join}
163
+ transmitter.close
164
+ stats.output
165
+
166
+ master_context.terminate
@@ -0,0 +1,5 @@
1
+ To avoid loading a system-wide 0mq library, place
2
+ the C libraries here. This let's you run your Ruby
3
+ code with a 0mq C library build that is different
4
+ from the system-wide one. This can be handy for
5
+ rolling upgrades or testing.
@@ -2,24 +2,24 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{ffi-rzmq}
5
- s.version = "0.8.2"
5
+ s.version = "0.9.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{2011-01-30}
9
+ s.date = %q{2011-09-14}
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
13
  MRI 1.9.x, Rubinius and JRuby.}
14
14
  s.email = %q{cremes@mac.com}
15
15
  s.extra_rdoc_files = ["AUTHORS.txt", "History.txt", "README.rdoc", "examples/README.rdoc", "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"]
16
+ s.files = [".bnsignore", "History.txt", "README.rdoc", "Rakefile", "examples/README.rdoc", "examples/v2api/local_lat.rb", "examples/v2api/local_lat_poll.rb", "examples/v2api/local_throughput.rb", "examples/v2api/publish_subscribe.rb", "examples/v2api/remote_lat.rb", "examples/v2api/remote_throughput.rb", "examples/v2api/reqrep_poll.rb", "examples/v2api/request_response.rb", "examples/v2api/throughput_measurement.rb", "examples/v3api/local_lat.rb", "examples/v3api/local_lat_poll.rb", "examples/v3api/local_throughput.rb", "examples/v3api/publish_subscribe.rb", "examples/v3api/remote_lat.rb", "examples/v3api/remote_throughput.rb", "examples/v3api/reqrep_poll.rb", "examples/v3api/request_response.rb", "examples/v3api/throughput_measurement.rb", "ext/README", "ffi-rzmq.gemspec", "lib/ffi-rzmq.rb", "lib/ffi-rzmq/constants.rb", "lib/ffi-rzmq/context.rb", "lib/ffi-rzmq/device.rb", "lib/ffi-rzmq/exceptions.rb", "lib/ffi-rzmq/libc.rb", "lib/ffi-rzmq/libzmq.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/util.rb", "spec/context_spec.rb", "spec/device_spec.rb", "spec/message_spec.rb", "spec/multipart_spec.rb", "spec/nonblocking_recv_spec.rb", "spec/pushpull_spec.rb", "spec/reqrep_spec.rb", "spec/socket_spec.rb", "spec/spec_helper.rb", "version.txt"]
17
17
  s.homepage = %q{http://github.com/chuckremes/ffi-rzmq}
18
18
  s.rdoc_options = ["--main", "README.rdoc"]
19
19
  s.require_paths = ["lib"]
20
20
  s.rubyforge_project = %q{ffi-rzmq}
21
21
  s.rubygems_version = %q{1.3.7}
22
- s.summary = %q{This gem wraps the ZeroMQ networking library using the ruby FFI (foreign function interface).}
22
+ s.summary = %q{This gem wraps the ZeroMQ (0mq) networking library using Ruby FFI (foreign function interface).}
23
23
 
24
24
  if s.respond_to? :specification_version then
25
25
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -66,7 +66,10 @@ end # module ZMQ
66
66
 
67
67
  RBX = defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ ? true : false
68
68
 
69
+ require 'ffi' unless RBX
70
+
69
71
  # the order of files is important
70
- %w(wrapper zmq exceptions context message socket poll_items poll device).each do |file|
72
+ #%w(wrapper zmq exceptions context message socket poll_items poll device).each do |file|
73
+ %w(libc libzmq constants util exceptions context message socket poll_items poll device).each do |file|
71
74
  require ZMQ.libpath(['ffi-rzmq', file])
72
75
  end
@@ -0,0 +1,178 @@
1
+ module ZMQ
2
+ # Set up all of the constants that are *common* to all API
3
+ # versions
4
+
5
+ # Socket types
6
+ PAIR = 0
7
+ PUB = 1
8
+ SUB = 2
9
+ REQ = 3
10
+ REP = 4
11
+ XREQ = 5
12
+ XREP = 6
13
+ PULL = 7
14
+ PUSH = 8
15
+
16
+ SocketTypeNameMap = {
17
+ PAIR => "PAIR",
18
+ PUB => "PUB",
19
+ SUB => "SUB",
20
+ REQ => "REQ",
21
+ REP => "REP",
22
+ PULL => "PULL",
23
+ PUSH => "PUSH",
24
+ XREQ => "XREQ",
25
+ XREP => "XREP"
26
+ }
27
+
28
+ # Socket options
29
+ AFFINITY = 4
30
+ SUBSCRIBE = 6
31
+ UNSUBSCRIBE = 7
32
+ RATE = 8
33
+ RECOVERY_IVL = 9
34
+ SNDBUF = 11
35
+ RCVBUF = 12
36
+ RCVMORE = 13
37
+ FD = 14
38
+ EVENTS = 15
39
+ TYPE = 16
40
+ LINGER = 17
41
+ RECONNECT_IVL = 18
42
+ BACKLOG = 19
43
+ RECONNECT_IVL_MAX = 21
44
+
45
+ # Send/recv options
46
+ SNDMORE = 2
47
+
48
+ # I/O multiplexing
49
+
50
+ POLL = 1
51
+ POLLIN = 1
52
+ POLLOUT = 2
53
+ POLLERR = 4
54
+
55
+ # Socket errors
56
+ EAGAIN = Errno::EAGAIN::Errno
57
+ EINVAL = Errno::EINVAL::Errno
58
+ ENOMEM = Errno::ENOMEM::Errno
59
+ ENODEV = Errno::ENODEV::Errno
60
+ EFAULT = Errno::EFAULT::Errno
61
+
62
+ # ZMQ errors
63
+ HAUSNUMERO = 156384712
64
+ EMTHREAD = (HAUSNUMERO + 50)
65
+ EFSM = (HAUSNUMERO + 51)
66
+ ENOCOMPATPROTO = (HAUSNUMERO + 52)
67
+ ETERM = (HAUSNUMERO + 53)
68
+
69
+ # Rescue unknown constants and use the ZeroMQ defined values
70
+ # Usually only happens on Windows though some don't resolve on
71
+ # OSX too (ENOTSUP)
72
+ ENOTSUP = Errno::ENOTSUP::Errno rescue (HAUSNUMERO + 1)
73
+ EPROTONOSUPPORT = Errno::EPROTONOSUPPORT::Errno rescue (HAUSNUMERO + 2)
74
+ ENOBUFS = Errno::ENOBUFS::Errno rescue (HAUSNUMERO + 3)
75
+ ENETDOWN = Errno::ENETDOWN::Errno rescue (HAUSNUMERO + 4)
76
+ EADDRINUSE = Errno::EADDRINUSE::Errno rescue (HAUSNUMERO + 5)
77
+ EADDRNOTAVAIL = Errno::EADDRNOTAVAIL::Errno rescue (HAUSNUMERO + 6)
78
+ ECONNREFUSED = Errno::ECONNREFUSED::Errno rescue (HAUSNUMERO + 7)
79
+ EINPROGRESS = Errno::EINPROGRESS::Errno rescue (HAUSNUMERO + 8)
80
+ ENOTSOCK = Errno::ENOTSOCK::Errno rescue (HAUSNUMERO + 9)
81
+ EINTR = Errno::EINTR::Errno rescue (HAUSNUMERO + 10)
82
+ end # module ZMQ
83
+
84
+
85
+ if LibZMQ.version2?
86
+ module ZMQ
87
+ # Socket types
88
+ UPSTREAM = PULL
89
+ DOWNSTREAM = PUSH
90
+ DEALER = XREQ
91
+ ROUTER = XREP
92
+
93
+ SocketTypeNameMap[ROUTER] = 'ROUTER'
94
+ SocketTypeNameMap[DEALER] = 'DEALER'
95
+
96
+ # Device Types
97
+ STREAMER = 1
98
+ FORWARDER = 2
99
+ QUEUE = 3
100
+
101
+ # Socket options
102
+ HWM = 1
103
+ IDENTITY = 5
104
+ MCAST_LOOP = 10
105
+ SWAP = 3
106
+ RECOVERY_IVL_MSEC = 20
107
+
108
+ # Send/recv options
109
+ NOBLOCK = 1
110
+ end
111
+ end # version2?
112
+
113
+
114
+ if LibZMQ.version3?
115
+ module ZMQ
116
+ # Socket types
117
+ XPUB = 9
118
+ XSUB = 10
119
+ ROUTER = 11
120
+ DEALER = 12
121
+
122
+ SocketTypeNameMap[ROUTER] = 'ROUTER'
123
+ SocketTypeNameMap[DEALER] = 'DEALER'
124
+ SocketTypeNameMap[XPUB] = 'XPUB'
125
+ SocketTypeNameMap[XSUB] = 'XSUB'
126
+
127
+ # Socket options
128
+ IDENTITY = 5
129
+ MAXMSGSIZE = 22
130
+ SNDHWM = 23
131
+ RCVHWM = 24
132
+ MULTICAST_HOPS = 25
133
+ RCVTIMEO = 27
134
+ SNDTIMEO = 28
135
+ RCVLABEL = 29
136
+
137
+ # Send/recv options
138
+ DONTWAIT = 1
139
+ SNDLABEL = 4
140
+
141
+
142
+ # Socket & other errors
143
+ EMFILE = Errno::EMFILE::Errno
144
+
145
+ end
146
+ end # version3?
147
+
148
+
149
+ if LibZMQ.version4?
150
+ module ZMQ
151
+ # Socket types
152
+ XPUB = 9
153
+ XSUB = 10
154
+ ROUTER = 13
155
+
156
+ SocketTypeNameMap[ROUTER] = 'ROUTER'
157
+ SocketTypeNameMap[XPUB] = 'XPUB'
158
+ SocketTypeNameMap[XSUB] = 'XSUB'
159
+
160
+ # Socket options
161
+ MAXMSGSIZE = 22
162
+ SNDHWM = 23
163
+ RCVHWM = 24
164
+ MULTICAST_HOPS = 25
165
+ RCVTIMEO = 27
166
+ SNDTIMEO = 28
167
+ RCVLABEL = 29
168
+
169
+ # Send/recv options
170
+ DONTWAIT = 1
171
+ SNDLABEL = 4
172
+
173
+
174
+ # Socket & other errors
175
+ EMFILE = Errno::EMFILE::Errno
176
+
177
+ end
178
+ end # version4?
@@ -1,70 +1,82 @@
1
1
 
2
2
  module ZMQ
3
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
4
 
5
+ # Recommended to use the default for +io_threads+
6
+ # since most programs will not saturate I/O.
7
+ #
8
+ # The rule of thumb is to make +io_threads+ equal to the number
9
+ # gigabits per second that the application will produce.
10
+ #
11
+ # The +io_threads+ number specifies the size of the thread pool
12
+ # allocated by 0mq for processing incoming/outgoing messages.
13
+ #
14
+ # Returns a context object when allocation succeeds. It's necessary
15
+ # for passing to the
16
+ # #Socket constructor when allocating new sockets. All sockets
17
+ # live within a context.
18
+ #
19
+ # Also, Sockets should *only* be accessed from the thread where they
20
+ # were first created. Do *not* pass sockets between threads; pass
21
+ # in the context and allocate a new socket per thread. If you must
22
+ # use threads, then make sure to execute a full memory barrier (e.g.
23
+ # mutex) as you pass a socket from one thread to the next.
24
+ #
25
+ # To connect sockets between contexts, use +inproc+ or +ipc+
26
+ # transport and set up a 0mq socket between them. This is also the
27
+ # recommended technique for allowing sockets to communicate between
28
+ # threads.
29
+ #
30
+ # context = ZMQ::Context.create
31
+ # if context
32
+ # socket = context.socket(ZMQ::REQ)
33
+ # if socket
34
+ # ...
35
+ # else
36
+ # STDERR.puts "Socket allocation failed"
37
+ # end
38
+ # else
39
+ # STDERR.puts "Context allocation failed"
40
+ # end
41
+ #
42
+ #
9
43
  class Context
10
44
  include ZMQ::Util
11
45
 
12
46
  attr_reader :context, :pointer
13
47
 
14
- # Recommended to use the default for +io_threads+
15
- # since most programs will not saturate I/O.
16
- #
17
- # The rule of thumb is to make +io_threads+ equal to the number
18
- # gigabits per second that the application will produce.
19
- #
20
- # The +io_threads+ number specifies the size of the thread pool
21
- # allocated by 0mq for processing incoming/outgoing messages.
22
- #
23
- # Returns a context object. It's necessary for passing to the
24
- # #Socket constructor when allocating new sockets. All sockets
25
- # live within a context. Sockets in one context may not be accessed
26
- # from another context; doing so raises an exception.
27
- #
28
- # Also, Sockets should *only* be accessed from the thread where they
29
- # were first created. Do *not* pass sockets between threads; pass
30
- # in the context and allocate a new socket per thread.
31
- #
32
- # To connect sockets between contexts, use +inproc+ or +ipc+
33
- # transport and set up a 0mq socket between them. This is also the
34
- # recommended technique for allowing sockets to communicate between
35
- # threads.
36
- #
37
- # Will raise a #ContextError when the native library context cannot be
38
- # be allocated.
48
+ def self.create io_threads = 1
49
+ new(io_threads) rescue nil
50
+ end
51
+
52
+ # Use the factory method Context#create to make contexts.
39
53
  #
40
54
  def initialize io_threads = 1
41
55
  @sockets = []
42
56
  @context = LibZMQ.zmq_init io_threads
43
57
  @pointer = @context
44
- error_check ZMQ_INIT_STR, (@context.nil? || @context.null?) ? 1 : 0
58
+ error_check 'zmq_init', (@context.nil? || @context.null?) ? -1 : 0
45
59
 
46
60
  define_finalizer
47
61
  end
48
62
 
49
63
  # Call to release the context and any remaining data associated
50
64
  # with past sockets. This will close any sockets that remain
51
- # open; further calls to those sockets will raise failure
52
- # exceptions.
53
- #
54
- # Returns nil.
65
+ # open; further calls to those sockets will return -1 to indicate
66
+ # the operation failed.
55
67
  #
56
- # Will raise a #ContextError when the call fails. Failures occur when
57
- # the context has somehow become null (indicates a libzmq bug).
68
+ # Returns 0 for success, -1 for failure.
58
69
  #
59
70
  def terminate
60
71
  unless @context.nil? || @context.null?
61
- result_code = LibZMQ.zmq_term @context
62
- error_check ZMQ_TERM_STR, result_code
72
+ remove_finalizer
73
+ rc = LibZMQ.zmq_term @context
63
74
  @context = nil
64
75
  @sockets = nil
65
- remove_finalizer
76
+ rc
77
+ else
78
+ 0
66
79
  end
67
- nil
68
80
  end
69
81
 
70
82
  # Short-cut to allocate a socket for a specific context.
@@ -80,13 +92,17 @@ module ZMQ
80
92
  # #ZMQ::DEALER
81
93
  # #ZMQ::ROUTER
82
94
  #
83
- # Returns a #ZMQ::Socket.
84
- #
85
- # May raise a #ContextError or #SocketError.
95
+ # Returns a #ZMQ::Socket when the allocation succeeds, nil
96
+ # if it fails.
86
97
  #
87
98
  def socket type
88
- sock = Socket.new @context, type
89
- error_check ZMQ_SOCKET_STR, sock.nil? ? 1 : 0
99
+ sock = nil
100
+ begin
101
+ sock = Socket.new @context, type
102
+ rescue ContextError => e
103
+ sock = nil
104
+ end
105
+
90
106
  sock
91
107
  end
92
108