posix_mq 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,5 +1,119 @@
1
1
  ChangeLog from git://git.bogomips.org/ruby_posix_mq.git ()
2
2
 
3
+ commit 2e420820d3b3fb228c810937539f95a618a2c271
4
+ Author: Eric Wong <normalperson@yhbt.net>
5
+ Date: Sat Jan 9 22:52:27 2010 +0000
6
+
7
+ posix_mq 0.3.0
8
+
9
+ This release adds a few new API methods, fixes MRI 1.8.6
10
+ support. We should now have full feature parity with
11
+ underlying POSIX message queue C API.
12
+
13
+ * POSIX_MQ#notify(&block)
14
+ RDoc: http://bogomips.org/ruby_posix_mq/POSIX_MQ.html#M000001
15
+ This is only supported on platforms that implement
16
+ SIGEV_THREAD with mq_notify(3) (tested with glibc + Linux).
17
+ Other platforms will have to continue to rely on signal
18
+ notifications via POSIX#notify=signal, or IO notifications
19
+ in FreeBSD (and Linux).
20
+
21
+ * POSIX_MQ#shift([buffer [,timeout]])
22
+ Shorthand for the common "POSIX_MQ#receive.first"
23
+ when you do not care for priority of the received message.
24
+
25
+ Rev, EventMachine and Reactor support are planned for
26
+ Linux, FreeBSD and possibly any other platforms where POSIX
27
+ message queues are implemented with a file descriptor.
28
+
29
+ commit 2c71257b2b95e737088726ffc963b4e72f1b5455
30
+ Author: Eric Wong <normalperson@yhbt.net>
31
+ Date: Sat Jan 9 22:49:49 2010 +0000
32
+
33
+ MRI 1.8 does not have rb_str_flush
34
+
35
+ It's Rubinius-specific and we use rb_str_resize
36
+ there anyways...
37
+
38
+ commit 531106e51e519458d37bed3721da4eff2f163206
39
+ Author: Eric Wong <normalperson@yhbt.net>
40
+ Date: Fri Jan 8 11:30:49 2010 -0800
41
+
42
+ no point in non-blocking for fd notifications
43
+
44
+ It's not needed since the native thread will retry in the
45
+ unlikely case of EINTR/EAGAIN. And writing one byte to a pipe
46
+ that's guaranteed by POSIX to be at least 512 bytes is highly
47
+ unlikely.
48
+
49
+ It's also bad because F_SETFL takes the big kernel lock under
50
+ Linux (and possibly other systems), and doing it unnecessarily
51
+ is a waste of system cycles.
52
+
53
+ commit d03c76ae11ca6294e05262df747e4d43822ada73
54
+ Author: Eric Wong <normalperson@yhbt.net>
55
+ Date: Fri Jan 8 11:25:06 2010 -0800
56
+
57
+ mode_t is usually unsigned
58
+
59
+ Most used open modes are well under INT_MAX, however
60
+
61
+ commit b3c31cf444e2ca3dae0f6d2370944bfbf3382d88
62
+ Author: Eric Wong <normalperson@yhbt.net>
63
+ Date: Thu Jan 7 01:45:25 2010 -0800
64
+
65
+ add POSIX_MQ#shift helper method
66
+
67
+ This acts like POSIX_MQ#receive but only returns the message
68
+ without the priority.
69
+
70
+ commit 3700db51399e4949ed314ad0545d037b7762064e
71
+ Author: Eric Wong <normalperson@yhbt.net>
72
+ Date: Thu Jan 7 09:28:57 2010 +0000
73
+
74
+ POSIX_MQ#notify only works on GNU/Linux for now
75
+
76
+ SIGEV_THREAD is not easy to implement, so many platforms
77
+ do not implement it.
78
+
79
+ commit 40d61f55ac53e3cd2f229d0b032da03032e3d53d
80
+ Author: Eric Wong <normalperson@yhbt.net>
81
+ Date: Thu Jan 7 00:37:57 2010 -0800
82
+
83
+ POSIX_MQ#notify block execution on message received
84
+
85
+ This is implementation uses both a short-lived POSIX thread and
86
+ a pre-spawned Ruby Thread in a manner that works properly under
87
+ both Ruby 1.8 (green threads) and 1.9 (where Ruby Threads are
88
+ POSIX threads).
89
+
90
+ The short-lived POSIX thread will write a single "\0" byte to
91
+ a pipe the Ruby Thread waits on. This operation is atomic
92
+ on all platforms. Once the Ruby Thread is woken up from the
93
+ pipe, it will execute th block given to it.
94
+
95
+ This dual-thread implementation is inspired by the way glibc
96
+ implements mq_notify(3) + SIGEV_THREAD under Linux where the
97
+ kernel itself cannot directly spawn POSIX threads.
98
+
99
+ commit d8c8fb4155c1feea454abc3ed3f0a4b26e90be68
100
+ Author: Eric Wong <normalperson@yhbt.net>
101
+ Date: Sun Jan 3 05:26:00 2010 +0000
102
+
103
+ fix warnings on platforms where mqd_t != int
104
+
105
+ The POSIX manpages specify the return values of all
106
+ mq_* functions besides mq_open(3) to be "int", not "mqd_t".
107
+
108
+ commit dbe5ed46e07b853e79e44141924a0166016e3e44
109
+ Author: Eric Wong <normalperson@yhbt.net>
110
+ Date: Sat Jan 2 23:19:34 2010 -0800
111
+
112
+ bump GIT-VERSION-GEN
113
+
114
+ Shouldn't affect most people since they should just
115
+ take code from git...
116
+
3
117
  commit fd2fcdeee6b44f7854255cb7e01c81db3cd2d99c
