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 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/
@@ -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
- long msgsize;
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 time)
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(time))
133
+ if (NIL_P(t))
135
134
  return NULL;
136
135
 
137
- tv = rb_time_interval(time); /* aggregate return :( */
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
- /* runs without GVL */
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->msgsize = -1;
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)rb_thread_blocking_region(xopen, &x, RUBY_UBF_IO, 0);
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 = (mqd_t)rb_thread_blocking_region(xunlink, ptr, RUBY_UBF_IO, 0);
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 = (mqd_t)rb_thread_blocking_region(xunlink, ptr, RUBY_UBF_IO, 0);
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
- rv = (mqd_t)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0);
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
- rv = (mqd_t)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0);
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->msgsize < 0)
563
- get_msgsize(mq);
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->msgsize);
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->msgsize);
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->msgsize;
572
+ x.msg_len = (size_t)mq->attr.mq_msgsize;
578
573
  x.des = mq->des;
579
574
 
580
- r = (ssize_t)rb_thread_blocking_region(xrecv, &x, RUBY_UBF_IO, 0);
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
- VALUE fileno = rb_funcall(io, id_fileno, 0, 0);
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
- if (mq_getattr(mq->des, &attr) < 0)
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, oldattr;
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, &oldattr) < 0)
853
+ if (mq_setattr(mq->des, &newattr, &mq->attr) < 0)
860
854
  rb_sys_fail("mq_setattr");
861
855
 
862
- mq->msgsize = oldattr.mq_msgsize; /* optimization */
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.3.1
5
- VERSION = '0.3.1'
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
- thr = Thread.new(r, w, self) do |r, w, mq|
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'
@@ -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.3.1
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-02-13 00:00:00 +00:00
12
+ date: 2010-03-13 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies: []
15
15