posix_mq 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|