4
118
  Author: Eric Wong <normalperson@yhbt.net>
5
119
  Date: Sun Jan 3 05:46:45 2010 +0000
data/GIT-VERSION-FILE CHANGED
@@ -1 +1 @@
1
- GIT_VERSION = 0.2.0
1
+ GIT_VERSION = 0.3.0
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.1.0.GIT
4
+ DEF_VER=v0.3.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/NEWS CHANGED
@@ -1,3 +1,25 @@
1
+ === 0.3.0 / 2010-01-09 23:11 UTC
2
+
3
+ This release adds a few new API methods, fixes MRI 1.8.6
4
+ support. We should now have full feature parity with
5
+ underlying POSIX message queue C API.
6
+
7
+ * POSIX_MQ#notify(&block)
8
+ RDoc: http://bogomips.org/ruby_posix_mq/POSIX_MQ.html#M000001
9
+ This is only supported on platforms that implement
10
+ SIGEV_THREAD with mq_notify(3) (tested with glibc + Linux).
11
+ Other platforms will have to continue to rely on signal
12
+ notifications via POSIX#notify=signal, or IO notifications
13
+ in FreeBSD (and Linux).
14
+
15
+ * POSIX_MQ#shift([buffer [,timeout]])
16
+ Shorthand for the common "POSIX_MQ#receive.first"
17
+ when you do not care for priority of the received message.
18
+
19
+ Rev, EventMachine and Reactor support are planned for
20
+ Linux, FreeBSD and possibly any other platforms where POSIX
21
+ message queues are implemented with a file descriptor.
22
+
1
23
  === 0.2.0 / 2010-01-03 05:52 UTC
2
24
 
3
25
  This release fixes notification (un)registration and should be
data/README CHANGED
@@ -11,15 +11,20 @@ network-aware message queue implementations.
11
11
 
12
12
  == Features
13
13
 
14
- * Supports message notifications via signals.
14
+ * Supports message notifications via signals on all platforms
15
15
 
16
16
  * Supports portable non-blocking operation. Under Linux 2.6.6+ and
17
17
  FreeBSD 7.2+, POSIX_MQ objects may even be used with event
18
18
  notification mechanisms such as IO.select.
19
19
 
20
+ * Supports notifications via block execution in a separate thread
21
+ on platforms that implement SIGEV_THREAD for mq_notify(3),
22
+ currently only GNU/Linux.
23
+
20
24
  * Optional timeouts may be applied to send and receive operations.
21
25
 
22
- * Thread-safe under Ruby 1.9, releases GVL before blocking operations.
26
+ * Thread-safe blocking operations under Ruby 1.9, releases GVL
27
+ before blocking operations.
23
28
 
24
29
  * Documented library API
25
30
 
@@ -4,9 +4,11 @@ have_header("sys/select.h")
4
4
  have_header("signal.h")
5
5
  have_header("mqueue.h") or abort "mqueue.h header missing"
6
6
  have_func("__mq_oshandle")
7
+ have_header("pthread.h")
7
8
  have_func("rb_str_set_len")
8
9
  have_func("rb_struct_alloc_noinit")
9
10
  have_func('rb_thread_blocking_region')
10
11
  have_library("rt")
