sysvmq 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d84404b90167dfecfe52eae482a6284f2af9bbc1
4
+ data.tar.gz: c4b84de9d1fa95c093f953797cd8d794e52e69bb
5
+ SHA512:
6
+ metadata.gz: 1ad89cfac4699a9f283024e0a75c2587200196b8e91410c5cdb2e10e70df3612d2887ba5ce92c9a9efc81a2dc76fb757446444ae3038f72cf79b0a1d3a50ebcd
7
+ data.tar.gz: acdf82f69e86f30542da3f98917c8b2ee75f859222bd7f41905d0d8a749d85070801d6fdb5e663dd0cd3add051b96145cadfa4d6cc0761f50df4aff98038d33e
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ bundle
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sysv-mq.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Simon Eskildsen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # sysvmq
2
+
3
+ `sysvmq` is a C extension that wraps SysV IPC Message Queues. Only compatible
4
+ with MRI 2.0 and 2.1 currently.
5
+
6
+ ```ruby
7
+ # Create a message queue with a 1024 byte buffer.
8
+ require 'sysvmq'
9
+ mq = SysVMQ.new(0xDEADC0DE, 1024, SysVMQ::IPC_CREAT | 0666)
10
+
11
+ mq.send "Hellø Wårld!"
12
+ assert_equal 1, mq.stats[:count]
13
+
14
+ assert_equal "Hellø Wårld!", mq.receive
15
+
16
+ # Raise an exception instead of blocking until a message is available
17
+ mq.receive(0, SysVMQ::IPC_NOWAIT)
18
+
19
+ ensure
20
+ # Delete queue
21
+ mq.destroy
22
+ ```
23
+
24
+ ## Installation
25
+
26
+ gem 'sysv-mq', github: "Sirupsen/sysvmq" # until published to rubygems
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+ require 'rake/extensiontask'
4
+
5
+ Rake::ExtensionTask.new 'sysvmq' do |ext|
6
+ ext.ext_dir = 'ext/'
7
+ end
8
+
9
+ task :default => [:compile, :test]
10
+
11
+ Rake::TestTask.new do |t|
12
+ t.libs << "test"
13
+ t.test_files = FileList['test/*_test.rb']
14
+ t.verbose = true
15
+ end
data/bin/coderay ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'coderay' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('coderay', 'coderay')
data/bin/pry ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'pry' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('pry', 'pry')
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/ext/extconf.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+ have_header 'sys/ipc.h'
3
+ have_header 'sys/msg.h'
4
+ have_header 'sys/types.h'
5
+ create_makefile 'sysvmq'
data/ext/sysvmq.c ADDED
@@ -0,0 +1,358 @@
1
+ #include <ruby.h>
2
+ #include <ruby/util.h>
3
+ #include <ruby/thread.h>
4
+ #include <ruby/io.h>
5
+
6
+ #include <sys/types.h>
7
+ #include <sys/ipc.h>
8
+ #include <sys/msg.h>
9
+
10
+ #include <stdlib.h>
11
+ #include <errno.h>
12
+ #include <stdio.h>
13
+ #include <string.h>
14
+
15
+ // This is the buffer passed to msg{rcv,snd,ctl}(2)
16
+ typedef struct {
17
+ long mtype;
18
+ char mtext[];
19
+ }
20
+ sysvmq_msgbuf_t;
21
+
22
+ // Used for rb_thread_wait_for to signal time between EINTR tries
23
+ struct timeval polling_interval;
24
+
25
+ // C struct linked to all Ruby objects
26
+ typedef struct {
27
+ key_t key;
28
+ int id;
29
+ size_t buffer_size;
30
+ sysvmq_msgbuf_t* msgbuf;
31
+ }
32
+ sysvmq_t;
33
+
34
+ static void
35
+ sysvmq_mark(void *ptr)
36
+ {
37
+ // noop, no Ruby objects in the internal struct currently
38
+ }
39
+
40
+ static void
41
+ sysvmq_free(void *ptr)
42
+ {
43
+ sysvmq_t* sysv = ptr;
44
+ xfree(sysv->msgbuf);
45
+ xfree(sysv);
46
+ }
47
+
48
+ static size_t
49
+ sysvmq_memsize(const void* ptr)
50
+ {
51
+ const sysvmq_t* sysv = ptr;
52
+ return sizeof(sysvmq_t) + sizeof(char) * sysv->buffer_size;
53
+ }
54
+
55
+ static const rb_data_type_t
56
+ sysvmq_type = {
57
+ "sysvmq_type",
58
+ {
59
+ sysvmq_mark,
60
+ sysvmq_free,
61
+ sysvmq_memsize
62
+ }
63
+ };
64
+
65
+ static VALUE
66
+ sysvmq_alloc(VALUE klass)
67
+ {
68
+ sysvmq_t* sysv;
69
+ VALUE obj = TypedData_Make_Struct(klass, sysvmq_t, &sysvmq_type, sysv);
70
+
71
+ sysv->key = 0;
72
+ sysv->id = -1;
73
+ sysv->buffer_size = 0;
74
+ sysv->msgbuf = memset(sysv, 0, sizeof(sysvmq_t));
75
+
76
+ return obj;
77
+ }
78
+
79
+ // int msgctl(int msqid, int cmd, struct msqid_ds *buf);
80
+ // http://man7.org/linux/man-pages/man2/msgctl.2.html
81
+ //
82
+ // Controls the queue with IPC_SET, IPC_INFO and IPC_RMID via msgctl(2). When no
83
+ // argument is passed, it'll return the information about the queue from
84
+ // IPC_INFO.
85
+ //
86
+ // TODO: IPC_SET is currently not supported.
87
+ static VALUE
88
+ sysvmq_stats(int argc, VALUE *argv, VALUE self)
89
+ {
90
+ struct msqid_ds info;
91
+ VALUE info_hash;
92
+ VALUE cmd;
93
+ sysvmq_t* sysv;
94
+
95
+ // Optional argument handling
96
+ if (argc > 1) {
97
+ rb_raise(rb_eArgError, "Wrong number of arguments (0..1)");
98
+ }
99
+
100
+ // Default to IPC_STAT
101
+ cmd = argc == 1 ? argv[0] : INT2FIX(IPC_STAT);
102
+
103
+ TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv);
104
+
105
+ // TODO: Does FIX2INT actually perform this check already?
106
+ Check_Type(cmd, T_FIXNUM);
107
+
108
+ while (msgctl(sysv->id, FIX2INT(cmd), &info) < 0) {
109
+ if (errno == EINTR) {
110
+ rb_thread_wait_for(polling_interval);
111
+ continue;
112
+ }
113
+ rb_sys_fail("Failed executing msgctl(2) command.");
114
+ }
115
+
116
+ // Map values from struct to a hash
117
+ // TODO: Add all the fields
118
+ // TODO: They are probably not ints..
119
+ info_hash = rb_hash_new();
120
+ rb_hash_aset(info_hash, ID2SYM(rb_intern("count")), INT2FIX(info.msg_qnum));
121
+ rb_hash_aset(info_hash, ID2SYM(rb_intern("maximum_size")), INT2FIX(info.msg_qbytes));
122
+
123
+ // TODO: Can probably make a better checker here for whether the struct
124
+ // actually has the member.
125
+ // TODO: BSD support?
126
+ #ifdef __linux__
127
+ rb_hash_aset(info_hash, ID2SYM(rb_intern("size")), INT2FIX(info.__msg_cbytes));
128
+ #elif __APPLE__
129
+ rb_hash_aset(info_hash, ID2SYM(rb_intern("size")), INT2FIX(info.msg_cbytes));
130
+ #endif
131
+
132
+ return info_hash;
133
+ }
134
+
135
+ // Proxies a call with IPC_RMID to `sysvmq_stats` to remove the queue.
136
+ static VALUE
137
+ sysvmq_destroy(VALUE self)
138
+ {
139
+ VALUE argv[1];
140
+ argv[0] = INT2FIX(IPC_RMID);
141
+ return sysvmq_stats(1, argv, self);
142
+ }
143
+
144
+ // This is used for passing values between the `maybe_blocking` function and the
145
+ // Ruby function. There's definitely a better way.
146
+ typedef struct {
147
+ size_t size;
148
+ int flags;
149
+ int type;
150
+ size_t msg_size; // TODO: typelol
151
+ sysvmq_t* sysv;
152
+
153
+ int retval;
154
+ }
155
+ sysvmq_blocking_call_t;
156
+
157
+ // Blocking call to msgsnd(2) (see sysvmq_send). This is to be called without
158
+ // the GVL, and must therefore not use any Ruby functions.
159
+ static void*
160
+ sysvmq_maybe_blocking_receive(void *args)
161
+ {
162
+ sysvmq_blocking_call_t* arguments = (sysvmq_blocking_call_t*) args;
163
+ arguments->retval = msgrcv(arguments->sysv->id, arguments->sysv->msgbuf, arguments->sysv->buffer_size, arguments->type, arguments->flags);
164
+
165
+ return NULL;
166
+ }
167
+
168
+ // ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
169
+ // http://man7.org/linux/man-pages/man2/msgsnd.2.html
170
+ //
171
+ // Receive a message from the message queue.
172
+ VALUE
173
+ sysvmq_receive(int argc, VALUE *argv, VALUE self)
174
+ {
175
+ VALUE type = INT2FIX(0);
176
+ VALUE flags = INT2FIX(0);
177
+ sysvmq_t* sysv;
178
+ sysvmq_blocking_call_t blocking;
179
+
180
+ if (argc > 2) {
181
+ rb_raise(rb_eArgError, "Wrong number of arguments (0..2)");
182
+ }
183
+
184
+ if (argc >= 1) type = argv[0];
185
+ if (argc == 2) flags = argv[1];
186
+
187
+ TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv);
188
+
189
+ Check_Type(type, T_FIXNUM);
190
+ Check_Type(flags, T_FIXNUM);
191
+
192
+ // Attach blocking call parameters to the struct passed to the blocking
193
+ // function wrapper.
194
+ blocking.flags = FIX2INT(flags);
195
+ blocking.type = FIX2INT(type);
196
+ blocking.sysv = sysv;
197
+
198
+ // msgrcv(2) can block sending a message, if IPC_NOWAIT is not passed.
199
+ // We unlock the GVL waiting for the call so other threads (e.g. signal
200
+ // handling) can continue to work. Sets `msg_size` on `blocking` with the size
201
+ // of the message returned.
202
+ while (rb_thread_call_without_gvl2(sysvmq_maybe_blocking_receive, &blocking, RUBY_UBF_IO, NULL) == NULL
203
+ && blocking.retval < 0) {
204
+ if (errno == EINTR) {
205
+ rb_thread_check_ints();
206
+ continue;
207
+ }
208
+
209
+ rb_sys_fail("Failed receiving message from queue");
210
+ }
211
+
212
+ // Reencode with default external encoding
213
+ return rb_enc_str_new(sysv->msgbuf->mtext, blocking.retval, rb_default_external_encoding());
214
+ }
215
+
216
+ // Blocking call to msgsnd(2) (see sysvmq_send). This is to be called without
217
+ // the GVL, and must therefore not use any Ruby functions.
218
+ static void*
219
+ sysvmq_maybe_blocking_send(void *data)
220
+ {
221
+ sysvmq_blocking_call_t* arguments = (sysvmq_blocking_call_t*) data;
222
+
223
+ arguments->retval = msgsnd(arguments->sysv->id, arguments->sysv->msgbuf, arguments->size, arguments->flags);
224
+
225
+ return NULL;
226
+ }
227
+
228
+ // int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
229
+ // http://man7.org/linux/man-pages/man2/msgsnd.2.html
230
+ //
231
+ // Sends a message to the message queue.
232
+ VALUE
233
+ sysvmq_send(int argc, VALUE *argv, VALUE self)
234
+ {
235
+ VALUE message;
236
+ VALUE priority = INT2FIX(1);
237
+ VALUE flags = INT2FIX(0);
238
+ sysvmq_blocking_call_t blocking;
239
+ sysvmq_t* sysv;
240
+
241
+ if (argc > 3 || argc == 0) {
242
+ rb_raise(rb_eArgError, "Wrong number of arguments (1..3)");
243
+ }
244
+
245
+ message = argv[0];
246
+ if (argc >= 2) priority = argv[1];
247
+ if (argc == 3) flags = argv[2];
248
+
249
+ TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv);
250
+
251
+ Check_Type(flags, T_FIXNUM);
252
+ Check_Type(priority, T_FIXNUM);
253
+ // TODO: Call to_s on message if it responds to
254
+
255
+ // Attach blocking call parameters to the struct passed to the blocking
256
+ // function wrapper.
257
+ blocking.flags = FIX2INT(flags);
258
+ blocking.size = RSTRING_LEN(message);
259
+ blocking.sysv = sysv;
260
+
261
+ // The buffer can be obtained from `sysvmq_maybe_blocking_send`, instead of
262
+ // passing it, set it directly on the instance struct.
263
+ sysv->msgbuf->mtype = FIX2INT(priority);
264
+
265
+ if (blocking.size > sysv->buffer_size) {
266
+ rb_raise(rb_eArgError, "Size of message is bigger than buffer size.");
267
+ }
268
+
269
+ // TODO: Can a string copy be avoided?
270
+ strncpy(sysv->msgbuf->mtext, StringValueCStr(message), blocking.size);
271
+
272
+ // msgsnd(2) can block waiting for a message, if IPC_NOWAIT is not passed.
273
+ // We unlock the GVL waiting for the call so other threads (e.g. signal
274
+ // handling) can continue to work.
275
+ while (rb_thread_call_without_gvl2(sysvmq_maybe_blocking_send, &blocking, RUBY_UBF_IO, NULL) == NULL
276
+ && blocking.retval < 0) {
277
+ if (errno == EINTR) {
278
+ rb_thread_check_ints();
279
+ continue;
280
+ }
281
+
282
+ rb_sys_fail("Failed sending message to queue");
283
+ }
284
+
285
+ return message;
286
+ }
287
+
288
+ // int msgget(key_t key, int msgflg);
289
+ // http://man7.org/linux/man-pages/man2/msgget.2.html
290
+ //
291
+ // Instead of calling `msgget` method directly to get the `msgid` (the return
292
+ // value of `msgget`) from Rubyland and pass it around, it's stored internally
293
+ // in a struct only directly accessible from C-land. It's passed to all the
294
+ // other calls that require a `msgid`, for convienence and to share the buffer.
295
+ VALUE
296
+ sysvmq_initialize(VALUE self, VALUE key, VALUE buffer_size, VALUE flags)
297
+ {
298
+ sysvmq_t* sysv;
299
+ size_t msgbuf_size;
300
+
301
+ // TODO: Also support string keys, so you can pass '0xDEADC0DE'
302
+ Check_Type(key, T_FIXNUM);
303
+ Check_Type(flags, T_FIXNUM);
304
+ Check_Type(buffer_size, T_FIXNUM);
305
+
306
+ TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv);
307
+
308
+ // TODO: This probably doesn't hold on all platforms.
309
+ sysv->key = FIX2LONG(key);
310
+
311
+ while ((sysv->id = msgget(sysv->key, FIX2INT(flags))) < 0) {
312
+ if (errno == EINTR) {
313
+ rb_thread_wait_for(polling_interval); // TODO: Really necessary here?
314
+ continue;
315
+ }
316
+ rb_sys_fail("Failed opening the message queue.");
317
+ }
318
+
319
+ // Allocate the msgbuf buffer once for the instance, to not allocate a buffer
320
+ // for each message sent. This makes SysVMQ not thread-safe (requiring a
321
+ // buffer for each thread), but is a reasonable trade-off for now for the
322
+ // performance.
323
+ sysv->buffer_size = FIX2INT(buffer_size);
324
+ msgbuf_size = sysv->buffer_size * sizeof(char) + sizeof(long);
325
+
326
+ // Note that this is a zero-length array, so we size the struct to size of the
327
+ // header (long, the mtype) and then the rest of the space for message buffer.
328
+ sysv->msgbuf = (sysvmq_msgbuf_t*) xmalloc(msgbuf_size);
329
+
330
+ return self;
331
+ }
332
+
333
+ void Init_sysvmq()
334
+ {
335
+ VALUE sysvmq = rb_define_class("SysVMQ", rb_cObject);
336
+
337
+ // Waiting between blocking calls that have been interrupted outside the GVL,
338
+ // this is to allow time for signal handlers to process signals.
339
+ polling_interval.tv_sec = 0;
340
+ polling_interval.tv_usec = 5;
341
+
342
+ // Define platform specific constants from headers
343
+ rb_define_const(sysvmq, "IPC_CREAT", INT2NUM(IPC_CREAT));
344
+ rb_define_const(sysvmq, "IPC_EXCL", INT2NUM(IPC_EXCL));
345
+ rb_define_const(sysvmq, "IPC_NOWAIT", INT2NUM(IPC_NOWAIT));
346
+ rb_define_const(sysvmq, "IPC_RMID", INT2NUM(IPC_RMID));
347
+ rb_define_const(sysvmq, "IPC_SET", INT2NUM(IPC_SET));
348
+ rb_define_const(sysvmq, "IPC_STAT", INT2NUM(IPC_STAT));
349
+ rb_define_const(sysvmq, "IPC_INFO", INT2NUM(IPC_INFO));
350
+
351
+ // Define the SysVMQ class and its methods
352
+ rb_define_alloc_func(sysvmq, sysvmq_alloc);
353
+ rb_define_method(sysvmq, "initialize", sysvmq_initialize, 3);
354
+ rb_define_method(sysvmq, "send", sysvmq_send, -1);
355
+ rb_define_method(sysvmq, "receive", sysvmq_receive, -1);
356
+ rb_define_method(sysvmq, "stats", sysvmq_stats, -1);
357
+ rb_define_method(sysvmq, "destroy", sysvmq_destroy, 0);
358
+ }
data/sysvmq.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "sysvmq"
7
+ spec.version = '0.0.1'
8
+ spec.authors = ["Simon Eskildsen"]
9
+ spec.email = ["sirup@sirupsen.com"]
10
+ spec.summary = %q{Ruby wrapper for SysV Message Queues}
11
+ spec.description = %q{Ruby wrapper for SysV Message Queues}
12
+ spec.homepage = "https://github.com/Sirupsen/sysvmq"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+ spec.extensions = ["ext/extconf.rb"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rake-compiler", "~> 0.9"
24
+ end
@@ -0,0 +1,114 @@
1
+ require_relative 'test_helper'
2
+
3
+ class SysVMQTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @size = 1024
6
+ @mq = SysVMQ.new(0xDEADC0DE, @size, SysVMQ::IPC_CREAT | 0666)
7
+ end
8
+
9
+ def teardown
10
+ @mq.destroy
11
+ end
12
+
13
+ def test_send_message
14
+ @mq.send("Hello world")
15
+ end
16
+
17
+ def test_send_and_receive_message
18
+ message = "Hello World"
19
+ @mq.send message
20
+ assert_equal message, @mq.receive
21
+ end
22
+
23
+ def test_send_and_count_message
24
+ @mq.send "test"
25
+ assert_equal 1, @mq.stats[:count]
26
+ @mq.send "test"
27
+ assert_equal 2, @mq.stats[:count]
28
+ end
29
+
30
+ def test_send_and_receive_many_times
31
+ many = 100_000
32
+ message = "Hello World"
33
+
34
+ many.times do
35
+ @mq.send message
36
+ assert_equal message, @mq.receive
37
+ end
38
+ end
39
+
40
+ def test_sends_and_receives_utf8
41
+ message = "simån hørup"
42
+ @mq.send message
43
+ assert_equal message, @mq.receive
44
+ end
45
+
46
+ def test_sending_5_bytes_should_report_5_byte_queue
47
+ message = "B" * 5
48
+ @mq.send message
49
+ assert_equal 5, @mq.stats[:size]
50
+ end
51
+
52
+ def test_sending_utf_should_report_correct_size_queue
53
+ message = "ø" * 5
54
+ @mq.send message
55
+ assert_equal "ø".bytes.size * 5, @mq.stats[:size]
56
+ end
57
+
58
+ def test_receive_on_empty_queue_raises_enomsg_if_ipc_nowait
59
+ assert_raises Errno::ENOMSG do
60
+ @mq.receive(0, SysVMQ::IPC_NOWAIT)
61
+ end
62
+ end
63
+
64
+ def test_send_and_receive_empty_message
65
+ @mq.send ""
66
+ assert_equal "", @mq.receive
67
+ end
68
+
69
+ def test_allow_multiple_queues_with_different_sizes
70
+ mq2 = SysVMQ.new(0xDEADCAFE, 2048, SysVMQ::IPC_CREAT | 0660)
71
+ mq2.send("B" * 2048)
72
+ mq2.destroy
73
+ end
74
+
75
+ def test_send_and_receive_with_type
76
+ @mq.send("10", 10)
77
+ @mq.send("5", 5)
78
+
79
+ assert_equal "5", @mq.receive(5)
80
+ assert_equal "10", @mq.receive(10)
81
+ end
82
+
83
+ def test_send_and_receive_with_negative_type
84
+ @mq.send("10", 10)
85
+ @mq.send("5", 5)
86
+
87
+ assert_equal "5", @mq.receive(-7)
88
+ assert_equal "10", @mq.receive(-10)
89
+ end
90
+
91
+ def test_responds_to_sigint
92
+ pid = fork {
93
+ begin
94
+ mq = SysVMQ.new(0xDEADCAFE, 2048, SysVMQ::IPC_CREAT | 0660)
95
+ mq.receive
96
+ rescue Interrupt
97
+ mq.destroy
98
+ end
99
+ }
100
+ sleep 0.01
101
+ Process.kill(:SIGINT, pid)
102
+ Process.wait(pid)
103
+ end
104
+
105
+ def test_kills_thread_cleanly
106
+ thread = Thread.new {
107
+ mq = SysVMQ.new(0xDEADCAFE, 2048, SysVMQ::IPC_CREAT | 0660)
108
+ mq.receive
109
+ }
110
+
111
+ sleep 0.01
112
+ thread.kill
113
+ end
114
+ end
@@ -0,0 +1,3 @@
1
+ require 'minitest/unit'
2
+ require 'minitest/autorun'
3
+ require 'sysvmq'
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sysvmq
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Simon Eskildsen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ description: Ruby wrapper for SysV Message Queues
56
+ email:
57
+ - sirup@sirupsen.com
58
+ executables:
59
+ - coderay
60
+ - pry
61
+ - rake
62
+ extensions:
63
+ - ext/extconf.rb
64
+ extra_rdoc_files: []
65
+ files:
66
+ - ".gitignore"
67
+ - ".travis.yml"
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/coderay
73
+ - bin/pry
74
+ - bin/rake
75
+ - ext/extconf.rb
76
+ - ext/sysvmq.c
77
+ - sysvmq.gemspec
78
+ - test/sysv_mq_test.rb
79
+ - test/test_helper.rb
80
+ homepage: https://github.com/Sirupsen/sysvmq
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.2.0
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Ruby wrapper for SysV Message Queues
104
+ test_files:
105
+ - test/sysv_mq_test.rb
106
+ - test/test_helper.rb