posix-mqueue 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a832068cb72094db986882a2f8799204decdb27d
4
- data.tar.gz: 4f7d8fb462a26bcb476a1fc3114e03910d864993
3
+ metadata.gz: 1ca2c22ede6eec604fc5c61e311fc94036dda433
4
+ data.tar.gz: b4bc3c44253878f51ebcae0ddd01d34bbdc89068
5
5
  SHA512:
6
- metadata.gz: 89f33cce3c747f8096af5ac3bc4a872b0162add9e8f6e300975a67ac67c19112f4638954ac48629d15d591d7ca95caad7901b2560d1f23a64399a41f06c34115
7
- data.tar.gz: 7a4c6d6466be7c9a508b5dfeee9a7ccd316f1959d54f80e49b9c71f6fcad5e3c3a2dadf312cef00cdd7ef2d09278bb9f2de8dc1438c813f5eaf889021be09b67
6
+ metadata.gz: 428afcd5fb9521142d0f65f62381deaf83ef21c18d3b702152bcc9869832535f4253c6735876ad87355a06eaa5ccaeae7177a27aeb1357b4151dcc5620124043
7
+ data.tar.gz: f1653576e2b418a39021bd4618d0b54b2283b6afc5e36f07ce7171233a2095ff802392d0d405fae0b87a4897d44729a6e23a2adb79369fe6bda29ebaf54bfd6d
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
data/README.md CHANGED
@@ -9,18 +9,31 @@ offers:
9
9
  * Blocking and non-blocking. Listeners block until a message arrives on the
10
10
  queue. No polling. Sending messages doesn't block.
11
11
 
12
- Add `gem 'posix-mqueue'` to your favorite Gemfile.
13
-
14
- Still WIP. Not stable. Not everything works as promised.
12
+ Add `gem 'posix-mqueue', :git => "git@github.com:Sirupsen/posix-mqueue.git"` to your favorite Gemfile.
15
13
 
16
14
  ## Usage
17
15
 
16
+ ### Important notes
17
+
18
+ 1. This will not work on OS X, but on Linux and probably BSD (not tested).
19
+ 2. `send` and `receive` block. `timedsend` and `timedreceive` do not.
20
+ 3. The default message size is `4096` bytes.
21
+ 4. Linux's default queue size is `10` bytes.
22
+
23
+ Read on for details.
24
+
25
+ ### Example
26
+
18
27
  ```ruby
19
28
  require 'posix/mqueue'
20
29
 
21
- m = POSIX::Mqueue.new("/whatever")
30
+ # On Linux the queue name must be prefixed with a slash. Note it is not a file
31
+ # created at `/whatever`. It's just the name of the queue.
32
+ # Set maximum default Linux options. See next section to push those limits.
33
+ # Default options are msgsize: 10 and maxmsg: 4096
34
+ m = POSIX::Mqueue.new("/whatever", msgsize: 10, maxmsg: 8192)
22
35
  m.send "hello"
23
- puts m.receive
36
+ m.receive
24
37
  # => "hello"
25
38
 
26
39
  fork { POSIX::Mqueue.new("/whatever").send("world") }
@@ -29,50 +42,53 @@ fork { POSIX::Mqueue.new("/whatever").send("world") }
29
42
  m.receive
30
43
  # => "world"
31
44
 
32
- # Deletes the queue and any messages remaining.
33
- # None in this case. Otherwise the queue will persist till reboot.
34
- m.unlink
35
-
36
45
  # Queue is now full by default Linux settings, see below on how to increase it.
37
46
  10.times { m.send rand(100).to_s }
38
47
 
39
- # #send will block until something is popped off the queue, but timedsend takes
40
- # timeout arguments (first one is seconds, second is nanoseconds). If you don't
41
- # want to block on send, pass 0 for both:
48
+ # #size returns the size of the queue
49
+ m.size
50
+ # => 10
51
+
52
+ # #send will block until something is popped off the now full queue.
53
+ # timesend takes timeout arguments (first one is seconds, second is
54
+ # nanoseconds). Pass 0 for for both to not block, this is default.
42
55
 
43
56
  assert_raises POSIX::Mqueue::QueueFull do
44
- m.timedsend(0, 0, "I will fail")
57
+ m.timedsend "I will fail"
45
58
  end
46
59
 
47
60
  # Empty the queue again
48
61
  10.times { m.receive }
49
62
 
50
63
  # Like timedsend, timedreceive takes timeout arguments and will raise
51
- # POSIX::Mqueue::Queueempty when it would otherwise block
64
+ # POSIX::Mqueue::Queueempty when it would otherwise block.
52
65
  assert_raises POSIX::Mqueue::QueueEmpty do
53
- m.timedreceive(0, 0)
66
+ m.timedreceive
54
67
  end
55
68
 
69
+ # Deletes the queue and any messages remaining.
70
+ # None in this case. If not unlinked, the queue will persist till reboot.
71
+ m.unlink
72
+
56
73
  ```