12
+ have_library("pthread")
11
13
  dir_config("posix_mq")
12
14
  create_makefile("posix_mq_ext")
@@ -5,6 +5,9 @@
5
5
  #ifdef HAVE_SIGNAL_H
6
6
  # include <signal.h>
7
7
  #endif
8
+ #ifdef HAVE_PTHREAD_H
9
+ # include <pthread.h>
10
+ #endif
8
11
  #include <ruby.h>
9
12
 
10
13
  #include <time.h>
@@ -34,13 +37,14 @@ struct posix_mq {
34
37
  mqd_t des;
35
38
  long msgsize;
36
39
  VALUE name;
40
+ VALUE thread;
37
41
  #ifdef MQD_TO_FD
38
42
  VALUE io;
39
43
  #endif
40
44
  };
41
45
 
42
46
  static VALUE cPOSIX_MQ, cAttr;
43
- static ID id_new;
47
+ static ID id_new, id_kill, id_fileno;
44
48
  static ID sym_r, sym_w, sym_rw;
45
49
  static const mqd_t MQD_INVALID = (mqd_t)-1;
46
50
 
@@ -67,7 +71,6 @@ static void rb_18_str_set_len(VALUE str, long len)
67
71
  {
68
72
  RSTRING(str)->len = len;
69
73
  RSTRING(str)->ptr[len] = '\0';
70
- rb_str_flush(str);
71
74
  }
72
75
  # define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
73
76
  # endif /* ! RUBINIUS */
@@ -198,6 +201,7 @@ static void mark(void *ptr)
198
201
  struct posix_mq *mq = ptr;
199
202
 
200
203
  rb_gc_mark(mq->name);
204
+ rb_gc_mark(mq->thread);
201
205
  MQ_IO_MARK(mq);
202
206
  }
203
207
 
@@ -225,6 +229,7 @@ static VALUE alloc(VALUE klass)
225
229
  mq->des = MQD_INVALID;
226
230
  mq->msgsize = -1;
227
231
  mq->name = Qnil;
232
+ mq->thread = Qnil;
228
233
  MQ_IO_SET(mq, Qnil);
229
234
 
230
235
  return rv;
