nanomsg 0.2.0 → 0.3.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.
- data/HISTORY +6 -1
- data/examples/aborting.rb +75 -0
- data/ext/init.c +67 -62
- data/ext/mkmf.log +22 -0
- metadata +4 -5
- data/ext/constants.o +0 -0
- data/ext/init.o +0 -0
- data/ext/nanomsg.bundle +0 -0
data/HISTORY
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
+
= 0.3 / 4Sept2013
|
1
2
|
|
2
|
-
|
3
|
+
* Fixes GVL related blocking behaviour, recv/send will now _NOT_ consume
|
4
|
+
a whole core.
|
5
|
+
* Adds a raw setsockopt that allows settting various types of values.
|
6
|
+
|
7
|
+
= 0.2 / 26Aug2013
|
3
8
|
|
4
9
|
* Adds REQ/REP socket type (ReqSocket, RepSocket).
|
5
10
|
* Adds PUB/SUB socket type.
|
@@ -0,0 +1,75 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + "/../lib"
|
2
|
+
require 'nanomsg'
|
3
|
+
include NanoMsg
|
4
|
+
|
5
|
+
class AbortBehaviourChecker
|
6
|
+
attr_reader :t
|
7
|
+
attr_reader :q, :p
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@q, @p = PairSocket.new, PairSocket.new
|
11
|
+
@adr = 'tcp://127.0.0.1:4000'
|
12
|
+
|
13
|
+
@q.bind(@adr)
|
14
|
+
@p.connect(@adr)
|
15
|
+
|
16
|
+
@q.setsockopt(NanoMsg::NN_SOL_SOCKET, NanoMsg::NN_RCVTIMEO, 5000)
|
17
|
+
end
|
18
|
+
|
19
|
+
def run_recv_thread
|
20
|
+
@t = Thread.start {
|
21
|
+
begin
|
22
|
+
@q.recv
|
23
|
+
rescue NanoMsg::Errno::EAGAIN
|
24
|
+
puts "EAGAIN"
|
25
|
+
# Gets raised when the read operation times out after 5 seconds
|
26
|
+
end
|
27
|
+
}
|
28
|
+
@t.abort_on_exception = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def kill
|
32
|
+
@t.kill
|
33
|
+
end
|
34
|
+
def join
|
35
|
+
s = Time.now
|
36
|
+
@t.join
|
37
|
+
Time.now - s
|
38
|
+
end
|
39
|
+
|
40
|
+
def send msg
|
41
|
+
@p.send msg
|
42
|
+
end
|
43
|
+
def recv
|
44
|
+
@q.recv
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# ------------------------------------------------- NN_RCVTIMEO behaviour test
|
50
|
+
|
51
|
+
abc = AbortBehaviourChecker.new
|
52
|
+
s = Time.now
|
53
|
+
|
54
|
+
abc.run_recv_thread
|
55
|
+
|
56
|
+
# During these first 10 seconds, CPU usage needs to stay low, since we're
|
57
|
+
# just waiting for a message to come in.
|
58
|
+
loop do
|
59
|
+
p abc.t
|
60
|
+
sleep 1
|
61
|
+
break if Time.now - s > 7
|
62
|
+
end
|
63
|
+
|
64
|
+
# -------------------------------------------------------- kill behaviour test
|
65
|
+
|
66
|
+
# Resets the EAGAIN behaviour
|
67
|
+
abc.send 'test'
|
68
|
+
p abc.recv
|
69
|
+
|
70
|
+
abc.run_recv_thread
|
71
|
+
abc.kill
|
72
|
+
|
73
|
+
puts "Joining..."
|
74
|
+
t = abc.join.round
|
75
|
+
puts "Join took #{t} seconds."
|
data/ext/init.c
CHANGED
@@ -77,6 +77,20 @@ sock_get(VALUE socket)
|
|
77
77
|
return psock->socket;
|
78
78
|
}
|
79
79
|
|
80
|
+
static int
|
81
|
+
nn_get_rcv_fd(int sock)
|
82
|
+
{
|
83
|
+
int fd;
|
84
|
+
size_t size = sizeof(fd);
|
85
|
+
int err;
|
86
|
+
|
87
|
+
err = nn_getsockopt(sock, NN_SOL_SOCKET, NN_RCVFD, &fd, &size);
|
88
|
+
if (err < 0)
|
89
|
+
return err;
|
90
|
+
|
91
|
+
return fd;
|
92
|
+
}
|
93
|
+
|
80
94
|
static VALUE
|
81
95
|
sock_alloc(VALUE klass)
|
82
96
|
{
|
@@ -145,36 +159,18 @@ struct ioop {
|
|
145
159
|
int sock;
|
146
160
|
char* buffer;
|
147
161
|
long len;
|
148
|
-
int abort;
|
149
162
|
};
|
150
163
|
|
151
164
|
static VALUE
|
152
|
-
|
165
|
+
sock_send_blocking(void* data)
|
153
166
|
{
|
154
167
|
struct ioop *pio = data;
|
155
168
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
// get stuck in an endless loop when the socket is just not answering.
|
160
|
-
|
161
|
-
while (pio->nn_errno == EAGAIN && !pio->abort) {
|
162
|
-
pio->return_code = nn_send(pio->sock, pio->buffer, pio->len, NN_DONTWAIT /* flags */);
|
163
|
-
|
164
|
-
if (pio->return_code < 0)
|
165
|
-
pio->nn_errno = nn_errno();
|
166
|
-
else
|
167
|
-
break;
|
168
|
-
}
|
169
|
-
|
170
|
-
return Qnil;
|
171
|
-
}
|
169
|
+
pio->return_code = nn_send(pio->sock, pio->buffer, pio->len, 0 /* flags */);
|
170
|
+
if (pio->return_code < 0)
|
171
|
+
pio->nn_errno = nn_errno();
|
172
172
|
|
173
|
-
|
174
|
-
sock_send_abort(void* data)
|
175
|
-
{
|
176
|
-
struct ioop *pio = data;
|
177
|
-
pio->abort = Qtrue;
|
173
|
+
return Qnil;
|
178
174
|
}
|
179
175
|
|
180
176
|
static VALUE
|
@@ -183,17 +179,10 @@ sock_send(VALUE socket, VALUE buffer)
|
|
183
179
|
struct ioop io;
|
184
180
|
|
185
181
|
io.sock = sock_get(socket);
|
186
|
-
io.nn_errno = EAGAIN;
|
187
182
|
io.buffer = StringValuePtr(buffer);
|
188
183
|
io.len = RSTRING_LEN(buffer);
|
189
|
-
io.abort = Qfalse;
|
190
|
-
|
191
|
-
rb_thread_blocking_region(sock_send_no_gvl, &io, sock_send_abort, &io);
|
192
184
|
|
193
|
-
|
194
|
-
// leaving Ruby to handle the abort.
|
195
|
-
if (io.abort)
|
196
|
-
return Qnil;
|
185
|
+
rb_thread_blocking_region(sock_send_blocking, &io, RUBY_UBF_IO, 0);
|
197
186
|
|
198
187
|
if (io.return_code < 0)
|
199
188
|
sock_raise_error(io.nn_errno);
|
@@ -202,35 +191,18 @@ sock_send(VALUE socket, VALUE buffer)
|
|
202
191
|
}
|
203
192
|
|
204
193
|
static VALUE
|
205
|
-
|
194
|
+
sock_recv_blocking(void* data)
|
206
195
|
{
|
207
196
|
struct ioop *pio = data;
|
208
197
|
|
209
|
-
|
210
|
-
// 'socket gone away' (=EAGAIN) and 'socket busy' (=EAGAIN). So I err on the
|
211
|
-
// side of 'socket busy' and do not raise the error. As a consequence, we'll
|
212
|
-
// get stuck in an endless loop when the socket is just not answering.
|
213
|
-
|
214
|
-
while (pio->nn_errno == EAGAIN && !pio->abort) {
|
215
|
-
pio->return_code = nn_recv(pio->sock, &pio->buffer, NN_MSG, NN_DONTWAIT /* flags */);
|
198
|
+
pio->return_code = nn_recv(pio->sock, &pio->buffer, NN_MSG, 0 /* flags */);
|
216
199
|
|
217
|
-
|
218
|
-
|
219
|
-
else
|
220
|
-
break;
|
221
|
-
}
|
200
|
+
if (pio->return_code < 0)
|
201
|
+
pio->nn_errno = nn_errno();
|
222
202
|
|
223
203
|
return Qnil;
|
224
204
|
}
|
225
205
|
|
226
|
-
static void
|
227
|
-
sock_recv_abort(void* data)
|
228
|
-
{
|
229
|
-
struct ioop *pio = data;
|
230
|
-
|
231
|
-
pio->abort = Qtrue;
|
232
|
-
}
|
233
|
-
|
234
206
|
static VALUE
|
235
207
|
sock_recv(VALUE socket)
|
236
208
|
{
|
@@ -238,14 +210,8 @@ sock_recv(VALUE socket)
|
|
238
210
|
struct ioop io;
|
239
211
|
|
240
212
|
io.sock = sock_get(socket);
|
241
|
-
io.buffer = (char*) 0;
|
242
|
-
io.abort = Qfalse;
|
243
|
-
io.nn_errno = EAGAIN;
|
244
|
-
|
245
|
-
rb_thread_blocking_region(sock_recv_no_gvl, &io, sock_recv_abort, &io);
|
246
213
|
|
247
|
-
|
248
|
-
return Qnil;
|
214
|
+
rb_thread_blocking_region(sock_recv_blocking, &io, RUBY_UBF_IO, 0);
|
249
215
|
|
250
216
|
if (io.return_code < 0)
|
251
217
|
sock_raise_error(io.nn_errno);
|
@@ -277,7 +243,7 @@ sock_close(VALUE socket)
|
|
277
243
|
|
278
244
|
// I've no idea on how to abort a close (which may block for NN_LINGER
|
279
245
|
// seconds), so we'll be uninterruptible.
|
280
|
-
rb_thread_blocking_region(sock_close_no_gvl, &io,
|
246
|
+
rb_thread_blocking_region(sock_close_no_gvl, &io, RUBY_UBF_IO, 0);
|
281
247
|
|
282
248
|
if (io.return_code < 0)
|
283
249
|
sock_raise_error(io.nn_errno);
|
@@ -285,6 +251,44 @@ sock_close(VALUE socket)
|
|
285
251
|
return Qnil;
|
286
252
|
}
|
287
253
|
|
254
|
+
static VALUE
|
255
|
+
sock_setsockopt(VALUE self, VALUE level, VALUE option, VALUE val)
|
256
|
+
{
|
257
|
+
int sock = sock_get(self);
|
258
|
+
int level_arg = FIX2INT(level);
|
259
|
+
int option_arg = FIX2INT(option);
|
260
|
+
int err;
|
261
|
+
int i;
|
262
|
+
void* v;
|
263
|
+
size_t vlen = 0;
|
264
|
+
|
265
|
+
switch (TYPE(val)) {
|
266
|
+
case T_FIXNUM:
|
267
|
+
i = FIX2INT(val);
|
268
|
+
goto numval;
|
269
|
+
case T_FALSE:
|
270
|
+
i = 0;
|
271
|
+
goto numval;
|
272
|
+
case T_TRUE:
|
273
|
+
i = 1;
|
274
|
+
numval:
|
275
|
+
v = (void*)&i; vlen = sizeof(i);
|
276
|
+
break;
|
277
|
+
|
278
|
+
default:
|
279
|
+
StringValue(val);
|
280
|
+
v = RSTRING_PTR(val);
|
281
|
+
vlen = RSTRING_LEN(val);
|
282
|
+
break;
|
283
|
+
}
|
284
|
+
|
285
|
+
err = nn_setsockopt(sock, level_arg, option_arg, v, vlen);
|
286
|
+
if (err < 0)
|
287
|
+
RAISE_SOCK_ERROR;
|
288
|
+
|
289
|
+
return self;
|
290
|
+
}
|
291
|
+
|
288
292
|
#define SOCK_INIT_FUNC(name, type) \
|
289
293
|
static VALUE \
|
290
294
|
name(int argc, VALUE *argv, VALUE self) \
|
@@ -390,7 +394,7 @@ nanomsg_run_device(VALUE self, VALUE a, VALUE b)
|
|
390
394
|
dop.sa = sock_get(a);
|
391
395
|
dop.sb = sock_get(b);
|
392
396
|
|
393
|
-
rb_thread_blocking_region(nanomsg_run_device_no_gvl, &dop,
|
397
|
+
rb_thread_blocking_region(nanomsg_run_device_no_gvl, &dop, RUBY_UBF_IO, 0);
|
394
398
|
if (dop.err < 0)
|
395
399
|
RAISE_SOCK_ERROR;
|
396
400
|
|
@@ -405,7 +409,7 @@ nanomsg_run_loopback(VALUE self, VALUE a)
|
|
405
409
|
dop.sa = sock_get(a);
|
406
410
|
dop.sb = -1; // invalid socket, see documentation
|
407
411
|
|
408
|
-
rb_thread_blocking_region(nanomsg_run_device_no_gvl, &dop,
|
412
|
+
rb_thread_blocking_region(nanomsg_run_device_no_gvl, &dop, RUBY_UBF_IO, 0);
|
409
413
|
if (dop.err < 0)
|
410
414
|
RAISE_SOCK_ERROR;
|
411
415
|
|
@@ -445,6 +449,7 @@ Init_nanomsg(void)
|
|
445
449
|
rb_define_method(cSocket, "send", sock_send, 1);
|
446
450
|
rb_define_method(cSocket, "recv", sock_recv, 0);
|
447
451
|
rb_define_method(cSocket, "close", sock_close, 0);
|
452
|
+
rb_define_method(cSocket, "setsockopt", sock_setsockopt, 3);
|
448
453
|
|
449
454
|
rb_define_method(cPairSocket, "initialize", pair_sock_init, -1);
|
450
455
|
|
data/ext/mkmf.log
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
have_library: checking for main() in -lnanomsg... -------------------- yes
|
2
|
+
|
3
|
+
"/usr/local/bin/gcc-4.2 -o conftest -I/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/include/ruby-1.9.1/x86_64-darwin12.3.0 -I/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/include/ruby-1.9.1/ruby/backward -I/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -I/usr/local/opt/libyaml/include -I/usr/local/opt/readline/include -I/usr/local/opt/libxml2/include -I/usr/local/opt/libxslt/include -I/usr/local/opt/libksba/include -I/usr/local/opt/openssl/include -I/usr/local/opt/sqlite/include -O3 -ggdb -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -fno-common -pipe conftest.c -L. -L/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libxml2/lib -L/usr/local/opt/libxslt/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/sqlite/lib -L. -L/usr/local/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libxml2/lib -L/usr/local/opt/libxslt/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/sqlite/lib -lruby.1.9.1 -lpthread -ldl -lobjc "
|
4
|
+
checked program was:
|
5
|
+
/* begin */
|
6
|
+
1: #include "ruby.h"
|
7
|
+
2:
|
8
|
+
3: int main() {return 0;}
|
9
|
+
/* end */
|
10
|
+
|
11
|
+
"/usr/local/bin/gcc-4.2 -o conftest -I/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/include/ruby-1.9.1/x86_64-darwin12.3.0 -I/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/include/ruby-1.9.1/ruby/backward -I/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -I/usr/local/opt/libyaml/include -I/usr/local/opt/readline/include -I/usr/local/opt/libxml2/include -I/usr/local/opt/libxslt/include -I/usr/local/opt/libksba/include -I/usr/local/opt/openssl/include -I/usr/local/opt/sqlite/include -O3 -ggdb -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -fno-common -pipe conftest.c -L. -L/Users/kschiess/.rvm/rubies/ruby-1.9.3-p392-turbo/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libxml2/lib -L/usr/local/opt/libxslt/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/sqlite/lib -L. -L/usr/local/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libxml2/lib -L/usr/local/opt/libxslt/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/sqlite/lib -lruby.1.9.1 -lnanomsg -lpthread -ldl -lobjc "
|
12
|
+
checked program was:
|
13
|
+
/* begin */
|
14
|
+
1: #include "ruby.h"
|
15
|
+
2:
|
16
|
+
3: /*top*/
|
17
|
+
4: int main() {return 0;}
|
18
|
+
5: int t() { void ((*volatile p)()); p = (void ((*)()))main; return 0; }
|
19
|
+
/* end */
|
20
|
+
|
21
|
+
--------------------
|
22
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nanomsg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-09-04 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! " nanomsg library is a high-performance implementation of several
|
15
15
|
\"scalability \n protocols\". Scalability protocol's job is to define how multiple
|
@@ -29,12 +29,11 @@ files:
|
|
29
29
|
- lib/nanomsg.rb
|
30
30
|
- ext/constants.c
|
31
31
|
- ext/constants.h
|
32
|
-
- ext/constants.o
|
33
32
|
- ext/extconf.rb
|
34
33
|
- ext/init.c
|
35
|
-
- ext/init.o
|
36
34
|
- ext/Makefile
|
37
|
-
- ext/
|
35
|
+
- ext/mkmf.log
|
36
|
+
- examples/aborting.rb
|
38
37
|
- examples/bus.rb
|
39
38
|
- examples/bus_device.rb
|
40
39
|
- examples/pair.rb
|
data/ext/constants.o
DELETED
Binary file
|
data/ext/init.o
DELETED
Binary file
|
data/ext/nanomsg.bundle
DELETED
Binary file
|