57
74
 
58
- ## mqueue
75
+ ### mqueue
59
76
 
60
77
  Most important information from the manpages, with a little added information
61
78
  about the behavior of `posix-mqueue`.
62
79
 
63
- ## /proc interfaces
80
+ ### /proc interfaces
64
81
 
65
82
  Linux has some default limits you can easily change.
66
83
 
67
84
  1. `/proc/sys/fs/mqueue/msg_max`. Contains the maximum number of messages in a
68
85
  single queue. Defaults to 10. You should increase that number. `#send` will
69
- eventually throw an exception if the queue is full (instead of blocking). It
70
- does not do that right now.
86
+ eventually block if the queue is full. `#timedsend` will throw `QueueFull`.
71
87
  2. `/proc/sys/fs/mqueue/msgsize_max`. Maximum size of a single message. Defaults
72
- to 8192 bytes. `posix-mqueue` allows up to 4096 bytes. You'll be able to
73
- change this, soon!
88
+ to 8192 bytes. `posix-mqueue` allows up to 4096 bytes. Overwrite this by
89
+ passing `{maxmsg: 8192}` as the second argument when initializing.
74
90
  3. `/proc/sys/fs/mqueue/queues_max`. Maximum number of queues on the system.
75
- Defaults to 256. Which is probably enough.
91
+ Defaults to 256.
76
92
 
77
93
  ## Virtual filesystem
78
94
 
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
+ task :default => [:test]
4
+
3
5
  require 'rake/testtask'
4
6
  Rake::TestTask.new do |t|
5
7
  `cd ext/posix && ruby extconf.rb && make`
@@ -1,5 +1,6 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/util.h>
3
+ #include <ruby/io.h>
3
4
 
4
5
  #include <mqueue.h>
5
6
  #include <fcntl.h>
@@ -89,9 +90,15 @@ VALUE posix_mqueue_send(VALUE self, VALUE message)
89
90
  rb_raise(rb_eTypeError, "Message must be a string");
90
91
  }
91
92
 
93
+ rb_io_wait_writable(data->fd);
94
+
92
95
  // TODO: Custom priority
93
96
  err = mq_send(data->fd, RSTRING_PTR(message), RSTRING_LEN(message), 10);
94
97
 
98
+ if(err < 0 && errno == EINTR) {
99
+ err = mq_send(data->fd, RSTRING_PTR(message), RSTRING_LEN(message), 10);
100
+ }
101
+
95
102
  if (err < 0) {
96
103
  rb_sys_fail("Message sending failed, please consult mq_send(3)");
97
104
  }
@@ -99,7 +106,7 @@ VALUE posix_mqueue_send(VALUE self, VALUE message)
99
106
  return Qtrue;
100
107
  }
101
108
 
