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 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