fix build under FreeBSD 7.2
[ruby_posix_mq.git] / ext / posix_mq / posix_mq.c
blob8ce1ab574c1ff610e742021ddd8659bc798779e4
1 #define _XOPEN_SOURCE 600
2 #ifdef HAVE_SYS_SELECT_H
3 # include <sys/select.h>
4 #endif
5 #ifdef HAVE_SIGNAL_H
6 # include <signal.h>
7 #endif
8 #include <ruby.h>
10 #include <time.h>
11 #include <mqueue.h>
12 #include <fcntl.h>
13 #include <sys/stat.h>
14 #include <errno.h>
15 #include <assert.h>
16 #include <unistd.h>
18 #if defined(__linux__)
19 # define MQD_IS_FD 1
20 # define MQ_IO_MARK(mq) rb_gc_mark((mq)->io)
21 # define MQ_IO_SET(mq,val) do { (mq)->io = (val); } while (0)
22 #else
23 # warning mqd_t is not select()-able on your OS
24 # define MQD_IS_FD 0
25 # define MQ_IO_MARK(mq) ((void)(0))
26 # define MQ_IO_SET(mq,val) ((void)(0))
27 #endif /* non-Linux */
29 struct posix_mq {
30 mqd_t des;
31 long msgsize;
32 VALUE name;
33 #if MQD_IS_FD
34 VALUE io;
35 #endif
38 static VALUE cPOSIX_MQ, cAttr;
39 static ID id_new;
40 static ID sym_r, sym_w, sym_rw;
41 static const mqd_t MQD_INVALID = (mqd_t)-1;
43 /* Ruby 1.8.6+ macros (for compatibility with Ruby 1.9) */
44 #ifndef RSTRING_PTR
45 # define RSTRING_PTR(s) (RSTRING(s)->ptr)
46 #endif
47 #ifndef RSTRING_LEN
48 # define RSTRING_LEN(s) (RSTRING(s)->len)
49 #endif
50 #ifndef RSTRUCT_PTR
51 # define RSTRUCT_PTR(s) (RSTRUCT(s)->ptr)
52 #endif
53 #ifndef RSTRUCT_LEN
54 # define RSTRUCT_LEN(s) (RSTRUCT(s)->len)
55 #endif
57 #ifndef HAVE_RB_STR_SET_LEN
58 # ifdef RUBINIUS
59 # define rb_str_set_len(str,len) rb_str_resize(str,len)
60 # else /* 1.8.6 optimized version */
61 /* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
62 static void rb_18_str_set_len(VALUE str, long len)
64 RSTRING(str)->len = len;
65 RSTRING(str)->ptr[len] = '\0';
66 rb_str_flush(str);
68 # define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
69 # endif /* ! RUBINIUS */
70 #endif /* !defined(HAVE_RB_STR_SET_LEN) */
72 #ifndef HAVE_RB_STRUCT_ALLOC_NOINIT
73 static VALUE rb_struct_alloc_noinit(VALUE class)
75 return rb_funcall(class, id_new, 0, 0);
77 #endif /* !defined(HAVE_RB_STRUCT_ALLOC_NOINIT) */
79 /* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
80 #ifndef HAVE_RB_THREAD_BLOCKING_REGION
81 # include <rubysig.h>
82 # define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
83 typedef void rb_unblock_function_t(void *);
84 typedef VALUE rb_blocking_function_t(void *);
85 static VALUE
86 rb_thread_blocking_region(
87 rb_blocking_function_t *func, void *data1,
88 rb_unblock_function_t *ubf, void *data2)
90 VALUE rv;
92 assert(RUBY_UBF_IO == ubf && "RUBY_UBF_IO required for emulation");
94 TRAP_BEG;
95 rv = func(data1);
96 TRAP_END;
98 return rv;
100 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
102 /* used to pass arguments to mq_open inside blocking region */
103 struct open_args {
104 int argc;
105 const char *name;
106 int oflags;
107 mode_t mode;
108 struct mq_attr attr;
111 /* used to pass arguments to mq_send/mq_receive inside blocking region */
112 struct rw_args {
113 mqd_t des;
114 char *msg_ptr;
115 size_t msg_len;
116 unsigned msg_prio;
117 struct timespec *timeout;
120 /* hope it's there..., TODO: a better version that works in rbx */
121 struct timeval rb_time_interval(VALUE);
123 static struct timespec *convert_timeout(struct timespec *dest, VALUE time)
125 struct timeval tv, now;
127 if (NIL_P(time))
128 return NULL;
130 tv = rb_time_interval(time); /* aggregate return :( */
131 gettimeofday(&now, NULL);
132 dest->tv_sec = now.tv_sec + tv.tv_sec;
133 dest->tv_nsec = (now.tv_usec + tv.tv_usec) * 1000;
135 if (dest->tv_nsec > 1000000000) {
136 dest->tv_nsec -= 1000000000;
137 dest->tv_sec++;
140 return dest;
143 /* runs without GVL */
144 static VALUE xopen(void *ptr)
146 struct open_args *x = ptr;
147 mqd_t rv;
149 switch (x->argc) {
150 case 2: rv = mq_open(x->name, x->oflags); break;
151 case 3: rv = mq_open(x->name, x->oflags, x->mode, NULL); break;
152 case 4: rv = mq_open(x->name, x->oflags, x->mode, &x->attr); break;
153 default: rv = MQD_INVALID;
156 return (VALUE)rv;
159 /* runs without GVL */
160 static VALUE xsend(void *ptr)
162 struct rw_args *x = ptr;
164 if (x->timeout)
165 return (VALUE)mq_timedsend(x->des, x->msg_ptr, x->msg_len,
166 x->msg_prio, x->timeout);
168 return (VALUE)mq_send(x->des, x->msg_ptr, x->msg_len, x->msg_prio);
171 /* runs without GVL */
172 static VALUE xrecv(void *ptr)
174 struct rw_args *x = ptr;
176 if (x->timeout)
177 return (VALUE)mq_timedreceive(x->des, x->msg_ptr, x->msg_len,
178 &x->msg_prio, x->timeout);
180 return (VALUE)mq_receive(x->des, x->msg_ptr, x->msg_len, &x->msg_prio);
183 /* runs without GVL, path resolution may be slow */
184 static VALUE xunlink(void *ptr)
186 VALUE name = (VALUE)ptr;
188 return (VALUE)mq_unlink(RSTRING_PTR(name));
191 /* called by GC */
192 static void mark(void *ptr)
194 struct posix_mq *mq = ptr;
196 rb_gc_mark(mq->name);
197 MQ_IO_MARK(mq);
200 /* called by GC */
201 static void _free(void *ptr)
203 struct posix_mq *mq = ptr;
205 if (mq->des != MQD_INVALID) {
206 /* we ignore errors when gc-ing */
207 int saved_errno = errno;
209 mq_close(mq->des);
210 errno = saved_errno;
211 mq->des = MQD_INVALID;
215 /* automatically called at creation (before initialize) */
216 static VALUE alloc(VALUE klass)
218 struct posix_mq *mq;
219 VALUE rv = Data_Make_Struct(klass, struct posix_mq, mark, _free, mq);
221 mq->des = MQD_INVALID;
222 mq->msgsize = -1;
223 mq->name = Qnil;
224 MQ_IO_SET(mq, Qnil);
226 return rv;
229 /* unwraps the posix_mq struct from self */
230 static struct posix_mq *get(VALUE self, int need_valid)
232 struct posix_mq *mq;
234 Data_Get_Struct(self, struct posix_mq, mq);
236 if (need_valid && mq->des == MQD_INVALID)
237 rb_raise(rb_eIOError, "closed queue descriptor");
239 return mq;
242 /* converts the POSIX_MQ::Attr astruct into a struct mq_attr attr */
243 static void attr_from_struct(struct mq_attr *attr, VALUE astruct, int all)
245 VALUE *ptr;
247 if (CLASS_OF(astruct) != cAttr)
248 rb_raise(rb_eArgError, "not a POSIX_MQ::Attr: %s",
249 RSTRING_PTR(rb_inspect(astruct)));
251 ptr = RSTRUCT_PTR(astruct);
253 attr->mq_flags = NUM2LONG(ptr[0]);
255 if (all || !NIL_P(ptr[1]))
256 attr->mq_maxmsg = NUM2LONG(ptr[1]);
257 if (all || !NIL_P(ptr[2]))
258 attr->mq_msgsize = NUM2LONG(ptr[2]);
259 if (!NIL_P(ptr[3]))
260 attr->mq_curmsgs = NUM2LONG(ptr[3]);
264 * call-seq:
265 * POSIX_MQ.new(name [, flags [, mode [, mq_attr]]) => mq
267 * Opens a POSIX message queue given by +name+. +name+ should start
268 * with a slash ("/") for portable applications.
270 * If a Symbol is given in place of integer +flags+, then:
272 * * +:r+ is equivalent to IO::RDONLY
273 * * +:w+ is equivalent to IO::CREAT|IO::WRONLY
274 * * +:rw+ is equivalent to IO::CREAT|IO::RDWR
276 * +mode+ is an integer and only used when IO::CREAT is used.
277 * +mq_attr+ is a POSIX_MQ::Attr and only used if IO::CREAT is used.
278 * If +mq_attr+ is not specified when creating a queue, then the
279 * system defaults will be used.
281 * See the manpage for mq_open(3) for more details on this function.
283 static VALUE init(int argc, VALUE *argv, VALUE self)
285 struct posix_mq *mq = get(self, 0);
286 struct open_args x;
287 VALUE name, oflags, mode, attr;
289 rb_scan_args(argc, argv, "13", &name, &oflags, &mode, &attr);
291 if (TYPE(name) != T_STRING)
292 rb_raise(rb_eArgError, "name must be a string");
294 switch (TYPE(oflags)) {
295 case T_NIL:
296 x.oflags = O_RDONLY;
297 break;
298 case T_SYMBOL:
299 if (oflags == sym_r)
300 x.oflags = O_RDONLY;
301 else if (oflags == sym_w)
302 x.oflags = O_CREAT|O_WRONLY;
303 else if (oflags == sym_rw)
304 x.oflags = O_CREAT|O_RDWR;
305 else
306 rb_raise(rb_eArgError,
307 "symbol must be :r, :w, or :rw: %s",
308 RSTRING_PTR(rb_inspect(oflags)));
309 break;
310 case T_BIGNUM:
311 case T_FIXNUM:
312 x.oflags = NUM2INT(oflags);
313 break;
314 default:
315 rb_raise(rb_eArgError, "flags must be an int, :r, :w, or :wr");
318 x.name = RSTRING_PTR(name);
319 x.argc = 2;
321 switch (TYPE(mode)) {
322 case T_FIXNUM:
323 x.argc = 3;
324 x.mode = NUM2INT(mode);
325 break;
326 case T_NIL:
327 if (x.oflags & O_CREAT) {
328 x.argc = 3;
329 x.mode = 0666;
331 break;
332 default:
333 rb_raise(rb_eArgError, "mode not an integer");
336 switch (TYPE(attr)) {
337 case T_STRUCT:
338 x.argc = 4;
339 attr_from_struct(&x.attr, attr, 1);
341 /* principle of least surprise */
342 if (x.attr.mq_flags & O_NONBLOCK)
343 x.oflags |= O_NONBLOCK;
344 break;
345 case T_NIL:
346 break;
347 default:
348 rb_raise(rb_eArgError, "attr must be a POSIX_MQ::Attr: %s",
349 RSTRING_PTR(rb_inspect(attr)));
352 mq->des = (mqd_t)rb_thread_blocking_region(xopen, &x, RUBY_UBF_IO, 0);
353 if (mq->des == MQD_INVALID)
354 rb_sys_fail("mq_open");
356 mq->name = rb_str_dup(name);
358 return self;
362 * call-seq:
363 * POSIX_MQ.unlink(name) => 1
365 * Unlinks the message queue given by +name+. The queue will be destroyed
366 * when the last process with the queue open closes its queue descriptors.
368 static VALUE s_unlink(VALUE self, VALUE name)
370 mqd_t rv;
371 void *ptr = (void *)name;
373 if (TYPE(name) != T_STRING)
374 rb_raise(rb_eArgError, "argument must be a string");
376 rv = (mqd_t)rb_thread_blocking_region(xunlink, ptr, RUBY_UBF_IO, 0);
377 if (rv == MQD_INVALID)
378 rb_sys_fail("mq_unlink");
380 return INT2NUM(1);
384 * call-seq:
385 * mq.unlink => mq
387 * Unlinks the message queue to prevent other processes from accessing it.
388 * All existing queue descriptors to this queue including those opened by
389 * other processes are unaffected. The queue will only be destroyed
390 * when the last process with open descriptors to this queue closes
391 * the descriptors.
393 static VALUE _unlink(VALUE self)
395 struct posix_mq *mq = get(self, 0);
396 mqd_t rv;
397 void *ptr = (void *)mq->name;
399 assert(TYPE(mq->name) == T_STRING && "mq->name is not a string");
401 rv = (mqd_t)rb_thread_blocking_region(xunlink, ptr, RUBY_UBF_IO, 0);
402 if (rv == MQD_INVALID)
403 rb_sys_fail("mq_unlink");
405 return self;
408 static void setup_send_buffer(struct rw_args *x, VALUE buffer)
410 buffer = rb_obj_as_string(buffer);
411 x->msg_ptr = RSTRING_PTR(buffer);
412 x->msg_len = (size_t)RSTRING_LEN(buffer);
416 * call-seq:
417 * mq.send(string [,priority[, timeout]]) => nil
419 * Inserts the given +string+ into the message queue with an optional,
420 * unsigned integer +priority+. If the optional +timeout+ is specified,
421 * then Errno::ETIMEDOUT will be raised if the operation cannot complete
422 * before +timeout+ seconds has elapsed. Without +timeout+, this method
423 * may block until the queue is writable.
425 static VALUE _send(int argc, VALUE *argv, VALUE self)
427 struct posix_mq *mq = get(self, 1);
428 struct rw_args x;
429 VALUE buffer, prio, timeout;
430 mqd_t rv;
431 struct timespec expire;
433 rb_scan_args(argc, argv, "12", &buffer, &prio, &timeout);
435 setup_send_buffer(&x, buffer);
436 x.des = mq->des;
437 x.timeout = convert_timeout(&expire, timeout);
438 x.msg_prio = NIL_P(prio) ? 0 : NUM2UINT(prio);
440 rv = (mqd_t)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0);
441 if (rv == MQD_INVALID)
442 rb_sys_fail("mq_send");
444 return Qnil;
448 * call-seq:
449 * mq << string => mq
451 * Inserts the given +string+ into the message queue with a
452 * default priority of 0 and no timeout.
454 static VALUE send0(VALUE self, VALUE buffer)
456 struct posix_mq *mq = get(self, 1);
457 struct rw_args x;
458 mqd_t rv;
460 setup_send_buffer(&x, buffer);
461 x.des = mq->des;
462 x.timeout = NULL;
463 x.msg_prio = 0;
465 rv = (mqd_t)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0);
466 if (rv == MQD_INVALID)
467 rb_sys_fail("mq_send");
469 return self;
472 #if MQD_IS_FD
474 * call-seq:
475 * mq.to_io => IO
477 * Returns an IO.select-able +IO+ object. This method is only available
478 * under Linux and is not intended to be portable.
480 static VALUE to_io(VALUE self)
482 struct posix_mq *mq = get(self, 1);
484 if (NIL_P(mq->io))
485 mq->io = rb_funcall(rb_cIO, id_new, 1, INT2NUM(mq->des));
487 return mq->io;
489 #endif
491 static void get_msgsize(struct posix_mq *mq)
493 struct mq_attr attr;
495 if (mq_getattr(mq->des, &attr) == MQD_INVALID)
496 rb_sys_fail("mq_getattr");
498 mq->msgsize = attr.mq_msgsize;
502 * call-seq:
503 * mq.receive([buffer, [timeout]]) => [ message, priority ]
505 * Takes the highest priority message off the queue and returns
506 * an array containing the message as a String and the Integer
507 * priority of the message.
509 * If the optional +buffer+ is present, then it must be a String
510 * which will receive the data.
512 * If the optional +timeout+ is present, then it may be a Float
513 * or Integer specifying the timeout in seconds. Errno::ETIMEDOUT
514 * will be raised if +timeout+ has elapsed and there are no messages
515 * in the queue.
517 static VALUE receive(int argc, VALUE *argv, VALUE self)
519 struct posix_mq *mq = get(self, 1);
520 struct rw_args x;
521 VALUE buffer, timeout;
522 ssize_t r;
523 struct timespec expire;
525 if (mq->msgsize < 0)
526 get_msgsize(mq);
528 rb_scan_args(argc, argv, "02", &buffer, &timeout);
529 x.timeout = convert_timeout(&expire, timeout);
531 if (NIL_P(buffer)) {
532 buffer = rb_str_new(0, mq->msgsize);
533 } else {
534 StringValue(buffer);
535 rb_str_modify(buffer);
536 rb_str_resize(buffer, mq->msgsize);
538 OBJ_TAINT(buffer);
539 x.msg_ptr = RSTRING_PTR(buffer);
540 x.msg_len = (size_t)mq->msgsize;
541 x.des = mq->des;
543 r = (ssize_t)rb_thread_blocking_region(xrecv, &x, RUBY_UBF_IO, 0);
544 if (r < 0)
545 rb_sys_fail("mq_receive");
547 rb_str_set_len(buffer, r);
549 return rb_ary_new3(2, buffer, UINT2NUM(x.msg_prio));
553 * call-seq:
554 * mq.attr => mq_attr
556 * Returns a POSIX_MQ::Attr struct containing the attributes
557 * of the message queue. See the mq_getattr(3) manpage for
558 * more details.
560 static VALUE getattr(VALUE self)
562 struct posix_mq *mq = get(self, 1);
563 struct mq_attr attr;
564 VALUE astruct;
565 VALUE *ptr;
567 if (mq_getattr(mq->des, &attr) == MQD_INVALID)
568 rb_sys_fail("mq_getattr");
570 astruct = rb_struct_alloc_noinit(cAttr);
571 ptr = RSTRUCT_PTR(astruct);
572 ptr[0] = LONG2NUM(attr.mq_flags);
573 ptr[1] = LONG2NUM(attr.mq_maxmsg);
574 ptr[2] = LONG2NUM(attr.mq_msgsize);
575 ptr[3] = LONG2NUM(attr.mq_curmsgs);
577 return astruct;
581 * call-seq:
582 * mq.attr = POSIX_MQ::Attr(IO::NONBLOCK) => mq_attr
584 * Only the IO::NONBLOCK flag may be set or unset (zero) in this manner.
585 * See the mq_setattr(3) manpage for more details.
587 * Consider using the POSIX_MQ#nonblock= method as it is easier and
588 * more natural to use.
590 static VALUE setattr(VALUE self, VALUE astruct)
592 struct posix_mq *mq = get(self, 1);
593 struct mq_attr newattr;
595 attr_from_struct(&newattr, astruct, 0);
597 if (mq_setattr(mq->des, &newattr, NULL) == MQD_INVALID)
598 rb_sys_fail("mq_setattr");
600 return astruct;
604 * call-seq:
605 * mq.close => nil
607 * Closes the underlying message queue descriptor.
608 * If this descriptor had a registered notification request, the request
609 * will be removed so another descriptor or process may register a
610 * notification request. Message queue descriptors are automatically
611 * closed by garbage collection.
613 static VALUE _close(VALUE self)
615 struct posix_mq *mq = get(self, 1);
617 if (mq_close(mq->des) == MQD_INVALID)
618 rb_sys_fail("mq_close");
620 mq->des = MQD_INVALID;
621 MQ_IO_SET(mq, Qnil);
623 return Qnil;
627 * call-seq:
628 * mq.closed? => true or false
630 * Returns +true+ if the message queue descriptor is closed and therefore
631 * unusable, otherwise +false+
633 static VALUE closed(VALUE self)
635 struct posix_mq *mq = get(self, 0);
637 return mq->des == MQD_INVALID ? Qtrue : Qfalse;
641 * call-seq:
642 * mq.name => string
644 * Returns the string name of message queue associated with +mq+
646 static VALUE name(VALUE self)
648 struct posix_mq *mq = get(self, 0);
650 return mq->name;
653 static int lookup_sig(VALUE sig)
655 static VALUE list;
656 const char *ptr;
657 long len;
659 sig = rb_obj_as_string(sig);
660 len = RSTRING_LEN(sig);
661 ptr = RSTRING_PTR(sig);
663 if (len > 3 && !memcmp("SIG", ptr, 3))
664 sig = rb_str_new(ptr + 3, len - 3);
666 if (!list) {
667 VALUE mSignal = rb_define_module("Signal"""); /* avoid RDoc */
669 list = rb_funcall(mSignal, rb_intern("list"), 0, 0);
670 rb_global_variable(&list);
673 sig = rb_hash_aref(list, sig);
674 if (NIL_P(sig))
675 rb_raise(rb_eArgError, "invalid signal: %s\n",
676 RSTRING_PTR(rb_inspect(sig)));
678 return NUM2INT(sig);
682 * call-seq:
683 * mq.notify = signal => signal
685 * Registers the notification request to deliver a given +signal+
686 * to the current process when message is received.
687 * If +signal+ is +nil+, it will unregister and disable the notification
688 * request to allow other processes to register a request.
689 * If +signal+ is +false+, it will register a no-op notification request
690 * which will prevent other processes from registering a notification.
691 * Only one process may have a notification request for a queue
692 * at a time, Errno::EBUSY will be raised if there is already
693 * a notification request registration for the queue.
695 * For readers of the mq_notify(3) manpage, passing +false+
696 * is equivalent to SIGEV_NONE, and passing +nil+ is equivalent
697 * of passing a NULL notification pointer to mq_notify(3).
699 static VALUE setnotify(VALUE self, VALUE arg)
701 struct posix_mq *mq = get(self, 1);
702 struct sigevent not;
703 struct sigevent * notification = &not;
704 VALUE rv = arg;
706 not.sigev_notify = SIGEV_SIGNAL;
708 switch (TYPE(arg)) {
709 case T_FALSE:
710 not.sigev_notify = SIGEV_NONE;
711 break;
712 case T_NIL:
713 notification = NULL;
714 break;
715 case T_FIXNUM:
716 not.sigev_signo = NUM2INT(arg);
717 break;
718 case T_SYMBOL:
719 case T_STRING:
720 not.sigev_signo = lookup_sig(arg);
721 rv = INT2NUM(not.sigev_signo);
722 break;
723 default:
724 /* maybe support Proc+thread via sigev_notify_function.. */
725 rb_raise(rb_eArgError, "must be a signal or nil");
728 if (mq_notify(mq->des, notification) == MQD_INVALID)
729 rb_sys_fail("mq_notify");
731 return rv;
735 * call-seq:
736 * mq.nonblock? => true or false
738 * Returns the current non-blocking state of the message queue descriptor.
740 static VALUE getnonblock(VALUE self)
742 struct mq_attr attr;
743 struct posix_mq *mq = get(self, 1);
745 if (mq_getattr(mq->des, &attr) == MQD_INVALID)
746 rb_sys_fail("mq_getattr");
748 mq->msgsize = attr.mq_msgsize; /* optimization */
750 return attr.mq_flags & O_NONBLOCK ? Qtrue : Qfalse;
754 * call-seq:
755 * mq.nonblock = boolean => boolean
757 * Enables or disables non-blocking operation for the message queue
758 * descriptor. Errno::EAGAIN will be raised in situations where
759 * the queue would block. This is not compatible with +timeout+
760 * arguments to POSIX_MQ#send and POSIX_MQ#receive.
762 static VALUE setnonblock(VALUE self, VALUE nb)
764 struct mq_attr newattr, oldattr;
765 struct posix_mq *mq = get(self, 1);
767 if (nb == Qtrue)
768 newattr.mq_flags = O_NONBLOCK;
769 else if (nb == Qfalse)
770 newattr.mq_flags = 0;
771 else
772 rb_raise(rb_eArgError, "must be true or false");
774 if (mq_setattr(mq->des, &newattr, &oldattr) == MQD_INVALID)
775 rb_sys_fail("mq_setattr");
777 mq->msgsize = oldattr.mq_msgsize; /* optimization */
779 return nb;
782 void Init_posix_mq_ext(void)
784 cPOSIX_MQ = rb_define_class("POSIX_MQ", rb_cObject);
785 rb_define_alloc_func(cPOSIX_MQ, alloc);
786 cAttr = rb_const_get(cPOSIX_MQ, rb_intern("Attr"));
789 * The maximum number of open message descriptors supported
790 * by the system. This may be -1, in which case it is dynamically
791 * set at runtime. Consult your operating system documentation
792 * for system-specific information about this.
794 rb_define_const(cPOSIX_MQ, "OPEN_MAX",
795 LONG2NUM(sysconf(_SC_MQ_OPEN_MAX)));
798 * The maximum priority that may be specified for POSIX_MQ#send
799 * On POSIX-compliant systems, this is at least 31, but some
800 * systems allow higher limits.
801 * The minimum priority is always zero.
803 rb_define_const(cPOSIX_MQ, "PRIO_MAX",
804 LONG2NUM(sysconf(_SC_MQ_PRIO_MAX)));
806 rb_define_singleton_method(cPOSIX_MQ, "unlink", s_unlink, 1);
808 rb_define_method(cPOSIX_MQ, "initialize", init, -1);
809 rb_define_method(cPOSIX_MQ, "send", _send, -1);
810 rb_define_method(cPOSIX_MQ, "<<", send0, 1);
811 rb_define_method(cPOSIX_MQ, "receive", receive, -1);
812 rb_define_method(cPOSIX_MQ, "attr", getattr, 0);
813 rb_define_method(cPOSIX_MQ, "attr=", setattr, 1);
814 rb_define_method(cPOSIX_MQ, "close", _close, 0);
815 rb_define_method(cPOSIX_MQ, "closed?", closed, 0);
816 rb_define_method(cPOSIX_MQ, "unlink", _unlink, 0);
817 rb_define_method(cPOSIX_MQ, "name", name, 0);
818 rb_define_method(cPOSIX_MQ, "notify=", setnotify, 1);
819 rb_define_method(cPOSIX_MQ, "nonblock=", setnonblock, 1);
820 rb_define_method(cPOSIX_MQ, "nonblock?", getnonblock, 0);
821 #if MQD_IS_FD
822 rb_define_method(cPOSIX_MQ, "to_io", to_io, 0);
823 #endif
825 id_new = rb_intern("new");
826 sym_r = ID2SYM(rb_intern("r"));
827 sym_w = ID2SYM(rb_intern("w"));
828 sym_rw = ID2SYM(rb_intern("rw"));