@@ -325,7 +330,7 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
325
330
  switch (TYPE(mode)) {
326
331
  case T_FIXNUM:
327
332
  x.argc = 3;
328
- x.mode = NUM2INT(mode);
333
+ x.mode = NUM2UINT(mode);
329
334
  break;
330
335
  case T_NIL:
331
336
  if (x.oflags & O_CREAT) {
@@ -497,12 +502,14 @@ static void get_msgsize(struct posix_mq *mq)
497
502
  {
498
503
  struct mq_attr attr;
499
504
 
500
- if (mq_getattr(mq->des, &attr) == MQD_INVALID)
505
+ if (mq_getattr(mq->des, &attr) < 0)
501
506
  rb_sys_fail("mq_getattr");
502
507
 
503
508
  mq->msgsize = attr.mq_msgsize;
504
509
  }
505
510
 
511
+ static VALUE _receive(int wantarray, int argc, VALUE *argv, VALUE self);
512
+
506
513
  /*
507
514
  * call-seq:
508
515
  * mq.receive([buffer, [timeout]]) => [ message, priority ]
@@ -520,6 +527,31 @@ static void get_msgsize(struct posix_mq *mq)
520
527
  * in the queue.
521
528
  */
522
529
  static VALUE receive(int argc, VALUE *argv, VALUE self)
530
+ {
531
+ return _receive(1, argc, argv, self);
532
+ }
533
+
534
+ /*
535
+ * call-seq:
536
+ * mq.shift([buffer, [timeout]]) => message
537
+ *
538
+ * Takes the highest priority message off the queue and returns
539
+ * the message as a String.
540
+ *
541
+ * If the optional +buffer+ is present, then it must be a String
542
+ * which will receive the data.
543
+ *
544
+ * If the optional +timeout+ is present, then it may be a Float
545
+ * or Integer specifying the timeout in seconds. Errno::ETIMEDOUT
546
+ * will be raised if +timeout+ has elapsed and there are no messages
547
+ * in the queue.
548
+ */
549
+ static VALUE shift(int argc, VALUE *argv, VALUE self)
550
+ {
551
+ return _receive(0, argc, argv, self);
552
+ }
553
+
554
+ static VALUE _receive(int wantarray, int argc, VALUE *argv, VALUE self)
523
555
  {
524
556
  struct posix_mq *mq = get(self, 1);
525
557
  struct rw_args x;
@@ -551,7 +583,9 @@ static VALUE receive(int argc, VALUE *argv, VALUE self)
551
583
 
552
584
  rb_str_set_len(buffer, r);
553
585
 
554
- return rb_ary_new3(2, buffer, UINT2NUM(x.msg_prio));
586
+ if (wantarray)
587
+ return rb_ary_new3(2, buffer, UINT2NUM(x.msg_prio));
588
+ return buffer;
555
589
  }
556
590
 
557
591
  /*
@@ -569,7 +603,7 @@ static VALUE getattr(VALUE self)
569
603
  VALUE astruct;
570
604
  VALUE *ptr;
571
605
 
572
- if (mq_getattr(mq->des, &attr) == MQD_INVALID)
606
+ if (mq_getattr(mq->des, &attr) < 0)
573
607
  rb_sys_fail("mq_getattr");
574
608
 
575
609
  astruct = rb_struct_alloc_noinit(cAttr);
@@ -599,7 +633,7 @@ static VALUE setattr(VALUE self, VALUE astruct)
599
633
 
600
634
  attr_from_struct(&newattr, astruct, 0);
601
635
 
602
- if (mq_setattr(mq->des, &newattr, NULL) == MQD_INVALID)
636
+ if (mq_setattr(mq->des, &newattr, NULL) < 0)
603
637
  rb_sys_fail("mq_setattr");
604
638
 
605
639
  return astruct;
@@ -619,7 +653,7 @@ static VALUE _close(VALUE self)
619
653
  {
620
654
  struct posix_mq *mq = get(self, 1);
621
655
 
622
- if (mq_close(mq->des) == MQD_INVALID)
656
+ if (mq_close(mq->des) < 0)
623
657
  rb_sys_fail("mq_close");
624
658
 
625
659
  mq->des = MQD_INVALID;
@@ -683,6 +717,39 @@ static int lookup_sig(VALUE sig)
683
717
  return NUM2INT(sig);
684
718
  }
685
719
 
720
+ /* we spawn a thread just to write ONE byte into an fd (usually a pipe) */
721
+ static void thread_notify_fd(union sigval sv)
722
+ {
723
+ int fd = sv.sival_int;
724
+
725
+ while ((write(fd, "", 1) < 0) && (errno == EINTR || errno == EAGAIN));
726
+ }
727
+
728
+ static void setup_notify_io(struct sigevent *not, VALUE io)
729
+ {
730
+ VALUE fileno = rb_funcall(io, id_fileno, 0, 0);
731
+ int fd = NUM2INT(fileno);
732
+ pthread_attr_t attr;
733
+ int e;
734
+
735
+ if ((e = pthread_attr_init(&attr)))
736
+ goto err;
737
+ if ((e = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)))
738
+ goto err;
739
+ #ifdef PTHREAD_STACK_MIN
740
+ (void)pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
741
+ #else
742
+ # warning PTHREAD_STACK_MIN not available,
743
+ #endif
744
+ not->sigev_notify = SIGEV_THREAD;
745
+ not->sigev_notify_function = thread_notify_fd;
746
+ not->sigev_notify_attributes = &attr;
747
+ not->sigev_value.sival_int = fd;
748
+ return;
749
+ err:
750
+ rb_raise(rb_eRuntimeError, "pthread failure: %s\n", strerror(e));
751
+ }
752
+
686
753
  /*
687
754
  * call-seq:
688
755
  * mq.notify = signal => signal
@@ -693,10 +760,16 @@ static int lookup_sig(VALUE sig)
693
760
  * request to allow other processes to register a request.
694
761
  * If +signal+ is +false+, it will register a no-op notification request
695
762
  * which will prevent other processes from registering a notification.
763
+ * If +signal+ is an +IO+ object, it will spawn a thread upon the
764
+ * arrival of the next message and write one "\\0" byte to the file
765
+ * descriptor belonging to that IO object.
696
766
  * Only one process may have a notification request for a queue
697
767
  * at a time, Errno::EBUSY will be raised if there is already
698
768
  * a notification request registration for the queue.
699
769
  *
770
+ * Notifications are only fired once and processes must reregister
771
+ * for subsequent notifications.
772
+ *
700
773
  * For readers of the mq_notify(3) manpage, passing +false+
701
774
  * is equivalent to SIGEV_NONE, and passing +nil+ is equivalent
702
775
  * of passing a NULL notification pointer to mq_notify(3).
@@ -708,6 +781,10 @@ static VALUE setnotify(VALUE self, VALUE arg)
708
781
  struct sigevent * notification = &not;
709
782
  VALUE rv = arg;
710
783
 
784
+ if (!NIL_P(mq->thread)) {
785
+ rb_funcall(mq->thread, id_kill, 0, 0);
786
+ mq->thread = Qnil;
787
+ }
711
788
  not.sigev_notify = SIGEV_SIGNAL;
712
789
 
713
790
  switch (TYPE(arg)) {
@@ -725,12 +802,15 @@ static VALUE setnotify(VALUE self, VALUE arg)
725
802
  not.sigev_signo = lookup_sig(arg);
726
803
  rv = INT2NUM(not.sigev_signo);
727
804
  break;
805
+ case T_FILE:
806
+ setup_notify_io(&not, arg);
807
+ break;
728
808
  default:
729
809
  /* maybe support Proc+thread via sigev_notify_function.. */
730
810
  rb_raise(rb_eArgError, "must be a signal or nil");
731
811
  }
