ffi-rzmq 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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