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