102
- VALUE posix_mqueue_timedreceive(VALUE self, VALUE seconds, VALUE nanoseconds)
109
+ VALUE posix_mqueue_timedreceive(VALUE self, VALUE args)
103
110
  {
104
111
  int err;
105
112
  mqueue_t* data;
@@ -107,6 +114,11 @@ VALUE posix_mqueue_timedreceive(VALUE self, VALUE seconds, VALUE nanoseconds)
107
114
  char *buf;
108
115
  struct timespec timeout;
109
116
  VALUE str;
117
+ VALUE seconds = rb_ary_entry(args, 0);
118
+ VALUE nanoseconds = rb_ary_entry(args, 1);
119
+
120
+ if (seconds == Qnil) seconds = INT2FIX(0);
121
+ if (nanoseconds == Qnil) nanoseconds = INT2FIX(0);
110
122
 
111
123
  TypedData_Get_Struct(self, mqueue_t, &mqueue_type, data);
112
124
 
@@ -115,7 +127,7 @@ VALUE posix_mqueue_timedreceive(VALUE self, VALUE seconds, VALUE nanoseconds)
115
127
  }
116
128
 
117
129
  if (!RB_TYPE_P(nanoseconds, T_FIXNUM)) {
118
- rb_raise(rb_eTypeError, "First argument must be a fixnum");
130
+ rb_raise(rb_eTypeError, "Second argument must be a Fixnum");
119
131
  }
120
132
 
121
133
  timeout.tv_sec = FIX2ULONG(seconds);
@@ -141,28 +153,32 @@ VALUE posix_mqueue_timedreceive(VALUE self, VALUE seconds, VALUE nanoseconds)
141
153
  free(buf);
142
154
 
143
155
  return str;
144
-
145
- return Qtrue;
146
156
  }
147
157
 