732
812
 
733
- if (mq_notify(mq->des, notification) == MQD_INVALID)
813
+ if (mq_notify(mq->des, notification) < 0)
734
814
  rb_sys_fail("mq_notify");
735
815
 
736
816
  return rv;
@@ -747,7 +827,7 @@ static VALUE getnonblock(VALUE self)
747
827
  struct mq_attr attr;
748
828
  struct posix_mq *mq = get(self, 1);
749
829
 
750
- if (mq_getattr(mq->des, &attr) == MQD_INVALID)
830
+ if (mq_getattr(mq->des, &attr) < 0)
751
831
  rb_sys_fail("mq_getattr");
752
832
 
753
833
  mq->msgsize = attr.mq_msgsize; /* optimization */
@@ -776,7 +856,7 @@ static VALUE setnonblock(VALUE self, VALUE nb)
776
856
  else
777
857
  rb_raise(rb_eArgError, "must be true or false");
778
858
 
779
- if (mq_setattr(mq->des, &newattr, &oldattr) == MQD_INVALID)
859
+ if (mq_setattr(mq->des, &newattr, &oldattr) < 0)
780
860
  rb_sys_fail("mq_setattr");
781
861
 
782
862
  mq->msgsize = oldattr.mq_msgsize; /* optimization */
@@ -784,6 +864,15 @@ static VALUE setnonblock(VALUE self, VALUE nb)
784
864
  return nb;
785
865
  }
786
866
 
867
+ /* :nodoc: */
868
+ static VALUE setnotifythread(VALUE self, VALUE thread)
869
+ {
870
+ struct posix_mq *mq = get(self, 1);
871
+
872
+ mq->thread = thread;
873
+ return thread;
874
+ }
875
+
787
876
  void Init_posix_mq_ext(void)
