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 CHANGED
@@ -1,5 +1,10 @@
1
+ = 0.3 / 4Sept2013
1
2
 
2
- = 0.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
- sock_send_no_gvl(void* data)
165
+ sock_send_blocking(void* data)
153
166
  {
154
167
  struct ioop *pio = data;
155
168
 
156
- // TODO This is buggy. I cannot make the difference between
157
- // 'socket gone away' (=EAGAIN) and 'socket busy' (=EAGAIN). So I err on the
158
- // side of 'socket busy' and do not raise the error. As a consequence, we'll
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
- static void
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
- // Unclear what to do in this situation, but we'll simply return nil,
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
- sock_recv_no_gvl(void* data)
194
+ sock_recv_blocking(void* data)
206
195
  {
207
196
  struct ioop *pio = data;
208
197
 
209
- // TODO This is buggy. I cannot make the difference between
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
- if (pio->return_code < 0)
218
- pio->nn_errno = nn_errno();
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
- if (io.abort)
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, NULL, NULL);
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, NULL, NULL);
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, NULL, NULL);
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.2.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-08-26 00:00:00.000000000 Z
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/nanomsg.bundle
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