148
- VALUE posix_mqueue_timedsend(VALUE self, VALUE seconds, VALUE nanoseconds, VALUE message)
158
+ VALUE posix_mqueue_timedsend(VALUE self, VALUE args)
149
159
  {
150
160
  int err;
151
161
  mqueue_t* data;
152
162
  struct timespec timeout;
163
+ VALUE message = rb_ary_entry(args, 0);
164
+ VALUE seconds = rb_ary_entry(args, 1);
165
+ VALUE nanoseconds = rb_ary_entry(args, 2);
166
+
167
+ if (seconds == Qnil) seconds = INT2FIX(0);
168
+ if (nanoseconds == Qnil) nanoseconds = INT2FIX(0);
153
169
 
154
170
  TypedData_Get_Struct(self, mqueue_t, &mqueue_type, data);
155
171
 
156
- if (!RB_TYPE_P(seconds, T_FIXNUM)) {
157
- rb_raise(rb_eTypeError, "First argument must be a Fixnum");
172
+ if (!RB_TYPE_P(message, T_STRING)) {
173
+ rb_raise(rb_eTypeError, "Message must be a string");
158
174
  }
159
175
 
160
- if (!RB_TYPE_P(nanoseconds, T_FIXNUM)) {
161
- rb_raise(rb_eTypeError, "First argument must be a fixnum");
176
+ if (!RB_TYPE_P(seconds, T_FIXNUM)) {
177
+ rb_raise(rb_eTypeError, "First argument must be a Fixnum");
162
178
  }
163
179
 
164
- if (!RB_TYPE_P(message, T_STRING)) {
165
- rb_raise(rb_eTypeError, "Message must be a string");
180
+ if (!RB_TYPE_P(nanoseconds, T_FIXNUM)) {
181
+ rb_raise(rb_eTypeError, "Second argument must be a Fixnum");
166
182
  }
167
183
 
168
184
  timeout.tv_sec = FIX2ULONG(seconds);
@@ -172,7 +188,7 @@ VALUE posix_mqueue_timedsend(VALUE self, VALUE seconds, VALUE nanoseconds, VALUE
172
188
 
173
189
  if (err < 0) {
174
190
  if(errno == 110) {
175
- rb_raise(rb_cQueueFull, "Queue full, most likely you wanna bump /proc/sys/fs/mqueue/msg_max from the default maximum queue size of 10.");
191
+ rb_raise(rb_cQueueFull, "Queue full, most likely you want to bump /proc/sys/fs/mqueue/msg_max from the default maximum queue size of 10.");
176
192
  } else {
177
193
  rb_sys_fail("Message sending failed, please consult mq_send(3)");
178
194
  }
@@ -181,6 +197,34 @@ VALUE posix_mqueue_timedsend(VALUE self, VALUE seconds, VALUE nanoseconds, VALUE
181
197
  return Qtrue;
182
198
  }
183
199
 
200
+ VALUE posix_mqueue_size(VALUE self)
201
+ {
202
+ mqueue_t* data;
203
+ struct mq_attr queue;
204
+
205
+ TypedData_Get_Struct(self, mqueue_t, &mqueue_type, data);
206
+
207
+ if (mq_getattr(data->fd, &queue) < 0) {
208
+ rb_sys_fail("Failed reading queue attributes, please consult mq_getattr(3)");
209
+ }
210
+
211
+ return INT2FIX(queue.mq_curmsgs);
212
+ }
213
+
214
+ VALUE posix_mqueue_msgsize(VALUE self)
215
+ {
216
+ mqueue_t* data;
217
+ struct mq_attr queue;
218
+
219
+ TypedData_Get_Struct(self, mqueue_t, &mqueue_type, data);
220
+
221
+ if (mq_getattr(data->fd, &queue) < 0) {
222
+ rb_sys_fail("Failed reading queue attributes, please consult mq_getattr(3)");
223
+ }
224
+
225
+ return INT2FIX(queue.mq_msgsize);
226
+ }
227
+
184
228
  VALUE posix_mqueue_receive(VALUE self)
185
229
  {
186
230
  int err;
@@ -197,9 +241,14 @@ VALUE posix_mqueue_receive(VALUE self)
197
241
  // Make sure the buffer is capable
198
242
  buf = (char*)malloc(buf_size);
199
243
 
200
- // TODO: Specify priority
244
+ rb_thread_wait_fd(data->fd);
245
+
201
246
  err = mq_receive(data->fd, buf, buf_size, NULL);
202
247
 
248
+ if(err < 0 && errno == EINTR) {
249
+ err = mq_receive(data->fd, buf, buf_size, NULL);
250
+ }
251
+
203
252
  if (err < 0) {
204
253
  rb_sys_fail("Message retrieval failed, please consult mq_receive(3)");
205
254
  }
@@ -210,14 +259,19 @@ VALUE posix_mqueue_receive(VALUE self)
210
259
  return str;
211
260
  }
212
261
 
213
- VALUE posix_mqueue_initialize(VALUE self, VALUE queue)
262
+ VALUE posix_mqueue_initialize(VALUE self, VALUE args)
214
263
  {
215
- // TODO: Modify these options from initialize arguments
216
- // TODO: Set nonblock and handle error in #push
264
+ VALUE options = rb_ary_entry(args, 1);
265
+ if (options == Qnil) options = rb_hash_new();
266
+
267
+ int msgsize = FIX2INT(rb_hash_lookup2(options, ID2SYM(rb_intern("msgsize")), INT2FIX(4096)));
268
+ int maxmsg = FIX2INT(rb_hash_lookup2(options, ID2SYM(rb_intern("maxmsg")), INT2FIX(10)));
269
+ VALUE queue = rb_ary_entry(args, 0);
270
+
217
271
  struct mq_attr attr = {
218
272
  .mq_flags = 0, // Flags, 0 or O_NONBLOCK
219
- .mq_maxmsg = 10, // Max messages in queue
220
- .mq_msgsize = 4096, // Max message size (bytes)
273
+ .mq_maxmsg = maxmsg, // Max messages in queue
274
+ .mq_msgsize = msgsize, // Max message size (bytes)
221
275
  .mq_curmsgs = 0 // # currently in queue
222
276
  };
223
277
 
@@ -249,11 +303,13 @@ void Init_mqueue()
249
303
  rb_cQueueEmpty = rb_define_class_under(mqueue, "QueueEmpty", rb_eStandardError);
250
304
 
251
305
  rb_define_alloc_func(mqueue, posix_mqueue_alloc);
252
- rb_define_method(mqueue, "initialize", posix_mqueue_initialize, 1);
306
+ rb_define_method(mqueue, "initialize", posix_mqueue_initialize, -2);
253
307
  rb_define_method(mqueue, "send", posix_mqueue_send, 1);
254
308
  rb_define_method(mqueue, "receive", posix_mqueue_receive, 0);
255
- rb_define_method(mqueue, "timedsend", posix_mqueue_timedsend, 3);
256
- rb_define_method(mqueue, "timedreceive", posix_mqueue_timedreceive, 2);
309
+ rb_define_method(mqueue, "timedsend", posix_mqueue_timedsend, -2);
310
+ rb_define_method(mqueue, "timedreceive", posix_mqueue_timedreceive, -2);
311
+ rb_define_method(mqueue, "msgsize", posix_mqueue_msgsize, 0);
312
+ rb_define_method(mqueue, "size", posix_mqueue_size, 0);
257
313
  rb_define_method(mqueue, "unlink", posix_mqueue_unlink, 0);
258
314
  }
259
315
 
@@ -1,5 +1,5 @@
1
1
  module POSIX
2
2
  class Mqueue
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -36,26 +36,25 @@ class MqueueTest < MiniTest::Unit::TestCase
36
36
  def test_multiple_queues
37
37
  @queue.send "hello"
38
38
 
39
- other = POSIX::Mqueue.new("/other-test-queue")
40
- other.send "world"
39
+ with_queue "/other-test-queue" do |q|
40
+ q.send "world"
41
+ assert_equal "world", q.receive
42
+ end
41
43
 
42
- assert_equal "world", other.receive
43
44
  assert_equal "hello", @queue.receive
44
-
45
- other.unlink
46
45
  end
47
46
 
48
47
  def test_timedsend_raises_exception_instead_of_blocking
49
- 10.times { @queue.timedsend 0, 0, "walrus" }
48
+ 10.times { @queue.timedsend "walrus", 0, 0 }
50
49
 
51
50
  assert_raises POSIX::Mqueue::QueueFull do
52
- @queue.timedsend(0, 0, "hi")
51
+ @queue.timedsend("penguin")
53
52
  end
54
53
  end
55
54
 
56
55
  def test_timedreceive_raises_exception_instead_of_blocking
57
56
  assert_raises POSIX::Mqueue::QueueEmpty do
58
- @queue.timedreceive(0, 0)
57
+ @queue.timedreceive
59
58
  end
60
59
  end
61
60
 
@@ -64,4 +63,47 @@ class MqueueTest < MiniTest::Unit::TestCase
64
63
  POSIX::Mqueue.new("notvalid")
65
64
  end
66
65
  end
66
+
67
+ def test_custom_message_size
68
+ assert_raises Errno::EMSGSIZE do
69
+ @queue.send('c' * 4097) # one byte too large
70
+ end
71
+
72
+ # Set to the maximum for Linux
73
+ with_queue "/big-queue", msgsize: 2 ** 13 do |q|
74
+ assert_equal 2 ** 13, q.msgsiza
75
+
76
+ q.send('c' * (2 ** 13))
77
+ end
78
+ end
79
+
80
+ def test_custom_max_queue_size
81
+ with_queue "/small-queue", maxmsg: 2 do |q|
82
+ 2.times { q.send "narwhal" }
83
+
84
+ assert_raises POSIX::Mqueue::QueueFull do
85
+ q.timedsend("narwhal", 0, 0)
86
+ end
87
+ end
88
+ end
89
+
90
+ def test_count_in_queue
91
+ assert_equal 0, @queue.size
92
+
93
+ @queue.send "first"
94
+ @queue.send "second"
95
+ @queue.send "third"
96
+
97
+ assert_equal 3, @queue.size
98
+ end
99
+
100
+ private
101
+ def with_queue(name, options = {})
102
+ queue = POSIX::Mqueue.new(name, options)
103
+ begin
104
+ yield(queue)
105
+ ensure
106
+ queue.unlink
107
+ end
108
+ end
67
109
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posix-mqueue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Eskildsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-01 00:00:00.000000000 Z
11
+ date: 2013-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -47,6 +47,7 @@ extensions:
47
47
  extra_rdoc_files: []
48
48
  files:
49
49
  - .gitignore
50
+ - .travis.yml
50
51
  - Gemfile
51
52
  - LICENSE.txt
52
53
  - README.md