posix-mqueue 0.0.3 → 0.0.4
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 +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
|