ffi-rxs 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +10 -0
- data/.yardopts +9 -0
- data/CHANGELOG +11 -0
- data/LICENSE +20 -0
- data/README.textile +86 -0
- data/examples/LICENSE +18 -0
- data/examples/README +2 -0
- data/examples/durable_pub.rb +34 -0
- data/examples/durable_sub.rb +29 -0
- data/examples/latency_measurement.rb +140 -0
- data/examples/reply.rb +25 -0
- data/examples/req_rep_poll.rb +71 -0
- data/examples/request.rb +24 -0
- data/examples/task_sink.rb +31 -0
- data/examples/task_vent.rb +34 -0
- data/examples/task_worker.rb +36 -0
- data/examples/throughput_measurement.rb +169 -0
- data/examples/weather_upd_client.rb +47 -0
- data/examples/weather_upd_server.rb +35 -0
- data/examples/xreq_xrep_poll.rb +101 -0
- data/ffi-rxs.gemspec +3 -5
- data/lib/ffi-rxs/constants.rb +15 -11
- data/lib/ffi-rxs/context.rb +54 -60
- data/lib/ffi-rxs/exceptions.rb +7 -5
- data/lib/ffi-rxs/libc.rb +1 -0
- data/lib/ffi-rxs/libxs.rb +2 -0
- data/lib/ffi-rxs/message.rb +79 -50
- data/lib/ffi-rxs/poll.rb +54 -12
- data/lib/ffi-rxs/poll_items.rb +2 -1
- data/lib/ffi-rxs/socket.rb +243 -184
- data/lib/ffi-rxs/util.rb +25 -16
- data/lib/ffi-rxs/version.rb +3 -1
- data/lib/ffi-rxs.rb +8 -14
- data/spec/socket_spec.rb +63 -0
- metadata +31 -19
- data/README.rdoc +0 -86
data/lib/ffi-rxs/message.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
|
2
3
|
module XS
|
3
4
|
|
@@ -28,71 +29,76 @@ module XS
|
|
28
29
|
# When you are done using a *received* message object, call #close to
|
29
30
|
# release the associated buffers.
|
30
31
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
32
|
+
# @example
|
33
|
+
# received_message = Message.create
|
34
|
+
# if received_message
|
35
|
+
# rc = socket.recvmsg(received_message)
|
36
|
+
# if XS::Util.resultcode_ok?(rc)
|
37
|
+
# puts "Message contained: #{received_message.copy_out_string}"
|
38
|
+
# else
|
39
|
+
# STDERR.puts "Error when receiving message: #{XS::Util.error_string}"
|
40
|
+
# end
|
39
41
|
#
|
42
|
+
# @example Define a custom layout for the data sent between Crossroads peers
|
43
|
+
# class MyMessage
|
44
|
+
# class Layout < FFI::Struct
|
45
|
+
# layout :value1, :uint8,
|
46
|
+
# :value2, :uint64,
|
47
|
+
# :value3, :uint32,
|
48
|
+
# :value4, [:char, 30]
|
49
|
+
# end
|
40
50
|
#
|
41
|
-
#
|
51
|
+
# def initialize msg_struct = nil
|
52
|
+
# if msg_struct
|
53
|
+
# @msg_t = msg_struct
|
54
|
+
# @data = Layout.new(@msg_t.data)
|
55
|
+
# else
|
56
|
+
# @pointer = FFI::MemoryPointer.new :byte, Layout.size, true
|
57
|
+
# @data = Layout.new @pointer
|
58
|
+
# end
|
59
|
+
# end
|
42
60
|
#
|
43
|
-
#
|
44
|
-
# class Layout < FFI::Struct
|
45
|
-
# layout :value1, :uint8,
|
46
|
-
# :value2, :uint64,
|
47
|
-
# :value3, :uint32,
|
48
|
-
# :value4, [:char, 30]
|
49
|
-
# end
|
61
|
+
# def size() @size = @msg_t.size; end
|
50
62
|
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
# @data = Layout.new(@msg_t.data)
|
55
|
-
# else
|
56
|
-
# @pointer = FFI::MemoryPointer.new :byte, Layout.size, true
|
57
|
-
# @data = Layout.new @pointer
|
58
|
-
# end
|
59
|
-
# end
|
63
|
+
# def value1
|
64
|
+
# @data[:value1]
|
65
|
+
# end
|
60
66
|
#
|
61
|
-
#
|
67
|
+
# def value4
|
68
|
+
# @data[:value4].to_ptr.read_string
|
69
|
+
# end
|
62
70
|
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
71
|
+
# def value1=(val)
|
72
|
+
# @data[:value1] = val
|
73
|
+
# end
|
66
74
|
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
75
|
+
# def create_sendable_message
|
76
|
+
# msg = Message.new
|
77
|
+
# msg.copy_in_bytes @pointer, Layout.size
|
78
|
+
# end
|
79
|
+
# end
|
70
80
|
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# def create_sendable_message
|
76
|
-
# msg = Message.new
|
77
|
-
# msg.copy_in_bytes @pointer, Layout.size
|
78
|
-
# end
|
79
|
-
#
|
80
|
-
#
|
81
|
-
# message = Message.new
|
82
|
-
# successful_read = socket.recv message
|
83
|
-
# message = MyMessage.new message if successful_read
|
84
|
-
# puts "value1 is #{message.value1}"
|
81
|
+
# message = Message.new
|
82
|
+
# successful_read = socket.recv message
|
83
|
+
# message = MyMessage.new message if successful_read
|
84
|
+
# puts "value1 is #{message.value1}"
|
85
85
|
#
|
86
86
|
class Message
|
87
87
|
include XS::Util
|
88
88
|
|
89
|
-
# Recommended way to create a standard message.
|
90
|
-
# returned upon success, nil when allocation fails.
|
89
|
+
# Recommended way to create a standard message.
|
91
90
|
#
|
91
|
+
# @param message (optional)
|
92
|
+
#
|
93
|
+
# @return [Message] upon success
|
94
|
+
# @return nil when allocation fails
|
92
95
|
def self.create message = nil
|
93
96
|
new(message) rescue nil
|
94
97
|
end
|
95
98
|
|
99
|
+
# Initialize object
|
100
|
+
#
|
101
|
+
# @param message (optional)
|
96
102
|
def initialize message = nil
|
97
103
|
# allocate our own pointer so that we can tell it to *not* zero out
|
98
104
|
# the memory; it's pointless work since the library is going to
|
@@ -114,6 +120,7 @@ module XS
|
|
114
120
|
#
|
115
121
|
# Can only be initialized via #copy_in_string or #copy_in_bytes once.
|
116
122
|
#
|
123
|
+
# @param string
|
117
124
|
def copy_in_string string
|
118
125
|
string_size = string.respond_to?(:bytesize) ? string.bytesize : string.size
|
119
126
|
copy_in_bytes string, string_size if string
|
@@ -124,6 +131,8 @@ module XS
|
|
124
131
|
#
|
125
132
|
# Can only be initialized via #copy_in_string or #copy_in_bytes once.
|
126
133
|
#
|
134
|
+
# @param bytes
|
135
|
+
# @param length
|
127
136
|
def copy_in_bytes bytes, len
|
128
137
|
data_buffer = LibC.malloc len
|
129
138
|
# writes the exact number of bytes, no null byte to terminate string
|
@@ -138,22 +147,26 @@ module XS
|
|
138
147
|
# Provides the memory address of the +xs_msg_t+ struct. Used mostly for
|
139
148
|
# passing to other methods accessing the underlying library that
|
140
149
|
# require a real data address.
|
141
|
-
#
|
142
150
|
def address
|
143
151
|
@pointer
|
144
152
|
end
|
145
153
|
alias :pointer :address
|
146
154
|
|
155
|
+
# Copy content of message to another message
|
156
|
+
#
|
157
|
+
# @param source
|
147
158
|
def copy source
|
148
159
|
LibXS.xs_msg_copy @pointer, source
|
149
160
|
end
|
150
161
|
|
162
|
+
# Move content of message to another message
|
163
|
+
#
|
164
|
+
# @param source
|
151
165
|
def move source
|
152
166
|
LibXS.xs_msg_move @pointer, source
|
153
167
|
end
|
154
168
|
|
155
169
|
# Provides the size of the data buffer for this +xs_msg_t+ C struct.
|
156
|
-
#
|
157
170
|
def size
|
158
171
|
LibXS.xs_msg_size @pointer
|
159
172
|
end
|
@@ -163,6 +176,7 @@ module XS
|
|
163
176
|
# when the +message+ object goes out of scope and gets garbage
|
164
177
|
# collected.
|
165
178
|
#
|
179
|
+
# @return pointer
|
166
180
|
def data
|
167
181
|
LibXS.xs_msg_data @pointer
|
168
182
|
end
|
@@ -171,6 +185,7 @@ module XS
|
|
171
185
|
#
|
172
186
|
# Note: If this is binary data, it won't print very prettily.
|
173
187
|
#
|
188
|
+
# @return string
|
174
189
|
def copy_out_string
|
175
190
|
data.read_string(size)
|
176
191
|
end
|
@@ -181,6 +196,8 @@ module XS
|
|
181
196
|
# Only releases the buffer a single time. Subsequent calls are
|
182
197
|
# no ops.
|
183
198
|
#
|
199
|
+
# @return 0 if successful
|
200
|
+
# @return -1 if unsuccessful
|
184
201
|
def close
|
185
202
|
rc = 0
|
186
203
|
|
@@ -196,6 +213,7 @@ module XS
|
|
196
213
|
# each new instance
|
197
214
|
@msg_size = LibXS::Msg.size
|
198
215
|
|
216
|
+
# Store the message size
|
199
217
|
def self.msg_size() @msg_size; end
|
200
218
|
|
201
219
|
end # class Message
|
@@ -231,6 +249,11 @@ module XS
|
|
231
249
|
# Makes a copy of +len+ bytes from the ruby string +bytes+. Library
|
232
250
|
# handles deallocation of the native memory buffer.
|
233
251
|
#
|
252
|
+
# @param bytes
|
253
|
+
# @param length
|
254
|
+
#
|
255
|
+
# @return 0 if successful
|
256
|
+
# @return -1 if unsuccessful
|
234
257
|
def copy_in_bytes bytes, len
|
235
258
|
rc = super(bytes, len)
|
236
259
|
|
@@ -243,6 +266,8 @@ module XS
|
|
243
266
|
# Manually release the message struct and its associated data
|
244
267
|
# buffer.
|
245
268
|
#
|
269
|
+
# @return 0 if successful
|
270
|
+
# @return -1 if unsuccessful
|
246
271
|
def close
|
247
272
|
rc = super()
|
248
273
|
remove_finalizer
|
@@ -252,10 +277,12 @@ module XS
|
|
252
277
|
|
253
278
|
private
|
254
279
|
|
280
|
+
# Deletes native resources after object has been destroyed
|
255
281
|
def define_finalizer
|
256
282
|
ObjectSpace.define_finalizer(self, self.class.close(@pointer))
|
257
283
|
end
|
258
284
|
|
285
|
+
# Removes all finalizers for object
|
259
286
|
def remove_finalizer
|
260
287
|
ObjectSpace.undefine_finalizer self
|
261
288
|
end
|
@@ -265,6 +292,8 @@ module XS
|
|
265
292
|
# This is intentional. Since this code runs as a finalizer, there is no
|
266
293
|
# way to catch a raised exception anywhere near where the error actually
|
267
294
|
# occurred in the code, so we just ignore deallocation failures here.
|
295
|
+
#
|
296
|
+
# @param pointer
|
268
297
|
def self.close ptr
|
269
298
|
Proc.new do
|
270
299
|
# release the data buffer
|
data/lib/ffi-rxs/poll.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
|
2
3
|
module XS
|
3
4
|
|
@@ -28,16 +29,14 @@ module XS
|
|
28
29
|
# this possible condition (via #size) and throttle the call
|
29
30
|
# frequency.
|
30
31
|
#
|
31
|
-
#
|
32
|
-
# or writable.
|
33
|
-
#
|
34
|
-
# Return 1 (or greater) to indicate the number of readable or writable
|
35
|
-
# sockets. These sockets should be processed using the #readables and
|
36
|
-
# #writables accessors.
|
32
|
+
# @param timeout
|
37
33
|
#
|
38
|
-
#
|
34
|
+
# @return 0 when there are no readable/writeable registered sockets
|
35
|
+
# @return number to indicate the number of readable or writable sockets
|
36
|
+
# @return -1 when there is an error
|
37
|
+
|
38
|
+
# When return code -1 use XS::Util.errno to get the related
|
39
39
|
# error number.
|
40
|
-
#
|
41
40
|
def poll timeout = :blocking
|
42
41
|
unless @items.empty?
|
43
42
|
timeout = adjust timeout
|
@@ -56,9 +55,9 @@ module XS
|
|
56
55
|
# The non-blocking version of #poll. See the #poll description for
|
57
56
|
# potential exceptions.
|
58
57
|
#
|
59
|
-
#
|
60
|
-
# to determine the underlying cause.
|
58
|
+
# @return -1 when an error is encountered.
|
61
59
|
#
|
60
|
+
# When return code -1 check XS::Util.errno to determine the underlying cause.
|
62
61
|
def poll_nonblock
|
63
62
|
poll 0
|
64
63
|
end
|
@@ -68,6 +67,12 @@ module XS
|
|
68
67
|
# will only get registered at most once. Calling multiple times with
|
69
68
|
# different values for +events+ will OR the event information together.
|
70
69
|
#
|
70
|
+
# @param socket
|
71
|
+
# @param events
|
72
|
+
# One of @XS::POLLIN@ and @XS::POLLOUT@
|
73
|
+
#
|
74
|
+
# @return true if successful
|
75
|
+
# @return false if not
|
71
76
|
def register sock, events = XS::POLLIN | XS::POLLOUT, fd = 0
|
72
77
|
return false if (sock.nil? && fd.zero?) || events.zero?
|
73
78
|
|
@@ -76,7 +81,6 @@ module XS
|
|
76
81
|
unless item
|
77
82
|
@sockets << sock
|
78
83
|
item = LibXS::PollItem.new
|
79
|
-
|
80
84
|
if sock.kind_of?(XS::Socket) || sock.kind_of?(Socket)
|
81
85
|
item[:socket] = sock.socket
|
82
86
|
item[:fd] = 0
|
@@ -95,6 +99,12 @@ module XS
|
|
95
99
|
# Deregister the +sock+ for +events+. When there are no events left,
|
96
100
|
# this also deletes the socket from the poll items.
|
97
101
|
#
|
102
|
+
# @param socket
|
103
|
+
# @param events
|
104
|
+
# One of @XS::POLLIN@ and @XS::POLLOUT@
|
105
|
+
#
|
106
|
+
# @return true if successful
|
107
|
+
# @return false if not
|
98
108
|
def deregister sock, events, fd = 0
|
99
109
|
return unless sock || !fd.zero?
|
100
110
|
|
@@ -113,24 +123,40 @@ module XS
|
|
113
123
|
|
114
124
|
# A helper method to register a +sock+ as readable events only.
|
115
125
|
#
|
126
|
+
# @param socket
|
127
|
+
#
|
128
|
+
# @return true if successful
|
129
|
+
# @return false if not
|
116
130
|
def register_readable sock
|
117
131
|
register sock, XS::POLLIN, 0
|
118
132
|
end
|
119
133
|
|
120
134
|
# A helper method to register a +sock+ for writable events only.
|
121
135
|
#
|
136
|
+
# @param socket
|
137
|
+
#
|
138
|
+
# @return true if successful
|
139
|
+
# @return false if not
|
122
140
|
def register_writable sock
|
123
141
|
register sock, XS::POLLOUT, 0
|
124
142
|
end
|
125
143
|
|
126
144
|
# A helper method to deregister a +sock+ for readable events.
|
127
145
|
#
|
146
|
+
# @param socket
|
147
|
+
#
|
148
|
+
# @return true if successful
|
149
|
+
# @return false if not
|
128
150
|
def deregister_readable sock
|
129
151
|
deregister sock, XS::POLLIN, 0
|
130
152
|
end
|
131
153
|
|
132
154
|
# A helper method to deregister a +sock+ for writable events.
|
133
155
|
#
|
156
|
+
# @param socket
|
157
|
+
#
|
158
|
+
# @return true if successful
|
159
|
+
# @return false if not
|
134
160
|
def deregister_writable sock
|
135
161
|
deregister sock, XS::POLLOUT, 0
|
136
162
|
end
|
@@ -142,6 +168,10 @@ module XS
|
|
142
168
|
# Can also be called directly to remove the socket from the polling
|
143
169
|
# array.
|
144
170
|
#
|
171
|
+
# @param socket
|
172
|
+
#
|
173
|
+
# @return true if successful
|
174
|
+
# @return false if not
|
145
175
|
def delete sock
|
146
176
|
unless (size = @sockets.size).zero?
|
147
177
|
@sockets.delete_if { |socket| socket.socket.address == sock.socket.address }
|
@@ -158,23 +188,32 @@ module XS
|
|
158
188
|
end
|
159
189
|
end
|
160
190
|
|
191
|
+
# Convenience method to return size of items array
|
161
192
|
def size(); @items.size; end
|
162
193
|
|
194
|
+
# Convenience method to inspect items array
|
163
195
|
def inspect
|
164
196
|
@items.inspect
|
165
197
|
end
|
166
198
|
|
199
|
+
# Convenience method to inspect poller
|
167
200
|
def to_s(); inspect; end
|
168
201
|
|
169
202
|
|
170
203
|
private
|
171
204
|
|
205
|
+
# Create hash of items
|
206
|
+
#
|
207
|
+
# @param empty hash
|
208
|
+
#
|
209
|
+
# @return hash
|
172
210
|
def items_hash hash
|
173
211
|
@items.each do |poll_item|
|
174
212
|
hash[@raw_to_socket[poll_item.socket.address]] = poll_item
|
175
213
|
end
|
176
214
|
end
|
177
215
|
|
216
|
+
# Update readables and writeables
|
178
217
|
def update_selectables
|
179
218
|
@readables.clear
|
180
219
|
@writables.clear
|
@@ -199,7 +238,10 @@ module XS
|
|
199
238
|
# Users will pass in values measured as
|
200
239
|
# milliseconds, so we need to convert that value to
|
201
240
|
# microseconds for the library.
|
202
|
-
|
241
|
+
#
|
242
|
+
# @param timeout
|
243
|
+
#
|
244
|
+
# @return number
|
203
245
|
def adjust timeout
|
204
246
|
if :blocking == timeout || -1 == timeout
|
205
247
|
-1
|
data/lib/ffi-rxs/poll_items.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
|
2
3
|
module XS
|
3
4
|
class PollItems
|
@@ -22,7 +23,7 @@ module XS
|
|
22
23
|
unless @items.empty? || index.nil?
|
23
24
|
clean
|
24
25
|
|
25
|
-
# pointer arithmetic in ruby
|
26
|
+
# pointer arithmetic in ruby
|
26
27
|
pointer = @store + (@element_size * index)
|
27
28
|
|
28
29
|
# cast the memory to a PollItem
|