788
877
  {
789
878
  cPOSIX_MQ = rb_define_class("POSIX_MQ", rb_cObject);
@@ -814,6 +903,7 @@ void Init_posix_mq_ext(void)
814
903
  rb_define_method(cPOSIX_MQ, "send", _send, -1);
815
904
  rb_define_method(cPOSIX_MQ, "<<", send0, 1);
816
905
  rb_define_method(cPOSIX_MQ, "receive", receive, -1);
906
+ rb_define_method(cPOSIX_MQ, "shift", shift, -1);
817
907
  rb_define_method(cPOSIX_MQ, "attr", getattr, 0);
818
908
  rb_define_method(cPOSIX_MQ, "attr=", setattr, 1);
819
909
  rb_define_method(cPOSIX_MQ, "close", _close, 0);
@@ -822,12 +912,15 @@ void Init_posix_mq_ext(void)
822
912
  rb_define_method(cPOSIX_MQ, "name", name, 0);
823
913
  rb_define_method(cPOSIX_MQ, "notify=", setnotify, 1);
824
914
  rb_define_method(cPOSIX_MQ, "nonblock=", setnonblock, 1);
915
+ rb_define_method(cPOSIX_MQ, "notify_thread=", setnotifythread, 1);
825
916
  rb_define_method(cPOSIX_MQ, "nonblock?", getnonblock, 0);
826
917
  #ifdef MQD_TO_FD
827
918
  rb_define_method(cPOSIX_MQ, "to_io", to_io, 0);
828
919
  #endif
829
920
 
830
921
  id_new = rb_intern("new");
922
+ id_kill = rb_intern("kill");
923
+ id_fileno = rb_intern("fileno");
831
924
  sym_r = ID2SYM(rb_intern("r"));
832
925
  sym_w = ID2SYM(rb_intern("w"));
833
926
  sym_rw = ID2SYM(rb_intern("rw"));
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.1.0
5
- VERSION = '0.2.0'
4
+ # version of POSIX_MQ, currently 0.3.0
5
+ VERSION = '0.3.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
@@ -26,9 +26,46 @@ class POSIX_MQ
26
26
  mq.close unless mq.closed?
27
27
  end
28
28
  end
29
-
30
29
  end
31
30
 
31
+ # Executes the given block upon reception of the next message in an
32
+ # empty queue. If the message queue is not empty, then this block
33
+ # will only be fired after the queue is emptied and repopulated with
34
+ # one message.
35
+ #
36
+ # This block will only be executed upon the arrival of the
37
+ # first message and must be reset/reenabled for subsequent
38
+ # notifications. This block will execute in a separate Ruby
39
+ # Thread (and thus will safely have the GVL by default).
40
+ #
41
+ # This method is only supported on platforms that implement
42
+ # SIGEV_THREAD functionality in mq_notify(3). So far we only
43
+ # know of glibc + Linux supporting this. Please let us
44
+ # know if your platform can support this functionality and
45
+ # are willing to test for us <ruby.posix.mq@librelist.com>
46
+ def notify(&block)
47
+ block.arity == 1 or
48
+ raise ArgumentError, "arity of notify block must be 1"
49
+ r, w = IO.pipe
50
+ thr = Thread.new(r, w, self) do |r, w, mq|
51
+ begin
52
+ begin
53
+ r.read(1) or raise Errno::EINTR
54
+ rescue Errno::EINTR, Errno::EAGAIN
55
+ retry
56
+ end
57
+ block.call(mq)
58
+ ensure
59
+ mq.notify_thread = nil
60
+ r.close rescue nil
61
+ w.close rescue nil
62
+ end
63
+ end
64
+ self.notify = w
65
+ self.notify_thread = thr
66
+ nil
67
+ end if RUBY_PLATFORM =~ /linux/
68
+
32
69
  end
33
70
 
34
71
  require 'posix_mq_ext'
@@ -1,6 +1,7 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'test/unit'
3
3
  require 'posix_mq'
4
+ require 'thread'
4
5
  require 'fcntl'
5
6
  $stderr.sync = $stdout.sync = true
6
7
 
@@ -89,6 +90,12 @@ class Test_POSIX_MQ < Test::Unit::TestCase
89
90
  assert_equal [ "world", 0 ], @mq.receive
90
91
  end
91
92
 
93
+ def test_shift
94
+ @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
95
+ @mq << "hello"
96
+ assert_equal "hello", @mq.shift
97
+ end
98
+
92
99
  def test_send_receive
93
100
  @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
94
101
  assert_nil @mq.send("hello", 0)
@@ -238,4 +245,28 @@ class Test_POSIX_MQ < Test::Unit::TestCase
238
245
  assert POSIX_MQ::OPEN_MAX.kind_of?(Integer)
239
246
  end
240
247
 
248
+ def test_notify_block_replace
249
+ q = Queue.new
250
+ @mq = POSIX_MQ.new(@path, :rw)
251
+ assert_nothing_raised { @mq.notify { |mq| q << mq } }
252
+ @mq << "hi"
253
+ assert_equal POSIX_MQ, q.pop.class
254
+ assert_equal "hi", @mq.receive.first
255
+ assert_nothing_raised { @mq.notify { |mq| q << "hi" } }
256
+ @mq << "bye"
257
+ assert_equal "hi", q.pop
258
+ end if POSIX_MQ.respond_to?(:notify)
259
+
260
+ def test_notify_thread
261
+ q = Queue.new
262
+ @mq = POSIX_MQ.new(@path, :rw)
263
+ @mq.notify_thread = thr = Thread.new { sleep }
264
+ assert thr.alive?
265
+ @mq.notify { |mq| q << Thread.current }
266
+ @mq << "."
267
+ x = q.pop
268
+ assert x.instance_of?(Thread)
269
+ assert Thread.current != x
270
+ assert ! thr.alive?
271
+ end if POSIX_MQ.respond_to?(:notify)
241
272
  end
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.2.0
4
+ version: 0.3.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-01-03 00:00:00 +00:00
12
+ date: 2010-01-09 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies: []
15
15