posix_mq 0.3.1 → 0.4.0
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.
- data/README +10 -0
- data/ext/posix_mq/posix_mq.c +54 -60
- data/lib/posix_mq.rb +15 -4
- data/test/test_posix_mq.rb +17 -0
- metadata +2 -2
data/README
CHANGED
@@ -109,3 +109,13 @@ don't email the git mailing list or maintainer with posix_mq patches.
|
|
109
109
|
|
110
110
|
All feedback (bug reports, user/development discussion, patches, pull
|
111
111
|
requests) go to the mailing list: mailto:ruby.posix.mq@librelist.com
|
112
|
+
|
113
|
+
== Mailing List Archives
|
114
|
+
|
115
|
+
In addition to the rsync-able archives provided by http://librelist.com/, we
|
116
|
+
are also mirrored to
|
117
|
+
{Gmane}[http://gmane.org/info.php?group=gmane.comp.lang.ruby.posix-mq.general]
|
118
|
+
and maintain our own mbox mirrors downloadable via HTTP.
|
119
|
+
|
120
|
+
* nntp://news.gmane.org/gmane.comp.lang.ruby.posix-mq.general
|
121
|
+
* http://bogomips.org/ruby_posix_mq/archives/
|
data/ext/posix_mq/posix_mq.c
CHANGED
@@ -23,7 +23,6 @@
|
|
23
23
|
#elif defined(HAVE___MQ_OSHANDLE) /* FreeBSD */
|
24
24
|
# define MQD_TO_FD(mqd) __mq_oshandle(mqd)
|
25
25
|
#else
|
26
|
-
# warning mqd_t is not select()-able on your OS
|
27
26
|
# define MQ_IO_MARK(mq) ((void)(0))
|
28
27
|
# define MQ_IO_SET(mq,val) ((void)(0))
|
29
28
|
#endif
|
@@ -35,7 +34,7 @@
|
|
35
34
|
|
36
35
|
struct posix_mq {
|
37
36
|
mqd_t des;
|
38
|
-
|
37
|
+
struct mq_attr attr;
|
39
38
|
VALUE name;
|
40
39
|
VALUE thread;
|
41
40
|
#ifdef MQD_TO_FD
|
@@ -127,14 +126,14 @@ struct rw_args {
|
|
127
126
|
/* hope it's there..., TODO: a better version that works in rbx */
|
128
127
|
struct timeval rb_time_interval(VALUE);
|
129
128
|
|
130
|
-
static struct timespec *convert_timeout(struct timespec *dest, VALUE
|
129
|
+
static struct timespec *convert_timeout(struct timespec *dest, VALUE t)
|
131
130
|
{
|
132
131
|
struct timeval tv, now;
|
133
132
|
|
134
|
-
if (NIL_P(
|
133
|
+
if (NIL_P(t))
|
135
134
|
return NULL;
|
136
135
|
|
137
|
-
tv = rb_time_interval(
|
136
|
+
tv = rb_time_interval(t); /* aggregate return :( */
|
138
137
|
gettimeofday(&now, NULL);
|
139
138
|
dest->tv_sec = now.tv_sec + tv.tv_sec;
|
140
139
|
dest->tv_nsec = (now.tv_usec + tv.tv_usec) * 1000;
|
@@ -147,7 +146,7 @@ static struct timespec *convert_timeout(struct timespec *dest, VALUE time)
|
|
147
146
|
return dest;
|
148
147
|
}
|
149
148
|
|
150
|
-
/*
|
149
|
+
/* (may) run without GVL */
|
151
150
|
static VALUE xopen(void *ptr)
|
152
151
|
{
|
153
152
|
struct open_args *x = ptr;
|
@@ -187,14 +186,6 @@ static VALUE xrecv(void *ptr)
|
|
187
186
|
return (VALUE)mq_receive(x->des, x->msg_ptr, x->msg_len, &x->msg_prio);
|
188
187
|
}
|
189
188
|
|
190
|
-
/* runs without GVL, path resolution may be slow */
|
191
|
-
static VALUE xunlink(void *ptr)
|
192
|
-
{
|
193
|
-
VALUE name = (VALUE)ptr;
|
194
|
-
|
195
|
-
return (VALUE)mq_unlink(RSTRING_PTR(name));
|
196
|
-
}
|
197
|
-
|
198
189
|
/* called by GC */
|
199
190
|
static void mark(void *ptr)
|
200
191
|
{
|
@@ -227,7 +218,10 @@ static VALUE alloc(VALUE klass)
|
|
227
218
|
VALUE rv = Data_Make_Struct(klass, struct posix_mq, mark, _free, mq);
|
228
219
|
|
229
220
|
mq->des = MQD_INVALID;
|
230
|
-
mq->
|
221
|
+
mq->attr.mq_flags = 0;
|
222
|
+
mq->attr.mq_maxmsg = 0;
|
223
|
+
mq->attr.mq_msgsize = -1;
|
224
|
+
mq->attr.mq_curmsgs = 0;
|
231
225
|
mq->name = Qnil;
|
232
226
|
mq->thread = Qnil;
|
233
227
|
MQ_IO_SET(mq, Qnil);
|
@@ -358,11 +352,13 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
|
|
358
352
|
RSTRING_PTR(rb_inspect(attr)));
|
359
353
|
}
|
360
354
|
|
361
|
-
mq->des = (mqd_t)
|
355
|
+
mq->des = (mqd_t)xopen(&x);
|
362
356
|
if (mq->des == MQD_INVALID)
|
363
357
|
rb_sys_fail("mq_open");
|
364
358
|
|
365
359
|
mq->name = rb_str_dup(name);
|
360
|
+
if (x.oflags & O_NONBLOCK)
|
361
|
+
mq->attr.mq_flags = O_NONBLOCK;
|
366
362
|
|
367
363
|
return self;
|
368
364
|
}
|
@@ -377,12 +373,11 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
|
|
377
373
|
static VALUE s_unlink(VALUE self, VALUE name)
|
378
374
|
{
|
379
375
|
mqd_t rv;
|
380
|
-
void *ptr = (void *)name;
|
381
376
|
|
382
377
|
if (TYPE(name) != T_STRING)
|
383
378
|
rb_raise(rb_eArgError, "argument must be a string");
|
384
379
|
|
385
|
-
rv = (
|
380
|
+
rv = mq_unlink(RSTRING_PTR(name));
|
386
381
|
if (rv == MQD_INVALID)
|
387
382
|
rb_sys_fail("mq_unlink");
|
388
383
|
|
@@ -403,11 +398,10 @@ static VALUE _unlink(VALUE self)
|
|
403
398
|
{
|
404
399
|
struct posix_mq *mq = get(self, 0);
|
405
400
|
mqd_t rv;
|
406
|
-
void *ptr = (void *)mq->name;
|
407
401
|
|
408
402
|
assert(TYPE(mq->name) == T_STRING && "mq->name is not a string");
|
409
403
|
|
410
|
-
rv = (
|
404
|
+
rv = mq_unlink(RSTRING_PTR(mq->name));
|
411
405
|
if (rv == MQD_INVALID)
|
412
406
|
rb_sys_fail("mq_unlink");
|
413
407
|
|
@@ -446,7 +440,11 @@ static VALUE _send(int argc, VALUE *argv, VALUE self)
|
|
446
440
|
x.timeout = convert_timeout(&expire, timeout);
|
447
441
|
x.msg_prio = NIL_P(prio) ? 0 : NUM2UINT(prio);
|
448
442
|
|
449
|
-
|
443
|
+
if (mq->attr.mq_flags & O_NONBLOCK)
|
444
|
+
rv = (mqd_t)xsend(&x);
|
445
|
+
else
|
446
|
+
rv = (mqd_t)rb_thread_blocking_region(xsend, &x,
|
447
|
+
RUBY_UBF_IO, 0);
|
450
448
|
if (rv == MQD_INVALID)
|
451
449
|
rb_sys_fail("mq_send");
|
452
450
|
|
@@ -471,7 +469,12 @@ static VALUE send0(VALUE self, VALUE buffer)
|
|
471
469
|
x.timeout = NULL;
|
472
470
|
x.msg_prio = 0;
|
473
471
|
|
474
|
-
|
472
|
+
if (mq->attr.mq_flags & O_NONBLOCK)
|
473
|
+
rv = (mqd_t)xsend(&x);
|
474
|
+
else
|
475
|
+
rv = (mqd_t)rb_thread_blocking_region(xsend, &x,
|
476
|
+
RUBY_UBF_IO, 0);
|
477
|
+
|
475
478
|
if (rv == MQD_INVALID)
|
476
479
|
rb_sys_fail("mq_send");
|
477
480
|
|
@@ -484,7 +487,7 @@ static VALUE send0(VALUE self, VALUE buffer)
|
|
484
487
|
* mq.to_io => IO
|
485
488
|
*
|
486
489
|
* Returns an IO.select-able +IO+ object. This method is only available
|
487
|
-
* under Linux and is not intended to be portable.
|
490
|
+
* under Linux and FreeBSD and is not intended to be portable.
|
488
491
|
*/
|
489
492
|
static VALUE to_io(VALUE self)
|
490
493
|
{
|
@@ -498,16 +501,6 @@ static VALUE to_io(VALUE self)
|
|
498
501
|
}
|
499
502
|
#endif
|
500
503
|
|
501
|
-
static void get_msgsize(struct posix_mq *mq)
|
502
|
-
{
|
503
|
-
struct mq_attr attr;
|
504
|
-
|
505
|
-
if (mq_getattr(mq->des, &attr) < 0)
|
506
|
-
rb_sys_fail("mq_getattr");
|
507
|
-
|
508
|
-
mq->msgsize = attr.mq_msgsize;
|
509
|
-
}
|
510
|
-
|
511
504
|
static VALUE _receive(int wantarray, int argc, VALUE *argv, VALUE self);
|
512
505
|
|
513
506
|
/*
|
@@ -559,25 +552,32 @@ static VALUE _receive(int wantarray, int argc, VALUE *argv, VALUE self)
|
|
559
552
|
ssize_t r;
|
560
553
|
struct timespec expire;
|
561
554
|
|
562
|
-
if (mq->
|
563
|
-
|
555
|
+
if (mq->attr.mq_msgsize < 0) {
|
556
|
+
if (mq_getattr(mq->des, &mq->attr) < 0)
|
557
|
+
rb_sys_fail("mq_getattr");
|
558
|
+
}
|
564
559
|
|
565
560
|
rb_scan_args(argc, argv, "02", &buffer, &timeout);
|
566
561
|
x.timeout = convert_timeout(&expire, timeout);
|
567
562
|
|
568
563
|
if (NIL_P(buffer)) {
|
569
|
-
buffer = rb_str_new(0, mq->
|
564
|
+
buffer = rb_str_new(0, mq->attr.mq_msgsize);
|
570
565
|
} else {
|
571
566
|
StringValue(buffer);
|
572
567
|
rb_str_modify(buffer);
|
573
|
-
rb_str_resize(buffer, mq->
|
568
|
+
rb_str_resize(buffer, mq->attr.mq_msgsize);
|
574
569
|
}
|
575
570
|
OBJ_TAINT(buffer);
|
576
571
|
x.msg_ptr = RSTRING_PTR(buffer);
|
577
|
-
x.msg_len = (size_t)mq->
|
572
|
+
x.msg_len = (size_t)mq->attr.mq_msgsize;
|
578
573
|
x.des = mq->des;
|
579
574
|
|
580
|
-
|
575
|
+
if (mq->attr.mq_flags & O_NONBLOCK) {
|
576
|
+
r = (ssize_t)xrecv(&x);
|
577
|
+
} else {
|
578
|
+
r = (ssize_t)rb_thread_blocking_region(xrecv, &x,
|
579
|
+
RUBY_UBF_IO, 0);
|
580
|
+
}
|
581
581
|
if (r < 0)
|
582
582
|
rb_sys_fail("mq_receive");
|
583
583
|
|
@@ -599,19 +599,18 @@ static VALUE _receive(int wantarray, int argc, VALUE *argv, VALUE self)
|
|
599
599
|
static VALUE getattr(VALUE self)
|
600
600
|
{
|
601
601
|
struct posix_mq *mq = get(self, 1);
|
602
|
-
struct mq_attr attr;
|
603
602
|
VALUE astruct;
|
604
603
|
VALUE *ptr;
|
605
604
|
|
606
|
-
if (mq_getattr(mq->des, &attr) < 0)
|
605
|
+
if (mq_getattr(mq->des, &mq->attr) < 0)
|
607
606
|
rb_sys_fail("mq_getattr");
|
608
607
|
|
609
608
|
astruct = rb_struct_alloc_noinit(cAttr);
|
610
609
|
ptr = RSTRUCT_PTR(astruct);
|
611
|
-
ptr[0] = LONG2NUM(attr.mq_flags);
|
612
|
-
ptr[1] = LONG2NUM(attr.mq_maxmsg);
|
613
|
-
ptr[2] = LONG2NUM(attr.mq_msgsize);
|
614
|
-
ptr[3] = LONG2NUM(attr.mq_curmsgs);
|
610
|
+
ptr[0] = LONG2NUM(mq->attr.mq_flags);
|
611
|
+
ptr[1] = LONG2NUM(mq->attr.mq_maxmsg);
|
612
|
+
ptr[2] = LONG2NUM(mq->attr.mq_msgsize);
|
613
|
+
ptr[3] = LONG2NUM(mq->attr.mq_curmsgs);
|
615
614
|
|
616
615
|
return astruct;
|
617
616
|
}
|
@@ -686,7 +685,7 @@ static VALUE name(VALUE self)
|
|
686
685
|
{
|
687
686
|
struct posix_mq *mq = get(self, 0);
|
688
687
|
|
689
|
-
return mq->name;
|
688
|
+
return rb_str_dup(mq->name);
|
690
689
|
}
|
691
690
|
|
692
691
|
static int lookup_sig(VALUE sig)
|
@@ -725,10 +724,13 @@ static void thread_notify_fd(union sigval sv)
|
|
725
724
|
while ((write(fd, "", 1) < 0) && (errno == EINTR || errno == EAGAIN));
|
726
725
|
}
|
727
726
|
|
727
|
+
/*
|
728
|
+
* TODO: Under Linux, we could just use netlink directly
|
729
|
+
* the same way glibc does...
|
730
|
+
*/
|
728
731
|
static void setup_notify_io(struct sigevent *not, VALUE io)
|
729
732
|
{
|
730
|
-
|
731
|
-
int fd = NUM2INT(fileno);
|
733
|
+
int fd = NUM2INT(rb_funcall(io, id_fileno, 0, 0));
|
732
734
|
pthread_attr_t attr;
|
733
735
|
int e;
|
734
736
|
|
@@ -738,8 +740,6 @@ static void setup_notify_io(struct sigevent *not, VALUE io)
|
|
738
740
|
goto err;
|
739
741
|
#ifdef PTHREAD_STACK_MIN
|
740
742
|
(void)pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
|
741
|
-
#else
|
742
|
-
# warning PTHREAD_STACK_MIN not available,
|
743
743
|
#endif
|
744
744
|
not->sigev_notify = SIGEV_THREAD;
|
745
745
|
not->sigev_notify_function = thread_notify_fd;
|
@@ -824,15 +824,9 @@ static VALUE setnotify(VALUE self, VALUE arg)
|
|
824
824
|
*/
|
825
825
|
static VALUE getnonblock(VALUE self)
|
826
826
|
{
|
827
|
-
struct mq_attr attr;
|
828
827
|
struct posix_mq *mq = get(self, 1);
|
829
828
|
|
830
|
-
|
831
|
-
rb_sys_fail("mq_getattr");
|
832
|
-
|
833
|
-
mq->msgsize = attr.mq_msgsize; /* optimization */
|
834
|
-
|
835
|
-
return attr.mq_flags & O_NONBLOCK ? Qtrue : Qfalse;
|
829
|
+
return mq->attr.mq_flags & O_NONBLOCK ? Qtrue : Qfalse;
|
836
830
|
}
|
837
831
|
|
838
832
|
/*
|
@@ -846,7 +840,7 @@ static VALUE getnonblock(VALUE self)
|
|
846
840
|
*/
|
847
841
|
static VALUE setnonblock(VALUE self, VALUE nb)
|
848
842
|
{
|
849
|
-
struct mq_attr newattr
|
843
|
+
struct mq_attr newattr;
|
850
844
|
struct posix_mq *mq = get(self, 1);
|
851
845
|
|
852
846
|
if (nb == Qtrue)
|
@@ -856,10 +850,10 @@ static VALUE setnonblock(VALUE self, VALUE nb)
|
|
856
850
|
else
|
857
851
|
rb_raise(rb_eArgError, "must be true or false");
|
858
852
|
|
859
|
-
if (mq_setattr(mq->des, &newattr, &
|
853
|
+
if (mq_setattr(mq->des, &newattr, &mq->attr) < 0)
|
860
854
|
rb_sys_fail("mq_setattr");
|
861
855
|
|
862
|
-
mq->
|
856
|
+
mq->attr.mq_flags = newattr.mq_flags;
|
863
857
|
|
864
858
|
return nb;
|
865
859
|
}
|
data/lib/posix_mq.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
class POSIX_MQ
|
3
3
|
|
4
|
-
# version of POSIX_MQ, currently 0.
|
5
|
-
VERSION = '0.
|
4
|
+
# version of POSIX_MQ, currently 0.4.0
|
5
|
+
VERSION = '0.4.0'
|
6
6
|
|
7
7
|
# An analogous Struct to "struct mq_attr" in C.
|
8
8
|
# This may be used in arguments for POSIX_MQ.new and
|
@@ -47,7 +47,7 @@ class POSIX_MQ
|
|
47
47
|
block.arity == 1 or
|
48
48
|
raise ArgumentError, "arity of notify block must be 1"
|
49
49
|
r, w = IO.pipe
|
50
|
-
|
50
|
+
self.notify_thread = Thread.new(r, w, self) do |r, w, mq|
|
51
51
|
begin
|
52
52
|
begin
|
53
53
|
r.read(1) or raise Errno::EINTR
|
@@ -62,10 +62,21 @@ class POSIX_MQ
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
self.notify = w
|
65
|
-
self.notify_thread = thr
|
66
65
|
nil
|
67
66
|
end if RUBY_PLATFORM =~ /linux/
|
68
67
|
|
68
|
+
# There's no point in ever duping a POSIX_MQ object.
|
69
|
+
# All send/receive operations are atomic and only one
|
70
|
+
# native thread may be notified at a time
|
71
|
+
def dup
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# There's no point in ever cloning a POSIX_MQ object.
|
76
|
+
# All send/receive operations are atomic and only one
|
77
|
+
# native thread may be notified at a time
|
78
|
+
alias clone dup
|
79
|
+
|
69
80
|
end
|
70
81
|
|
71
82
|
require 'posix_mq_ext'
|
data/test/test_posix_mq.rb
CHANGED
@@ -27,6 +27,23 @@ class Test_POSIX_MQ < Test::Unit::TestCase
|
|
27
27
|
assert @mq.closed?
|
28
28
|
end
|
29
29
|
|
30
|
+
def test_name_clobber_proof
|
31
|
+
@mq = POSIX_MQ.new(@path, :rw)
|
32
|
+
tmp = @mq.name
|
33
|
+
tmp.freeze
|
34
|
+
assert_nothing_raised { @mq.name.gsub!(/\A/, "foo") }
|
35
|
+
assert_equal tmp, @mq.name
|
36
|
+
assert tmp.object_id != @mq.name.object_id
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_dup_clone
|
40
|
+
@mq = POSIX_MQ.new(@path, :rw)
|
41
|
+
dup = @mq.dup
|
42
|
+
assert_equal @mq.object_id, dup.object_id
|
43
|
+
clone = @mq.clone
|
44
|
+
assert_equal @mq.object_id, clone.object_id
|
45
|
+
end
|
46
|
+
|
30
47
|
def test_timed_receive
|
31
48
|
interval = 0.01
|
32
49
|
@mq = POSIX_MQ.new(@path, :rw)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: posix_mq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruby POSIX MQ hackers
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-03-13 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|