posix-mqueue 0.0.4 → 0.0.5

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