posix-mqueue 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +56 -23
- data/Rakefile +1 -0
- data/ext/posix/mqueue.c +96 -5
- data/lib/posix/mqueue/version.rb +1 -1
- data/test/mqueue_test.rb +18 -6
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a832068cb72094db986882a2f8799204decdb27d
|
4
|
+
data.tar.gz: 4f7d8fb462a26bcb476a1fc3114e03910d864993
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89f33cce3c747f8096af5ac3bc4a872b0162add9e8f6e300975a67ac67c19112f4638954ac48629d15d591d7ca95caad7901b2560d1f23a64399a41f06c34115
|
7
|
+
data.tar.gz: 7a4c6d6466be7c9a508b5dfeee9a7ccd316f1959d54f80e49b9c71f6fcad5e3c3a2dadf312cef00cdd7ef2d09278bb9f2de8dc1438c813f5eaf889021be09b67
|
data/README.md
CHANGED
@@ -28,6 +28,31 @@ fork { POSIX::Mqueue.new("/whatever").send("world") }
|
|
28
28
|
# Blocks until the forked process pushes to the queue
|
29
29
|
m.receive
|
30
30
|
# => "world"
|
31
|
+
|
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
|
+
# Queue is now full by default Linux settings, see below on how to increase it.
|
37
|
+
10.times { m.send rand(100).to_s }
|
38
|
+
|
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:
|
42
|
+
|
43
|
+
assert_raises POSIX::Mqueue::QueueFull do
|
44
|
+
m.timedsend(0, 0, "I will fail")
|
45
|
+
end
|
46
|
+
|
47
|
+
# Empty the queue again
|
48
|
+
10.times { m.receive }
|
49
|
+
|
50
|
+
# Like timedsend, timedreceive takes timeout arguments and will raise
|
51
|
+
# POSIX::Mqueue::Queueempty when it would otherwise block
|
52
|
+
assert_raises POSIX::Mqueue::QueueEmpty do
|
53
|
+
m.timedreceive(0, 0)
|
54
|
+
end
|
55
|
+
|
31
56
|
```
|
32
57
|
|
33
58
|
## mqueue
|
@@ -37,11 +62,14 @@ about the behavior of `posix-mqueue`.
|
|
37
62
|
|
38
63
|
## /proc interfaces
|
39
64
|
|
40
|
-
|
41
|
-
|
42
|
-
|
65
|
+
Linux has some default limits you can easily change.
|
66
|
+
|
67
|
+
1. `/proc/sys/fs/mqueue/msg_max`. Contains the maximum number of messages in a
|
68
|
+
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.
|
43
71
|
2. `/proc/sys/fs/mqueue/msgsize_max`. Maximum size of a single message. Defaults
|
44
|
-
to 8192 bytes. `posix-mqueue`
|
72
|
+
to 8192 bytes. `posix-mqueue` allows up to 4096 bytes. You'll be able to
|
45
73
|
change this, soon!
|
46
74
|
3. `/proc/sys/fs/mqueue/queues_max`. Maximum number of queues on the system.
|
47
75
|
Defaults to 256. Which is probably enough.
|
@@ -51,30 +79,35 @@ about the behavior of `posix-mqueue`.
|
|
51
79
|
The message queue is created as a virtual file system. That means you can mount
|
52
80
|
it:
|
53
81
|
|
54
|
-
|
55
|
-
|
82
|
+
```bash
|
83
|
+
# sudo mkdir /dev/queue
|
84
|
+
# sudo mount -t mqueue none /dev/queue
|
85
|
+
```
|
56
86
|
|
57
|
-
Add a queue and a few tasks, count the characters
|
87
|
+
Add a queue and a few tasks, count the characters (19):
|
58
88
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
89
|
+
```ruby
|
90
|
+
$ irb
|
91
|
+
> require 'posix/mqueue'
|
92
|
+
=> true
|
93
|
+
> m = POSIX::Mqueue.new("/queue")
|
94
|
+
=> #<POSIX::Mqueue:0xb8c9fe88>
|
95
|
+
> m.send "narwhal"
|
96
|
+
=> true
|
97
|
+
> m.send "walrus"
|
98
|
+
=> true
|
99
|
+
> m.send "ponies"
|
100
|
+
=> true
|
101
|
+
```
|
71
102
|
|
72
103
|
Inspect the mounted filesystem:
|
73
104
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
105
|
+
```bash
|
106
|
+
$ ls /dev/queue/
|
107
|
+
important mails queue
|
108
|
+
$ cat /dev/queue/queue
|
109
|
+
QSIZE:19 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
|
110
|
+
```
|
78
111
|
|
79
112
|
Here `QSIZE` is the bytes of data in the queue. The other flags are about
|
80
113
|
notifications which `posix-mqueue` does not support currently, read about them
|
data/Rakefile
CHANGED
data/ext/posix/mqueue.c
CHANGED
@@ -4,10 +4,14 @@
|
|
4
4
|
#include <mqueue.h>
|
5
5
|
#include <fcntl.h>
|
6
6
|
#include <errno.h>
|
7
|
+
#include <time.h>
|
7
8
|
|
8
9
|
#include <stdlib.h>
|
9
10
|
#include <stdio.h>
|
10
11
|
|
12
|
+
VALUE rb_cQueueFull = Qnil;
|
13
|
+
VALUE rb_cQueueEmpty = Qnil;
|
14
|
+
|
11
15
|
typedef struct {
|
12
16
|
mqd_t fd;
|
13
17
|
struct mq_attr attr;
|
@@ -68,7 +72,7 @@ VALUE posix_mqueue_unlink(VALUE self)
|
|
68
72
|
TypedData_Get_Struct(self, mqueue_t, &mqueue_type, data);
|
69
73
|
|
70
74
|
if (mq_unlink(data->queue) == -1) {
|
71
|
-
rb_sys_fail("Message queue unlinking failed");
|
75
|
+
rb_sys_fail("Message queue unlinking failed, please consume mq_unlink(3)");
|
72
76
|
}
|
73
77
|
|
74
78
|
return Qtrue;
|
@@ -89,7 +93,89 @@ VALUE posix_mqueue_send(VALUE self, VALUE message)
|
|
89
93
|
err = mq_send(data->fd, RSTRING_PTR(message), RSTRING_LEN(message), 10);
|
90
94
|
|
91
95
|
if (err < 0) {
|
92
|
-
rb_sys_fail("Message sending failed");
|
96
|
+
rb_sys_fail("Message sending failed, please consult mq_send(3)");
|
97
|
+
}
|
98
|
+
|
99
|
+
return Qtrue;
|
100
|
+
}
|
101
|
+
|
102
|
+
VALUE posix_mqueue_timedreceive(VALUE self, VALUE seconds, VALUE nanoseconds)
|
103
|
+
{
|
104
|
+
int err;
|
105
|
+
mqueue_t* data;
|
106
|
+
size_t buf_size;
|
107
|
+
char *buf;
|
108
|
+
struct timespec timeout;
|
109
|
+
VALUE str;
|
110
|
+
|
111
|
+
TypedData_Get_Struct(self, mqueue_t, &mqueue_type, data);
|
112
|
+
|
113
|
+
if (!RB_TYPE_P(seconds, T_FIXNUM)) {
|
114
|
+
rb_raise(rb_eTypeError, "First argument must be a Fixnum");
|
115
|
+
}
|
116
|
+
|
117
|
+
if (!RB_TYPE_P(nanoseconds, T_FIXNUM)) {
|
118
|
+
rb_raise(rb_eTypeError, "First argument must be a fixnum");
|
119
|
+
}
|
120
|
+
|
121
|
+
timeout.tv_sec = FIX2ULONG(seconds);
|
122
|
+
timeout.tv_nsec = FIX2ULONG(nanoseconds);
|
123
|
+
|
124
|
+
buf_size = data->attr.mq_msgsize + 1;
|
125
|
+
|
126
|
+
// Make sure the buffer is capable
|
127
|
+
buf = (char*)malloc(buf_size);
|
128
|
+
|
129
|
+
// TODO: Specify priority
|
130
|
+
err = mq_timedreceive(data->fd, buf, buf_size, NULL, &timeout);
|
131
|
+
|
132
|
+
if (err < 0) {
|
133
|
+
if(errno == 110) {
|
134
|
+
rb_raise(rb_cQueueEmpty, "Queue empty");
|
135
|
+
} else {
|
136
|
+
rb_sys_fail("Message sending failed, please consult mq_send(3)");
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
str = rb_str_new(buf, err);
|
141
|
+
free(buf);
|
142
|
+
|
143
|
+
return str;
|
144
|
+
|
145
|
+
return Qtrue;
|
146
|
+
}
|
147
|
+
|
148
|
+
VALUE posix_mqueue_timedsend(VALUE self, VALUE seconds, VALUE nanoseconds, VALUE message)
|
149
|
+
{
|
150
|
+
int err;
|
151
|
+
mqueue_t* data;
|
152
|
+
struct timespec timeout;
|
153
|
+
|
154
|
+
TypedData_Get_Struct(self, mqueue_t, &mqueue_type, data);
|
155
|
+
|
156
|
+
if (!RB_TYPE_P(seconds, T_FIXNUM)) {
|
157
|
+
rb_raise(rb_eTypeError, "First argument must be a Fixnum");
|
158
|
+
}
|
159
|
+
|
160
|
+
if (!RB_TYPE_P(nanoseconds, T_FIXNUM)) {
|
161
|
+
rb_raise(rb_eTypeError, "First argument must be a fixnum");
|
162
|
+
}
|
163
|
+
|
164
|
+
if (!RB_TYPE_P(message, T_STRING)) {
|
165
|
+
rb_raise(rb_eTypeError, "Message must be a string");
|
166
|
+
}
|
167
|
+
|
168
|
+
timeout.tv_sec = FIX2ULONG(seconds);
|
169
|
+
timeout.tv_nsec = FIX2ULONG(nanoseconds);
|
170
|
+
|
171
|
+
err = mq_timedsend(data->fd, RSTRING_PTR(message), RSTRING_LEN(message), 10, &timeout);
|
172
|
+
|
173
|
+
if (err < 0) {
|
174
|
+
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.");
|
176
|
+
} else {
|
177
|
+
rb_sys_fail("Message sending failed, please consult mq_send(3)");
|
178
|
+
}
|
93
179
|
}
|
94
180
|
|
95
181
|
return Qtrue;
|
@@ -115,7 +201,7 @@ VALUE posix_mqueue_receive(VALUE self)
|
|
115
201
|
err = mq_receive(data->fd, buf, buf_size, NULL);
|
116
202
|
|
117
203
|
if (err < 0) {
|
118
|
-
rb_sys_fail("Message retrieval failed");
|
204
|
+
rb_sys_fail("Message retrieval failed, please consult mq_receive(3)");
|
119
205
|
}
|
120
206
|
|
121
207
|
str = rb_str_new(buf, err);
|
@@ -146,10 +232,10 @@ VALUE posix_mqueue_initialize(VALUE self, VALUE queue)
|
|
146
232
|
data->attr = attr;
|
147
233
|
data->queue_len = RSTRING_LEN(queue);
|
148
234
|
data->queue = ruby_strdup(StringValueCStr(queue));
|
149
|
-
data->fd = mq_open(data->queue, O_CREAT | O_RDWR,
|
235
|
+
data->fd = mq_open(data->queue, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, &data->attr);
|
150
236
|
|
151
237
|
if (data->fd == (mqd_t)-1) {
|
152
|
-
rb_sys_fail("Failed opening the message queue");
|
238
|
+
rb_sys_fail("Failed opening the message queue, please consult mq_open(3)");
|
153
239
|
}
|
154
240
|
|
155
241
|
return self;
|
@@ -159,10 +245,15 @@ void Init_mqueue()
|
|
159
245
|
{
|
160
246
|
VALUE posix = rb_define_module("POSIX");
|
161
247
|
VALUE mqueue = rb_define_class_under(posix, "Mqueue", rb_cObject);
|
248
|
+
rb_cQueueFull = rb_define_class_under(mqueue, "QueueFull", rb_eStandardError);
|
249
|
+
rb_cQueueEmpty = rb_define_class_under(mqueue, "QueueEmpty", rb_eStandardError);
|
250
|
+
|
162
251
|
rb_define_alloc_func(mqueue, posix_mqueue_alloc);
|
163
252
|
rb_define_method(mqueue, "initialize", posix_mqueue_initialize, 1);
|
164
253
|
rb_define_method(mqueue, "send", posix_mqueue_send, 1);
|
165
254
|
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);
|
166
257
|
rb_define_method(mqueue, "unlink", posix_mqueue_unlink, 0);
|
167
258
|
}
|
168
259
|
|
data/lib/posix/mqueue/version.rb
CHANGED
data/test/mqueue_test.rb
CHANGED
@@ -45,11 +45,23 @@ class MqueueTest < MiniTest::Unit::TestCase
|
|
45
45
|
other.unlink
|
46
46
|
end
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
def test_timedsend_raises_exception_instead_of_blocking
|
49
|
+
10.times { @queue.timedsend 0, 0, "walrus" }
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
assert_raises POSIX::Mqueue::QueueFull do
|
52
|
+
@queue.timedsend(0, 0, "hi")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_timedreceive_raises_exception_instead_of_blocking
|
57
|
+
assert_raises POSIX::Mqueue::QueueEmpty do
|
58
|
+
@queue.timedreceive(0, 0)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_errors_when_queue_name_is_not_slash_prefixed
|
63
|
+
assert_raises Errno::EINVAL do
|
64
|
+
POSIX::Mqueue.new("notvalid")
|
65
|
+
end
|
66
|
+
end
|
55
67
|
end
|