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 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