ffi-rxs 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/AUTHORS.txt +21 -0
- data/Gemfile +3 -0
- data/README.rdoc +86 -0
- data/Rakefile +6 -0
- data/ext/README +5 -0
- data/ffi-rxs.gemspec +25 -0
- data/lib/ffi-rxs/constants.rb +104 -0
- data/lib/ffi-rxs/constants.rb~ +100 -0
- data/lib/ffi-rxs/context.rb +153 -0
- data/lib/ffi-rxs/context.rb~ +155 -0
- data/lib/ffi-rxs/device.rb~ +28 -0
- data/lib/ffi-rxs/exceptions.rb +47 -0
- data/lib/ffi-rxs/exceptions.rb~ +47 -0
- data/lib/ffi-rxs/libc.rb +19 -0
- data/lib/ffi-rxs/libc.rb~ +19 -0
- data/lib/ffi-rxs/libxs.rb +156 -0
- data/lib/ffi-rxs/libxs.rb~ +156 -0
- data/lib/ffi-rxs/message.rb +282 -0
- data/lib/ffi-rxs/message.rb~ +282 -0
- data/lib/ffi-rxs/poll.rb +212 -0
- data/lib/ffi-rxs/poll.rb~ +212 -0
- data/lib/ffi-rxs/poll_items.rb +120 -0
- data/lib/ffi-rxs/poll_items.rb~ +120 -0
- data/lib/ffi-rxs/socket.rb +659 -0
- data/lib/ffi-rxs/socket.rb~ +659 -0
- data/lib/ffi-rxs/util.rb +105 -0
- data/lib/ffi-rxs/util.rb~ +105 -0
- data/lib/ffi-rxs/version.rb +3 -0
- data/lib/ffi-rxs/version.rb~ +3 -0
- data/lib/ffi-rxs.rb +74 -0
- data/spec/context_spec.rb +138 -0
- data/spec/message_spec.rb +128 -0
- data/spec/multipart_spec.rb +108 -0
- data/spec/nonblocking_recv_spec.rb +309 -0
- data/spec/poll_spec.rb +168 -0
- data/spec/pushpull_spec.rb +113 -0
- data/spec/reqrep_spec.rb +66 -0
- data/spec/socket_spec.rb +496 -0
- data/spec/spec_helper.rb +57 -0
- metadata +126 -0
data/.gitignore
ADDED
data/AUTHORS.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Chuck Remes, github: chuckremes
|
2
|
+
|
3
|
+
Andrew Cholakian, github: andrewvc
|
4
|
+
|
5
|
+
Ar Vicco, github: arvicco
|
6
|
+
|
7
|
+
Ben Mabey, github: bmabey
|
8
|
+
|
9
|
+
Julien Ammous, github: schmurfy
|
10
|
+
|
11
|
+
Zachary Belzer, github: zbelzer
|
12
|
+
|
13
|
+
Cory Forsyth, github: bantic
|
14
|
+
|
15
|
+
Stefan Kaes, github: skaes
|
16
|
+
|
17
|
+
Dmitry Ustalov, github: eveel
|
18
|
+
|
19
|
+
Patrik Sundberg, github: sundbp
|
20
|
+
|
21
|
+
Chris Duncan, github: celldee
|
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
ffi-rxs
|
2
|
+
by Chris Duncan
|
3
|
+
|
4
|
+
== DESCRIPTION:
|
5
|
+
|
6
|
+
This gem wraps the Crossroads I/O networking library using the Ruby FFI (foreign
|
7
|
+
function interface). It's a pure Ruby wrapper so this gem can be loaded
|
8
|
+
and run by any Ruby runtime that supports FFI. That's all of them:
|
9
|
+
MRI 1.9.x, Rubinius and JRuby.
|
10
|
+
|
11
|
+
Crossroads I/O is a fork of ZeroMQ. This gem is a re-working of the ffi-rzmq gem
|
12
|
+
created by Chuck Remes to provide bindings for the Crossroads I/O libxs C library
|
13
|
+
instead of the ZeroMQ libzmq library. The gem auto-configures itself to expose
|
14
|
+
the API conforming to the loaded C library.
|
15
|
+
|
16
|
+
== FEATURES/PROBLEMS:
|
17
|
+
|
18
|
+
This gem needs to be tested in the wild. Please kick its tyres and give it a
|
19
|
+
good thrashing. It is inevitable that bugs will be discovered, so please open
|
20
|
+
issues for them here or fork this project, fix them, and send me a pull
|
21
|
+
request.
|
22
|
+
|
23
|
+
The 'ffi' gem has dropped support for MRI 1.8.x. Since this project relies
|
24
|
+
on that gem to load and run this code, then this project does not support
|
25
|
+
MRI 1.8.x. I recommend JRuby for the best performance and stability.
|
26
|
+
|
27
|
+
== REQUIREMENTS:
|
28
|
+
|
29
|
+
* Crossroads I/O version 1.0.0 or later.
|
30
|
+
|
31
|
+
The Crossroads I/O library must be installed on your system in a well-known location
|
32
|
+
like /usr/local/lib. This is the default for new Crossroads I/O installs.
|
33
|
+
|
34
|
+
Future releases may include the library as a C extension built at
|
35
|
+
time of installation.
|
36
|
+
|
37
|
+
* ffi (>= 1.0.0)
|
38
|
+
|
39
|
+
Do *not* run this gem under MRI with an old 'ffi' gem. It will crash randomly and
|
40
|
+
you will be sad.
|
41
|
+
|
42
|
+
== INSTALL:
|
43
|
+
|
44
|
+
A full gem has been released to Rubygems.org as of release 1.0.0.
|
45
|
+
Make sure the Crossroads I/O library is already installed on your system.
|
46
|
+
|
47
|
+
% gem install ffi-rxs # should grab the latest release
|
48
|
+
|
49
|
+
|
50
|
+
To build from git master:
|
51
|
+
|
52
|
+
% git clone git://github.com/celldee/ffi-rxs
|
53
|
+
% cd ffi-rxs
|
54
|
+
% gem build ffi-rxs.gemspec
|
55
|
+
% gem install ffi-rxs-*.gem
|
56
|
+
|
57
|
+
|
58
|
+
NOTE for Windows users!
|
59
|
+
In order for this gem to find the libxs.dll, it *must* be on the Windows PATH. Google
|
60
|
+
for "modify windows path" for instructions on how to do that if you are unfamiliar with
|
61
|
+
that activity.
|
62
|
+
|
63
|
+
== LICENSE:
|
64
|
+
|
65
|
+
(The MIT License)
|
66
|
+
|
67
|
+
Copyright (c) 2011 - 2012 Chuck Remes, Chris Duncan and contributors
|
68
|
+
|
69
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
70
|
+
a copy of this software and associated documentation files (the
|
71
|
+
'Software'), to deal in the Software without restriction, including
|
72
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
73
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
74
|
+
permit persons to whom the Software is furnished to do so, subject to
|
75
|
+
the following conditions:
|
76
|
+
|
77
|
+
The above copyright notice and this permission notice shall be
|
78
|
+
included in all copies or substantial portions of the Software.
|
79
|
+
|
80
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
81
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
82
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
83
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
84
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
85
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
86
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/ext/README
ADDED
data/ffi-rxs.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ffi-rxs/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ffi-rxs"
|
7
|
+
s.version = XS::VERSION
|
8
|
+
s.authors = ["Chris Duncan"]
|
9
|
+
s.email = ["celldee@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/celldee/ffi-rxs"
|
11
|
+
s.summary = %q{This gem wraps the Crossroads I/O networking library using Ruby FFI (foreign function interface).}
|
12
|
+
s.description = %q{This gem wraps the Crossroads I/O networking library using the ruby FFI (foreign
|
13
|
+
function interface). It's a pure ruby wrapper so this gem can be loaded
|
14
|
+
and run by any ruby runtime that supports FFI. That's all of them:
|
15
|
+
MRI 1.9.x, Rubinius and JRuby.}
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_runtime_dependency "ffi"
|
23
|
+
s.add_development_dependency "rspec", ["~> 2.6"]
|
24
|
+
s.add_development_dependency "rake"
|
25
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module XS
|
2
|
+
# Set up all of the constants
|
3
|
+
|
4
|
+
# Context options
|
5
|
+
MAX_SOCKETS = 1
|
6
|
+
IO_THREADS = 2
|
7
|
+
|
8
|
+
# Socket types
|
9
|
+
PAIR = 0
|
10
|
+
PUB = 1
|
11
|
+
SUB = 2
|
12
|
+
REQ = 3
|
13
|
+
REP = 4
|
14
|
+
XREQ = 5
|
15
|
+
XREP = 6
|
16
|
+
PULL = 7
|
17
|
+
PUSH = 8
|
18
|
+
XPUB = 9
|
19
|
+
XSUB = 10
|
20
|
+
DEALER = XREQ
|
21
|
+
ROUTER = XREP
|
22
|
+
|
23
|
+
SocketTypeNameMap = {
|
24
|
+
PAIR => "PAIR",
|
25
|
+
PUB => "PUB",
|
26
|
+
SUB => "SUB",
|
27
|
+
REQ => "REQ",
|
28
|
+
REP => "REP",
|
29
|
+
PULL => "PULL",
|
30
|
+
PUSH => "PUSH",
|
31
|
+
XREQ => "XREQ",
|
32
|
+
XREP => "XREP",
|
33
|
+
ROUTER => "ROUTER",
|
34
|
+
DEALER => "DEALER",
|
35
|
+
XPUB => "XPUB",
|
36
|
+
XSUB => "XSUB"
|
37
|
+
}
|
38
|
+
|
39
|
+
# Socket options
|
40
|
+
AFFINITY = 4
|
41
|
+
IDENTITY = 5
|
42
|
+
SUBSCRIBE = 6
|
43
|
+
UNSUBSCRIBE = 7
|
44
|
+
RATE = 8
|
45
|
+
RECOVERY_IVL = 9
|
46
|
+
SNDBUF = 11
|
47
|
+
RCVBUF = 12
|
48
|
+
RCVMORE = 13
|
49
|
+
FD = 14
|
50
|
+
EVENTS = 15
|
51
|
+
TYPE = 16
|
52
|
+
LINGER = 17
|
53
|
+
RECONNECT_IVL = 18
|
54
|
+
BACKLOG = 19
|
55
|
+
RECONNECT_IVL_MAX = 21
|
56
|
+
MAXMSGSIZE = 22
|
57
|
+
SNDHWM = 23
|
58
|
+
RCVHWM = 24
|
59
|
+
MULTICAST_HOPS = 25
|
60
|
+
RCVTIMEO = 27
|
61
|
+
SNDTIMEO = 28
|
62
|
+
|
63
|
+
# Send/recv options
|
64
|
+
DONTWAIT = 1
|
65
|
+
SNDMORE = 2
|
66
|
+
SNDLABEL = 4
|
67
|
+
NonBlocking = DONTWAIT
|
68
|
+
|
69
|
+
# I/O multiplexing
|
70
|
+
|
71
|
+
POLL = 1
|
72
|
+
POLLIN = 1
|
73
|
+
POLLOUT = 2
|
74
|
+
POLLERR = 4
|
75
|
+
|
76
|
+
# Socket errors
|
77
|
+
EAGAIN = Errno::EAGAIN::Errno
|
78
|
+
EFAULT = Errno::EFAULT::Errno
|
79
|
+
EINVAL = Errno::EINVAL::Errno
|
80
|
+
EMFILE = Errno::EMFILE::Errno
|
81
|
+
ENOMEM = Errno::ENOMEM::Errno
|
82
|
+
ENODEV = Errno::ENODEV::Errno
|
83
|
+
|
84
|
+
# XS errors
|
85
|
+
HAUSNUMERO = 156384712
|
86
|
+
EMTHREAD = (HAUSNUMERO + 50)
|
87
|
+
EFSM = (HAUSNUMERO + 51)
|
88
|
+
ENOCOMPATPROTO = (HAUSNUMERO + 52)
|
89
|
+
ETERM = (HAUSNUMERO + 53)
|
90
|
+
|
91
|
+
# Rescue unknown constants and use the Crossroads defined values
|
92
|
+
# Usually only happens on Windows though some don't resolve on
|
93
|
+
# OSX too (ENOTSUP)
|
94
|
+
ENOTSUP = Errno::ENOTSUP::Errno rescue (HAUSNUMERO + 1)
|
95
|
+
EPROTONOSUPPORT = Errno::EPROTONOSUPPORT::Errno rescue (HAUSNUMERO + 2)
|
96
|
+
ENOBUFS = Errno::ENOBUFS::Errno rescue (HAUSNUMERO + 3)
|
97
|
+
ENETDOWN = Errno::ENETDOWN::Errno rescue (HAUSNUMERO + 4)
|
98
|
+
EADDRINUSE = Errno::EADDRINUSE::Errno rescue (HAUSNUMERO + 5)
|
99
|
+
EADDRNOTAVAIL = Errno::EADDRNOTAVAIL::Errno rescue (HAUSNUMERO + 6)
|
100
|
+
ECONNREFUSED = Errno::ECONNREFUSED::Errno rescue (HAUSNUMERO + 7)
|
101
|
+
EINPROGRESS = Errno::EINPROGRESS::Errno rescue (HAUSNUMERO + 8)
|
102
|
+
ENOTSOCK = Errno::ENOTSOCK::Errno rescue (HAUSNUMERO + 9)
|
103
|
+
EINTR = Errno::EINTR::Errno rescue (HAUSNUMERO + 10)
|
104
|
+
end # module XS
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module XS
|
2
|
+
# Set up all of the constants
|
3
|
+
|
4
|
+
# Socket types
|
5
|
+
PAIR = 0
|
6
|
+
PUB = 1
|
7
|
+
SUB = 2
|
8
|
+
REQ = 3
|
9
|
+
REP = 4
|
10
|
+
XREQ = 5
|
11
|
+
XREP = 6
|
12
|
+
PULL = 7
|
13
|
+
PUSH = 8
|
14
|
+
XPUB = 9
|
15
|
+
XSUB = 10
|
16
|
+
DEALER = XREQ
|
17
|
+
ROUTER = XREP
|
18
|
+
|
19
|
+
SocketTypeNameMap = {
|
20
|
+
PAIR => "PAIR",
|
21
|
+
PUB => "PUB",
|
22
|
+
SUB => "SUB",
|
23
|
+
REQ => "REQ",
|
24
|
+
REP => "REP",
|
25
|
+
PULL => "PULL",
|
26
|
+
PUSH => "PUSH",
|
27
|
+
XREQ => "XREQ",
|
28
|
+
XREP => "XREP",
|
29
|
+
ROUTER => "ROUTER",
|
30
|
+
DEALER => "DEALER",
|
31
|
+
XPUB => "XPUB",
|
32
|
+
XSUB => "XSUB"
|
33
|
+
}
|
34
|
+
|
35
|
+
# Socket options
|
36
|
+
AFFINITY = 4
|
37
|
+
IDENTITY = 5
|
38
|
+
SUBSCRIBE = 6
|
39
|
+
UNSUBSCRIBE = 7
|
40
|
+
RATE = 8
|
41
|
+
RECOVERY_IVL = 9
|
42
|
+
SNDBUF = 11
|
43
|
+
RCVBUF = 12
|
44
|
+
RCVMORE = 13
|
45
|
+
FD = 14
|
46
|
+
EVENTS = 15
|
47
|
+
TYPE = 16
|
48
|
+
LINGER = 17
|
49
|
+
RECONNECT_IVL = 18
|
50
|
+
BACKLOG = 19
|
51
|
+
RECONNECT_IVL_MAX = 21
|
52
|
+
MAXMSGSIZE = 22
|
53
|
+
SNDHWM = 23
|
54
|
+
RCVHWM = 24
|
55
|
+
MULTICAST_HOPS = 25
|
56
|
+
RCVTIMEO = 27
|
57
|
+
SNDTIMEO = 28
|
58
|
+
|
59
|
+
# Send/recv options
|
60
|
+
DONTWAIT = 1
|
61
|
+
SNDMORE = 2
|
62
|
+
SNDLABEL = 4
|
63
|
+
NonBlocking = DONTWAIT
|
64
|
+
|
65
|
+
# I/O multiplexing
|
66
|
+
|
67
|
+
POLL = 1
|
68
|
+
POLLIN = 1
|
69
|
+
POLLOUT = 2
|
70
|
+
POLLERR = 4
|
71
|
+
|
72
|
+
# Socket errors
|
73
|
+
EAGAIN = Errno::EAGAIN::Errno
|
74
|
+
EFAULT = Errno::EFAULT::Errno
|
75
|
+
EINVAL = Errno::EINVAL::Errno
|
76
|
+
EMFILE = Errno::EMFILE::Errno
|
77
|
+
ENOMEM = Errno::ENOMEM::Errno
|
78
|
+
ENODEV = Errno::ENODEV::Errno
|
79
|
+
|
80
|
+
# XS errors
|
81
|
+
HAUSNUMERO = 156384712
|
82
|
+
EMTHREAD = (HAUSNUMERO + 50)
|
83
|
+
EFSM = (HAUSNUMERO + 51)
|
84
|
+
ENOCOMPATPROTO = (HAUSNUMERO + 52)
|
85
|
+
ETERM = (HAUSNUMERO + 53)
|
86
|
+
|
87
|
+
# Rescue unknown constants and use the Crossroads defined values
|
88
|
+
# Usually only happens on Windows though some don't resolve on
|
89
|
+
# OSX too (ENOTSUP)
|
90
|
+
ENOTSUP = Errno::ENOTSUP::Errno rescue (HAUSNUMERO + 1)
|
91
|
+
EPROTONOSUPPORT = Errno::EPROTONOSUPPORT::Errno rescue (HAUSNUMERO + 2)
|
92
|
+
ENOBUFS = Errno::ENOBUFS::Errno rescue (HAUSNUMERO + 3)
|
93
|
+
ENETDOWN = Errno::ENETDOWN::Errno rescue (HAUSNUMERO + 4)
|
94
|
+
EADDRINUSE = Errno::EADDRINUSE::Errno rescue (HAUSNUMERO + 5)
|
95
|
+
EADDRNOTAVAIL = Errno::EADDRNOTAVAIL::Errno rescue (HAUSNUMERO + 6)
|
96
|
+
ECONNREFUSED = Errno::ECONNREFUSED::Errno rescue (HAUSNUMERO + 7)
|
97
|
+
EINPROGRESS = Errno::EINPROGRESS::Errno rescue (HAUSNUMERO + 8)
|
98
|
+
ENOTSOCK = Errno::ENOTSOCK::Errno rescue (HAUSNUMERO + 9)
|
99
|
+
EINTR = Errno::EINTR::Errno rescue (HAUSNUMERO + 10)
|
100
|
+
end # module XS
|
@@ -0,0 +1,153 @@
|
|
1
|
+
|
2
|
+
module XS
|
3
|
+
|
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 Crossroads socket between them. This is also the
|
27
|
+
# recommended technique for allowing sockets to communicate between
|
28
|
+
# threads.
|
29
|
+
#
|
30
|
+
# context = XS::Context.create
|
31
|
+
# if context
|
32
|
+
# socket = context.socket(XS::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
|
+
#
|
43
|
+
class Context
|
44
|
+
include XS::Util
|
45
|
+
|
46
|
+
attr_reader :context, :pointer
|
47
|
+
|
48
|
+
def self.create
|
49
|
+
new() rescue nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# Use the factory method Context#create to make contexts.
|
53
|
+
#
|
54
|
+
def initialize
|
55
|
+
@sockets = []
|
56
|
+
@context = LibXS.xs_init()
|
57
|
+
@pointer = @context
|
58
|
+
error_check 'xs_init', (@context.nil? || @context.null?) ? -1 : 0
|
59
|
+
|
60
|
+
define_finalizer
|
61
|
+
end
|
62
|
+
|
63
|
+
# Set options on this context.
|
64
|
+
#
|
65
|
+
# Context options take effect only if set with setctxopt() prior to
|
66
|
+
# creating the first socket in a given context with socket().
|
67
|
+
#
|
68
|
+
# Valid +name+ values that take a numeric +value+ are:
|
69
|
+
# XS::IO_THREADS
|
70
|
+
# XS::MAX_SOCKETS
|
71
|
+
#
|
72
|
+
# Returns 0 when the operation completed successfully.
|
73
|
+
# Returns -1 when this operation failed.
|
74
|
+
#
|
75
|
+
# With a -1 return code, the user must check XS.errno to determine the
|
76
|
+
# cause.
|
77
|
+
#
|
78
|
+
# rc = context.setctxopt(XS::IO_THREADS, 10)
|
79
|
+
# XS::Util.resultcode_ok?(rc) ? puts("succeeded") : puts("failed")
|
80
|
+
#
|
81
|
+
def setctxopt name, value, length = nil
|
82
|
+
length = 4
|
83
|
+
pointer = LibC.malloc length
|
84
|
+
pointer.write_int value
|
85
|
+
|
86
|
+
rc = LibXS.xs_setctxopt @context, name, pointer, length
|
87
|
+
LibC.free(pointer) unless pointer.nil? || pointer.null?
|
88
|
+
rc
|
89
|
+
end
|
90
|
+
|
91
|
+
# Call to release the context and any remaining data associated
|
92
|
+
# with past sockets. This will close any sockets that remain
|
93
|
+
# open; further calls to those sockets will return -1 to indicate
|
94
|
+
# the operation failed.
|
95
|
+
#
|
96
|
+
# Returns 0 for success, -1 for failure.
|
97
|
+
#
|
98
|
+
def terminate
|
99
|
+
unless @context.nil? || @context.null?
|
100
|
+
remove_finalizer
|
101
|
+
rc = LibXS.xs_term @context
|
102
|
+
@context = nil
|
103
|
+
@sockets = nil
|
104
|
+
rc
|
105
|
+
else
|
106
|
+
0
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Short-cut to allocate a socket for a specific context.
|
111
|
+
#
|
112
|
+
# Takes several +type+ values:
|
113
|
+
# #XS::REQ
|
114
|
+
# #XS::REP
|
115
|
+
# #XS::PUB
|
116
|
+
# #XS::SUB
|
117
|
+
# #XS::PAIR
|
118
|
+
# #XS::PULL
|
119
|
+
# #XS::PUSH
|
120
|
+
# #XS::DEALER
|
121
|
+
# #XS::ROUTER
|
122
|
+
#
|
123
|
+
# Returns a #XS::Socket when the allocation succeeds, nil
|
124
|
+
# if it fails.
|
125
|
+
#
|
126
|
+
def socket type
|
127
|
+
sock = nil
|
128
|
+
begin
|
129
|
+
sock = Socket.new @context, type
|
130
|
+
rescue ContextError => e
|
131
|
+
sock = nil
|
132
|
+
end
|
133
|
+
|
134
|
+
sock
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def define_finalizer
|
141
|
+
ObjectSpace.define_finalizer(self, self.class.close(@context))
|
142
|
+
end
|
143
|
+
|
144
|
+
def remove_finalizer
|
145
|
+
ObjectSpace.undefine_finalizer self
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.close context
|
149
|
+
Proc.new { LibXS.xs_term context unless context.null? }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end # module XS
|
@@ -0,0 +1,155 @@
|
|
1
|
+
|
2
|
+
module XS
|
3
|
+
|
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 Crossroads socket between them. This is also the
|
27
|
+
# recommended technique for allowing sockets to communicate between
|
28
|
+
# threads.
|
29
|
+
#
|
30
|
+
# context = XS::Context.create
|
31
|
+
# if context
|
32
|
+
# socket = context.socket(XS::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
|
+
#
|
43
|
+
class Context
|
44
|
+
include XS::Util
|
45
|
+
|
46
|
+
attr_reader :context, :pointer
|
47
|
+
|
48
|
+
def self.create
|
49
|
+
new() rescue nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# Use the factory method Context#create to make contexts.
|
53
|
+
#
|
54
|
+
def initialize
|
55
|
+
@sockets = []
|
56
|
+
@context = LibXS.xs_init()
|
57
|
+
@pointer = @context
|
58
|
+
error_check 'xs_init', (@context.nil? || @context.null?) ? -1 : 0
|
59
|
+
|
60
|
+
define_finalizer
|
61
|
+
end
|
62
|
+
|
63
|
+
# Set options on this context.
|
64
|
+
#
|
65
|
+
# Context options take effect only if set with setctxopt() prior to
|
66
|
+
# creating the first socket in a given context with socket().
|
67
|
+
#
|
68
|
+
# Valid +name+ values that take a numeric +value+ are:
|
69
|
+
# XS::IO_THREADS
|
70
|
+
# XS::MAX_SOCKETS
|
71
|
+
#
|
72
|
+
# Returns 0 when the operation completed successfully.
|
73
|
+
# Returns -1 when this operation failed.
|
74
|
+
#
|
75
|
+
# With a -1 return code, the user must check XS.errno to determine the
|
76
|
+
# cause.
|
77
|
+
#
|
78
|
+
# rc = context.setctxopt(XS::IO_THREADS, 10)
|
79
|
+
# XS::Util.resultcode_ok?(rc) ? puts("succeeded") : puts("failed")
|
80
|
+
#
|
81
|
+
def setctxopt name, value, length = nil
|
82
|
+
#if (name == XS::IO_THREADS) || (name == XS::MAX_SOCKETS)
|
83
|
+
length = 4
|
84
|
+
pointer = LibC.malloc length
|
85
|
+
pointer.write_int value
|
86
|
+
#end
|
87
|
+
|
88
|
+
rc = LibXS.xs_setctxopt @context, name, pointer, length
|
89
|
+
LibC.free(pointer) unless pointer.nil? || pointer.null?
|
90
|
+
rc
|
91
|
+
end
|
92
|
+
|
93
|
+
# Call to release the context and any remaining data associated
|
94
|
+
# with past sockets. This will close any sockets that remain
|
95
|
+
# open; further calls to those sockets will return -1 to indicate
|
96
|
+
# the operation failed.
|
97
|
+
#
|
98
|
+
# Returns 0 for success, -1 for failure.
|
99
|
+
#
|
100
|
+
def terminate
|
101
|
+
unless @context.nil? || @context.null?
|
102
|
+
remove_finalizer
|
103
|
+
rc = LibXS.xs_term @context
|
104
|
+
@context = nil
|
105
|
+
@sockets = nil
|
106
|
+
rc
|
107
|
+
else
|
108
|
+
0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Short-cut to allocate a socket for a specific context.
|
113
|
+
#
|
114
|
+
# Takes several +type+ values:
|
115
|
+
# #XS::REQ
|
116
|
+
# #XS::REP
|
117
|
+
# #XS::PUB
|
118
|
+
# #XS::SUB
|
119
|
+
# #XS::PAIR
|
120
|
+
# #XS::PULL
|
121
|
+
# #XS::PUSH
|
122
|
+
# #XS::DEALER
|
123
|
+
# #XS::ROUTER
|
124
|
+
#
|
125
|
+
# Returns a #XS::Socket when the allocation succeeds, nil
|
126
|
+
# if it fails.
|
127
|
+
#
|
128
|
+
def socket type
|
129
|
+
sock = nil
|
130
|
+
begin
|
131
|
+
sock = Socket.new @context, type
|
132
|
+
rescue ContextError => e
|
133
|
+
sock = nil
|
134
|
+
end
|
135
|
+
|
136
|
+
sock
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def define_finalizer
|
143
|
+
ObjectSpace.define_finalizer(self, self.class.close(@context))
|
144
|
+
end
|
145
|
+
|
146
|
+
def remove_finalizer
|
147
|
+
ObjectSpace.undefine_finalizer self
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.close context
|
151
|
+
Proc.new { LibXS.xs_term context unless context.null? }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end # module XS
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ZMQ
|
2
|
+
if LibZMQ.version2?
|
3
|
+
class Device
|
4
|
+
attr_reader :device
|
5
|
+
|
6
|
+
def self.create(device_type, frontend, backend)
|
7
|
+
dev = nil
|
8
|
+
begin
|
9
|
+
dev = new device_type, frontend, backend
|
10
|
+
rescue ArgumentError
|
11
|
+
dev = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
dev
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(device_type,frontend,backend)
|
18
|
+
[["frontend", frontend],["backend", backend]].each do |name,socket|
|
19
|
+
unless socket.is_a?(ZMQ::Socket)
|
20
|
+
raise ArgumentError, "Expected a ZMQ::Socket, not a #{socket.class} as the #{name}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
LibZMQ.zmq_device(device_type, frontend.socket, backend.socket)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|