1 /* $NetBSD: sys_mqueue.c,v 1.28 2009/12/10 12:22:48 drochner Exp $ */
4 * Copyright (c) 2007-2009 Mindaugas Rasiukevicius <rmind at NetBSD org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * Implementation of POSIX message queues.
31 * Defined in the Base Definitions volume of IEEE Std 1003.1-2001.
35 * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt
36 * counter are protected by mqlist_mtx lock. The very message queue and
37 * its members are protected by mqueue::mq_mtx.
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.28 2009/12/10 12:22:48 drochner Exp $");
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/condvar.h>
50 #include <sys/errno.h>
51 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
54 #include <sys/kauth.h>
55 #include <sys/kernel.h>
58 #include <sys/mqueue.h>
59 #include <sys/module.h>
60 #include <sys/mutex.h>
64 #include <sys/queue.h>
65 #include <sys/select.h>
66 #include <sys/signal.h>
67 #include <sys/signalvar.h>
69 #include <sys/sysctl.h>
70 #include <sys/syscall.h>
71 #include <sys/syscallvar.h>
72 #include <sys/syscallargs.h>
73 #include <sys/systm.h>
74 #include <sys/unistd.h>
76 #include <miscfs/genfs/genfs.h>
78 MODULE(MODULE_CLASS_MISC
, mqueue
, NULL
);
80 /* System-wide limits. */
81 static u_int mq_open_max
= MQ_OPEN_MAX
;
82 static u_int mq_prio_max
= MQ_PRIO_MAX
;
83 static u_int mq_max_msgsize
= 16 * MQ_DEF_MSGSIZE
;
84 static u_int mq_def_maxmsg
= 32;
85 static u_int mq_max_maxmsg
= 16 * 32;
87 static kmutex_t mqlist_mtx
;
88 static pool_cache_t mqmsg_cache
;
89 static LIST_HEAD(, mqueue
) mqueue_head
;
91 static int mqueue_sysinit(void);
92 static int mqueue_sysfini(bool);
93 static int mq_poll_fop(file_t
*, int);
94 static int mq_stat_fop(file_t
*, struct stat
*);
95 static int mq_close_fop(file_t
*);
97 static const struct fileops mqops
= {
98 .fo_read
= fbadop_read
,
99 .fo_write
= fbadop_write
,
100 .fo_ioctl
= fbadop_ioctl
,
101 .fo_fcntl
= fnullop_fcntl
,
102 .fo_poll
= mq_poll_fop
,
103 .fo_stat
= mq_stat_fop
,
104 .fo_close
= mq_close_fop
,
105 .fo_kqfilter
= fnullop_kqfilter
,
106 .fo_restart
= fnullop_restart
,
109 static const struct syscall_package mqueue_syscalls
[] = {
110 { SYS_mq_open
, 0, (sy_call_t
*)sys_mq_open
},
111 { SYS_mq_close
, 0, (sy_call_t
*)sys_mq_close
},
112 { SYS_mq_unlink
, 0, (sy_call_t
*)sys_mq_unlink
},
113 { SYS_mq_getattr
, 0, (sy_call_t
*)sys_mq_getattr
},
114 { SYS_mq_setattr
, 0, (sy_call_t
*)sys_mq_setattr
},
115 { SYS_mq_notify
, 0, (sy_call_t
*)sys_mq_notify
},
116 { SYS_mq_send
, 0, (sy_call_t
*)sys_mq_send
},
117 { SYS_mq_receive
, 0, (sy_call_t
*)sys_mq_receive
},
118 { SYS___mq_timedsend50
, 0, (sy_call_t
*)sys___mq_timedsend50
},
119 { SYS___mq_timedreceive50
, 0, (sy_call_t
*)sys___mq_timedreceive50
},
124 * Initialisation and unloading of POSIX message queue subsystem.
132 mqmsg_cache
= pool_cache_init(MQ_DEF_MSGSIZE
, coherency_unit
,
133 0, 0, "mqmsgpl", NULL
, IPL_NONE
, NULL
, NULL
, NULL
);
134 mutex_init(&mqlist_mtx
, MUTEX_DEFAULT
, IPL_NONE
);
135 LIST_INIT(&mqueue_head
);
137 error
= syscall_establish(NULL
, mqueue_syscalls
);
139 (void)mqueue_sysfini(false);
145 mqueue_sysfini(bool interface
)
152 /* Stop syscall activity. */
153 error
= syscall_disestablish(NULL
, mqueue_syscalls
);
157 * Check if there are any message queues in use.
158 * TODO: We shall support forced unload.
160 mutex_enter(&mqlist_mtx
);
161 inuse
= !LIST_EMPTY(&mqueue_head
);
162 mutex_exit(&mqlist_mtx
);
164 error
= syscall_establish(NULL
, mqueue_syscalls
);
169 mutex_destroy(&mqlist_mtx
);
170 pool_cache_destroy(mqmsg_cache
);
178 mqueue_modcmd(modcmd_t cmd
, void *arg
)
182 case MODULE_CMD_INIT
:
183 return mqueue_sysinit();
184 case MODULE_CMD_FINI
:
185 return mqueue_sysfini(true);
195 mqueue_freemsg(struct mq_msg
*msg
, const size_t size
)
198 if (size
> MQ_DEF_MSGSIZE
) {
199 kmem_free(msg
, size
);
201 pool_cache_put(mqmsg_cache
, msg
);
206 * Destroy the message queue.
209 mqueue_destroy(struct mqueue
*mq
)
215 /* Note MQ_PQSIZE + 1. */
216 for (i
= 0; i
<= MQ_PQSIZE
; i
++) {
217 while ((msg
= TAILQ_FIRST(&mq
->mq_head
[i
])) != NULL
) {
218 TAILQ_REMOVE(&mq
->mq_head
[i
], msg
, msg_queue
);
219 msz
= sizeof(struct mq_msg
) + msg
->msg_len
;
220 mqueue_freemsg(msg
, msz
);
223 seldestroy(&mq
->mq_rsel
);
224 seldestroy(&mq
->mq_wsel
);
225 cv_destroy(&mq
->mq_send_cv
);
226 cv_destroy(&mq
->mq_recv_cv
);
227 mutex_destroy(&mq
->mq_mtx
);
228 kmem_free(mq
, sizeof(struct mqueue
));
232 * Lookup for file name in general list of message queues.
233 * => locks the message queue
236 mqueue_lookup(char *name
)
239 KASSERT(mutex_owned(&mqlist_mtx
));
241 LIST_FOREACH(mq
, &mqueue_head
, mq_list
) {
242 if (strncmp(mq
->mq_name
, name
, MQ_NAMELEN
) == 0) {
243 mutex_enter(&mq
->mq_mtx
);
252 * mqueue_get: get the mqueue from the descriptor.
253 * => locks the message queue, if found.
254 * => holds a reference on the file descriptor.
257 mqueue_get(mqd_t mqd
, file_t
**fpr
)
262 fp
= fd_getfile((int)mqd
);
263 if (__predict_false(fp
== NULL
)) {
266 if (__predict_false(fp
->f_type
!= DTYPE_MQUEUE
)) {
267 fd_putfile((int)mqd
);
271 mutex_enter(&mq
->mq_mtx
);
278 * mqueue_linear_insert: perform linear insert according to the message
279 * priority into the reserved queue (MQ_PQRESQ). Reserved queue is a
280 * sorted list used only when mq_prio_max is increased via sysctl.
283 mqueue_linear_insert(struct mqueue
*mq
, struct mq_msg
*msg
)
287 TAILQ_FOREACH(mit
, &mq
->mq_head
[MQ_PQRESQ
], msg_queue
) {
288 if (msg
->msg_prio
> mit
->msg_prio
)
292 TAILQ_INSERT_TAIL(&mq
->mq_head
[MQ_PQRESQ
], msg
, msg_queue
);
294 TAILQ_INSERT_BEFORE(mit
, msg
, msg_queue
);
299 mq_stat_fop(file_t
*fp
, struct stat
*st
)
301 struct mqueue
*mq
= fp
->f_data
;
303 memset(st
, 0, sizeof(*st
));
305 mutex_enter(&mq
->mq_mtx
);
306 st
->st_mode
= mq
->mq_mode
;
307 st
->st_uid
= mq
->mq_euid
;
308 st
->st_gid
= mq
->mq_egid
;
309 st
->st_atimespec
= mq
->mq_atime
;
310 st
->st_mtimespec
= mq
->mq_mtime
;
311 st
->st_ctimespec
= st
->st_birthtimespec
= mq
->mq_btime
;
312 st
->st_uid
= kauth_cred_geteuid(fp
->f_cred
);
313 st
->st_gid
= kauth_cred_getegid(fp
->f_cred
);
314 mutex_exit(&mq
->mq_mtx
);
320 mq_poll_fop(file_t
*fp
, int events
)
322 struct mqueue
*mq
= fp
->f_data
;
323 struct mq_attr
*mqattr
;
326 mutex_enter(&mq
->mq_mtx
);
327 mqattr
= &mq
->mq_attrib
;
328 if (events
& (POLLIN
| POLLRDNORM
)) {
329 /* Ready for receiving, if there are messages in the queue */
330 if (mqattr
->mq_curmsgs
)
331 revents
|= (POLLIN
| POLLRDNORM
);
333 selrecord(curlwp
, &mq
->mq_rsel
);
335 if (events
& (POLLOUT
| POLLWRNORM
)) {
336 /* Ready for sending, if the message queue is not full */
337 if (mqattr
->mq_curmsgs
< mqattr
->mq_maxmsg
)
338 revents
|= (POLLOUT
| POLLWRNORM
);
340 selrecord(curlwp
, &mq
->mq_wsel
);
342 mutex_exit(&mq
->mq_mtx
);
348 mq_close_fop(file_t
*fp
)
350 struct proc
*p
= curproc
;
351 struct mqueue
*mq
= fp
->f_data
;
354 mutex_enter(&mqlist_mtx
);
355 mutex_enter(&mq
->mq_mtx
);
357 /* Decrease the counters */
361 /* Remove notification if registered for this process */
362 if (mq
->mq_notify_proc
== p
)
363 mq
->mq_notify_proc
= NULL
;
366 * If this is the last reference and mqueue is marked for unlink,
367 * remove and later destroy the message queue.
369 if (mq
->mq_refcnt
== 0 && (mq
->mq_attrib
.mq_flags
& MQ_UNLINK
)) {
370 LIST_REMOVE(mq
, mq_list
);
375 mutex_exit(&mq
->mq_mtx
);
376 mutex_exit(&mqlist_mtx
);
385 mqueue_access(struct mqueue
*mq
, mode_t mode
, kauth_cred_t cred
)
388 if (genfs_can_access(VNON
, mq
->mq_mode
, mq
->mq_euid
,
389 mq
->mq_egid
, mode
, cred
)) {
397 * General mqueue system calls.
401 sys_mq_open(struct lwp
*l
, const struct sys_mq_open_args
*uap
,
405 syscallarg(const char *) name;
406 syscallarg(int) oflag;
407 syscallarg(mode_t) mode;
408 syscallarg(struct mq_attr) attr;
410 struct proc
*p
= l
->l_proc
;
411 struct mqueue
*mq
, *mq_new
= NULL
;
414 int mqd
, error
, oflag
;
416 oflag
= SCARG(uap
, oflag
);
418 /* Get the name from the user-space */
419 name
= kmem_zalloc(MQ_NAMELEN
, KM_SLEEP
);
420 error
= copyinstr(SCARG(uap
, name
), name
, MQ_NAMELEN
- 1, NULL
);
422 kmem_free(name
, MQ_NAMELEN
);
426 if (oflag
& O_CREAT
) {
427 struct cwdinfo
*cwdi
= p
->p_cwdi
;
431 /* Check the limit */
432 if (p
->p_mqueue_cnt
== mq_open_max
) {
433 kmem_free(name
, MQ_NAMELEN
);
437 /* Empty name is invalid */
438 if (name
[0] == '\0') {
439 kmem_free(name
, MQ_NAMELEN
);
443 /* Check for mqueue attributes */
444 if (SCARG(uap
, attr
)) {
445 error
= copyin(SCARG(uap
, attr
), &attr
,
446 sizeof(struct mq_attr
));
448 kmem_free(name
, MQ_NAMELEN
);
451 if (attr
.mq_maxmsg
<= 0 ||
452 attr
.mq_maxmsg
> mq_max_maxmsg
||
453 attr
.mq_msgsize
<= 0 ||
454 attr
.mq_msgsize
> mq_max_msgsize
) {
455 kmem_free(name
, MQ_NAMELEN
);
460 memset(&attr
, 0, sizeof(struct mq_attr
));
461 attr
.mq_maxmsg
= mq_def_maxmsg
;
463 MQ_DEF_MSGSIZE
- sizeof(struct mq_msg
);
467 * Allocate new mqueue, initialize data structures,
468 * copy the name, attributes and set the flag.
470 mq_new
= kmem_zalloc(sizeof(struct mqueue
), KM_SLEEP
);
472 mutex_init(&mq_new
->mq_mtx
, MUTEX_DEFAULT
, IPL_NONE
);
473 cv_init(&mq_new
->mq_send_cv
, "mqsendcv");
474 cv_init(&mq_new
->mq_recv_cv
, "mqrecvcv");
475 for (i
= 0; i
< (MQ_PQSIZE
+ 1); i
++) {
476 TAILQ_INIT(&mq_new
->mq_head
[i
]);
478 selinit(&mq_new
->mq_rsel
);
479 selinit(&mq_new
->mq_wsel
);
481 strlcpy(mq_new
->mq_name
, name
, MQ_NAMELEN
);
482 memcpy(&mq_new
->mq_attrib
, &attr
, sizeof(struct mq_attr
));
484 CTASSERT((O_MASK
& (MQ_UNLINK
| MQ_RECEIVE
)) == 0);
485 mq_new
->mq_attrib
.mq_flags
= (O_MASK
& oflag
);
487 /* Store mode and effective UID with GID */
488 mq_new
->mq_mode
= ((SCARG(uap
, mode
) &
489 ~cwdi
->cwdi_cmask
) & ALLPERMS
) & ~S_ISTXT
;
490 mq_new
->mq_euid
= kauth_cred_geteuid(l
->l_cred
);
491 mq_new
->mq_egid
= kauth_cred_getegid(l
->l_cred
);
494 /* Allocate file structure and descriptor */
495 error
= fd_allocfile(&fp
, &mqd
);
498 mqueue_destroy(mq_new
);
499 kmem_free(name
, MQ_NAMELEN
);
502 fp
->f_type
= DTYPE_MQUEUE
;
503 fp
->f_flag
= FFLAGS(oflag
) & (FREAD
| FWRITE
);
506 /* Look up for mqueue with such name */
507 mutex_enter(&mqlist_mtx
);
508 mq
= mqueue_lookup(name
);
512 KASSERT(mutex_owned(&mq
->mq_mtx
));
514 /* Check if mqueue is not marked as unlinking */
515 if (mq
->mq_attrib
.mq_flags
& MQ_UNLINK
) {
520 /* Fail if O_EXCL is set, and mqueue already exists */
521 if ((oflag
& O_CREAT
) && (oflag
& O_EXCL
)) {
527 * Check the permissions. Note the difference between
528 * VREAD/VWRITE and FREAD/FWRITE.
531 if (fp
->f_flag
& FREAD
) {
534 if (fp
->f_flag
& FWRITE
) {
537 if (mqueue_access(mq
, acc_mode
, l
->l_cred
) != 0) {
542 /* Fail if mqueue neither exists, nor we create it */
543 if ((oflag
& O_CREAT
) == 0) {
544 mutex_exit(&mqlist_mtx
);
545 KASSERT(mq_new
== NULL
);
546 fd_abort(p
, fp
, mqd
);
547 kmem_free(name
, MQ_NAMELEN
);
551 /* Check the limit */
552 if (p
->p_mqueue_cnt
== mq_open_max
) {
557 /* Insert the queue to the list */
559 mutex_enter(&mq
->mq_mtx
);
560 LIST_INSERT_HEAD(&mqueue_head
, mq
, mq_list
);
562 getnanotime(&mq
->mq_btime
);
563 mq
->mq_atime
= mq
->mq_mtime
= mq
->mq_btime
;
566 /* Increase the counters, and make descriptor ready */
571 mutex_exit(&mq
->mq_mtx
);
572 mutex_exit(&mqlist_mtx
);
575 mqueue_destroy(mq_new
);
577 fd_abort(p
, fp
, mqd
);
579 fd_affix(p
, fp
, mqd
);
582 kmem_free(name
, MQ_NAMELEN
);
588 sys_mq_close(struct lwp
*l
, const struct sys_mq_close_args
*uap
,
592 return sys_close(l
, (const void *)uap
, retval
);
596 * Primary mq_recv1() function.
599 mq_recv1(mqd_t mqdes
, void *msg_ptr
, size_t msg_len
, u_int
*msg_prio
,
600 struct timespec
*ts
, ssize_t
*mlen
)
604 struct mq_msg
*msg
= NULL
;
605 struct mq_attr
*mqattr
;
609 /* Get the message queue */
610 error
= mqueue_get(mqdes
, &fp
);
615 if ((fp
->f_flag
& FREAD
) == 0) {
619 getnanotime(&mq
->mq_atime
);
620 mqattr
= &mq
->mq_attrib
;
622 /* Check the message size limits */
623 if (msg_len
< mqattr
->mq_msgsize
) {
628 /* Check if queue is empty */
629 while (mqattr
->mq_curmsgs
== 0) {
632 if (mqattr
->mq_flags
& O_NONBLOCK
) {
637 error
= abstimeout2timo(ts
, &t
);
643 * Block until someone sends the message.
644 * While doing this, notification should not be sent.
646 mqattr
->mq_flags
|= MQ_RECEIVE
;
647 error
= cv_timedwait_sig(&mq
->mq_send_cv
, &mq
->mq_mtx
, t
);
648 mqattr
->mq_flags
&= ~MQ_RECEIVE
;
649 if (error
|| (mqattr
->mq_flags
& MQ_UNLINK
)) {
650 error
= (error
== EWOULDBLOCK
) ? ETIMEDOUT
: EINTR
;
656 * Find the highest priority message, and remove it from the queue.
657 * At first, reserved queue is checked, bitmap is next.
659 msg
= TAILQ_FIRST(&mq
->mq_head
[MQ_PQRESQ
]);
660 if (__predict_true(msg
== NULL
)) {
661 idx
= ffs(mq
->mq_bitmap
);
662 msg
= TAILQ_FIRST(&mq
->mq_head
[idx
]);
663 KASSERT(msg
!= NULL
);
667 TAILQ_REMOVE(&mq
->mq_head
[idx
], msg
, msg_queue
);
669 /* Unmark the bit, if last message. */
670 if (__predict_true(idx
) && TAILQ_EMPTY(&mq
->mq_head
[idx
])) {
671 KASSERT((MQ_PQSIZE
- idx
) == msg
->msg_prio
);
672 mq
->mq_bitmap
&= ~(1 << --idx
);
675 /* Decrement the counter and signal waiter, if any */
676 mqattr
->mq_curmsgs
--;
677 cv_signal(&mq
->mq_recv_cv
);
679 /* Ready for sending now */
680 selnotify(&mq
->mq_wsel
, POLLOUT
| POLLWRNORM
, 0);
682 mutex_exit(&mq
->mq_mtx
);
683 fd_putfile((int)mqdes
);
688 * Copy the data to the user-space.
689 * Note: According to POSIX, no message should be removed from the
690 * queue in case of fail - this would be violated.
692 *mlen
= msg
->msg_len
;
693 error
= copyout(msg
->msg_ptr
, msg_ptr
, msg
->msg_len
);
694 if (error
== 0 && msg_prio
)
695 error
= copyout(&msg
->msg_prio
, msg_prio
, sizeof(unsigned));
696 mqueue_freemsg(msg
, sizeof(struct mq_msg
) + msg
->msg_len
);
702 sys_mq_receive(struct lwp
*l
, const struct sys_mq_receive_args
*uap
,
706 syscallarg(mqd_t) mqdes;
707 syscallarg(char *) msg_ptr;
708 syscallarg(size_t) msg_len;
709 syscallarg(unsigned *) msg_prio;
714 error
= mq_recv1(SCARG(uap
, mqdes
), SCARG(uap
, msg_ptr
),
715 SCARG(uap
, msg_len
), SCARG(uap
, msg_prio
), NULL
, &mlen
);
723 sys___mq_timedreceive50(struct lwp
*l
,
724 const struct sys___mq_timedreceive50_args
*uap
, register_t
*retval
)
727 syscallarg(mqd_t) mqdes;
728 syscallarg(char *) msg_ptr;
729 syscallarg(size_t) msg_len;
730 syscallarg(unsigned *) msg_prio;
731 syscallarg(const struct timespec *) abs_timeout;
733 struct timespec ts
, *tsp
;
737 /* Get and convert time value */
738 if (SCARG(uap
, abs_timeout
)) {
739 error
= copyin(SCARG(uap
, abs_timeout
), &ts
, sizeof(ts
));
747 error
= mq_recv1(SCARG(uap
, mqdes
), SCARG(uap
, msg_ptr
),
748 SCARG(uap
, msg_len
), SCARG(uap
, msg_prio
), tsp
, &mlen
);
756 * Primary mq_send1() function.
759 mq_send1(mqd_t mqdes
, const char *msg_ptr
, size_t msg_len
, u_int msg_prio
,
765 struct mq_attr
*mqattr
;
766 struct proc
*notify
= NULL
;
771 /* Check the priority range */
772 if (msg_prio
>= mq_prio_max
)
775 /* Allocate a new message */
776 size
= sizeof(struct mq_msg
) + msg_len
;
777 if (size
> mq_max_msgsize
)
780 if (size
> MQ_DEF_MSGSIZE
) {
781 msg
= kmem_alloc(size
, KM_SLEEP
);
783 msg
= pool_cache_get(mqmsg_cache
, PR_WAITOK
);
786 /* Get the data from user-space */
787 error
= copyin(msg_ptr
, msg
->msg_ptr
, msg_len
);
789 mqueue_freemsg(msg
, size
);
792 msg
->msg_len
= msg_len
;
793 msg
->msg_prio
= msg_prio
;
796 error
= mqueue_get(mqdes
, &fp
);
798 mqueue_freemsg(msg
, size
);
802 if ((fp
->f_flag
& FWRITE
) == 0) {
806 getnanotime(&mq
->mq_mtime
);
807 mqattr
= &mq
->mq_attrib
;
809 /* Check the message size limit */
810 if (msg_len
<= 0 || msg_len
> mqattr
->mq_msgsize
) {
815 /* Check if queue is full */
816 while (mqattr
->mq_curmsgs
>= mqattr
->mq_maxmsg
) {
819 if (mqattr
->mq_flags
& O_NONBLOCK
) {
824 error
= abstimeout2timo(ts
, &t
);
829 /* Block until queue becomes available */
830 error
= cv_timedwait_sig(&mq
->mq_recv_cv
, &mq
->mq_mtx
, t
);
831 if (error
|| (mqattr
->mq_flags
& MQ_UNLINK
)) {
832 error
= (error
== EWOULDBLOCK
) ? ETIMEDOUT
: error
;
836 KASSERT(mqattr
->mq_curmsgs
< mqattr
->mq_maxmsg
);
839 * Insert message into the queue, according to the priority.
840 * Note the difference between index and priority.
842 if (__predict_true(msg_prio
< MQ_PQSIZE
)) {
843 u_int idx
= MQ_PQSIZE
- msg_prio
;
845 KASSERT(idx
!= MQ_PQRESQ
);
846 TAILQ_INSERT_TAIL(&mq
->mq_head
[idx
], msg
, msg_queue
);
847 mq
->mq_bitmap
|= (1 << --idx
);
849 mqueue_linear_insert(mq
, msg
);
852 /* Check for the notify */
853 if (mqattr
->mq_curmsgs
== 0 && mq
->mq_notify_proc
&&
854 (mqattr
->mq_flags
& MQ_RECEIVE
) == 0 &&
855 mq
->mq_sig_notify
.sigev_notify
== SIGEV_SIGNAL
) {
856 /* Initialize the signal */
858 ksi
.ksi_signo
= mq
->mq_sig_notify
.sigev_signo
;
859 ksi
.ksi_code
= SI_MESGQ
;
860 ksi
.ksi_value
= mq
->mq_sig_notify
.sigev_value
;
861 /* Unregister the process */
862 notify
= mq
->mq_notify_proc
;
863 mq
->mq_notify_proc
= NULL
;
866 /* Increment the counter and signal waiter, if any */
867 mqattr
->mq_curmsgs
++;
868 cv_signal(&mq
->mq_send_cv
);
870 /* Ready for receiving now */
871 selnotify(&mq
->mq_rsel
, POLLIN
| POLLRDNORM
, 0);
873 mutex_exit(&mq
->mq_mtx
);
874 fd_putfile((int)mqdes
);
877 mqueue_freemsg(msg
, size
);
879 /* Send the notify, if needed */
880 mutex_enter(proc_lock
);
881 kpsignal(notify
, &ksi
, NULL
);
882 mutex_exit(proc_lock
);
888 sys_mq_send(struct lwp
*l
, const struct sys_mq_send_args
*uap
,
892 syscallarg(mqd_t) mqdes;
893 syscallarg(const char *) msg_ptr;
894 syscallarg(size_t) msg_len;
895 syscallarg(unsigned) msg_prio;
898 return mq_send1(SCARG(uap
, mqdes
), SCARG(uap
, msg_ptr
),
899 SCARG(uap
, msg_len
), SCARG(uap
, msg_prio
), NULL
);
903 sys___mq_timedsend50(struct lwp
*l
, const struct sys___mq_timedsend50_args
*uap
,
907 syscallarg(mqd_t) mqdes;
908 syscallarg(const char *) msg_ptr;
909 syscallarg(size_t) msg_len;
910 syscallarg(unsigned) msg_prio;
911 syscallarg(const struct timespec *) abs_timeout;
913 struct timespec ts
, *tsp
;
916 /* Get and convert time value */
917 if (SCARG(uap
, abs_timeout
)) {
918 error
= copyin(SCARG(uap
, abs_timeout
), &ts
, sizeof(ts
));
926 return mq_send1(SCARG(uap
, mqdes
), SCARG(uap
, msg_ptr
),
927 SCARG(uap
, msg_len
), SCARG(uap
, msg_prio
), tsp
);
931 sys_mq_notify(struct lwp
*l
, const struct sys_mq_notify_args
*uap
,
935 syscallarg(mqd_t) mqdes;
936 syscallarg(const struct sigevent *) notification;
943 if (SCARG(uap
, notification
)) {
944 /* Get the signal from user-space */
945 error
= copyin(SCARG(uap
, notification
), &sig
,
946 sizeof(struct sigevent
));
949 if (sig
.sigev_notify
== SIGEV_SIGNAL
&&
950 (sig
.sigev_signo
<=0 || sig
.sigev_signo
>= NSIG
))
954 error
= mqueue_get(SCARG(uap
, mqdes
), &fp
);
959 if (SCARG(uap
, notification
)) {
960 /* Register notification: set the signal and target process */
961 if (mq
->mq_notify_proc
== NULL
) {
962 memcpy(&mq
->mq_sig_notify
, &sig
,
963 sizeof(struct sigevent
));
964 mq
->mq_notify_proc
= l
->l_proc
;
966 /* Fail if someone else already registered */
970 /* Unregister the notification */
971 mq
->mq_notify_proc
= NULL
;
973 mutex_exit(&mq
->mq_mtx
);
974 fd_putfile((int)SCARG(uap
, mqdes
));
980 sys_mq_getattr(struct lwp
*l
, const struct sys_mq_getattr_args
*uap
,
984 syscallarg(mqd_t) mqdes;
985 syscallarg(struct mq_attr *) mqstat;
992 /* Get the message queue */
993 error
= mqueue_get(SCARG(uap
, mqdes
), &fp
);
997 memcpy(&attr
, &mq
->mq_attrib
, sizeof(struct mq_attr
));
998 mutex_exit(&mq
->mq_mtx
);
999 fd_putfile((int)SCARG(uap
, mqdes
));
1001 return copyout(&attr
, SCARG(uap
, mqstat
), sizeof(struct mq_attr
));
1005 sys_mq_setattr(struct lwp
*l
, const struct sys_mq_setattr_args
*uap
,
1009 syscallarg(mqd_t) mqdes;
1010 syscallarg(const struct mq_attr *) mqstat;
1011 syscallarg(struct mq_attr *) omqstat;
1015 struct mq_attr attr
;
1016 int error
, nonblock
;
1018 error
= copyin(SCARG(uap
, mqstat
), &attr
, sizeof(struct mq_attr
));
1021 nonblock
= (attr
.mq_flags
& O_NONBLOCK
);
1023 /* Get the message queue */
1024 error
= mqueue_get(SCARG(uap
, mqdes
), &fp
);
1029 /* Copy the old attributes, if needed */
1030 if (SCARG(uap
, omqstat
)) {
1031 memcpy(&attr
, &mq
->mq_attrib
, sizeof(struct mq_attr
));
1034 /* Ignore everything, except O_NONBLOCK */
1036 mq
->mq_attrib
.mq_flags
|= O_NONBLOCK
;
1038 mq
->mq_attrib
.mq_flags
&= ~O_NONBLOCK
;
1040 mutex_exit(&mq
->mq_mtx
);
1041 fd_putfile((int)SCARG(uap
, mqdes
));
1044 * Copy the data to the user-space.
1045 * Note: According to POSIX, the new attributes should not be set in
1046 * case of fail - this would be violated.
1048 if (SCARG(uap
, omqstat
))
1049 error
= copyout(&attr
, SCARG(uap
, omqstat
),
1050 sizeof(struct mq_attr
));
1056 sys_mq_unlink(struct lwp
*l
, const struct sys_mq_unlink_args
*uap
,
1060 syscallarg(const char *) name;
1064 int error
, refcnt
= 0;
1066 /* Get the name from the user-space */
1067 name
= kmem_zalloc(MQ_NAMELEN
, KM_SLEEP
);
1068 error
= copyinstr(SCARG(uap
, name
), name
, MQ_NAMELEN
- 1, NULL
);
1070 kmem_free(name
, MQ_NAMELEN
);
1074 /* Lookup for this file */
1075 mutex_enter(&mqlist_mtx
);
1076 mq
= mqueue_lookup(name
);
1082 /* Check the permissions */
1083 if (kauth_cred_geteuid(l
->l_cred
) != mq
->mq_euid
&&
1084 kauth_authorize_generic(l
->l_cred
, KAUTH_GENERIC_ISSUSER
, NULL
)) {
1085 mutex_exit(&mq
->mq_mtx
);
1090 /* Mark message queue as unlinking, before leaving the window */
1091 mq
->mq_attrib
.mq_flags
|= MQ_UNLINK
;
1093 /* Wake up all waiters, if there are such */
1094 cv_broadcast(&mq
->mq_send_cv
);
1095 cv_broadcast(&mq
->mq_recv_cv
);
1097 selnotify(&mq
->mq_rsel
, POLLHUP
, 0);
1098 selnotify(&mq
->mq_wsel
, POLLHUP
, 0);
1100 refcnt
= mq
->mq_refcnt
;
1102 LIST_REMOVE(mq
, mq_list
);
1104 mutex_exit(&mq
->mq_mtx
);
1106 mutex_exit(&mqlist_mtx
);
1109 * If there are no references - destroy the message
1110 * queue, otherwise, the last mq_close() will do that.
1112 if (error
== 0 && refcnt
== 0)
1115 kmem_free(name
, MQ_NAMELEN
);
1120 * System control nodes.
1123 SYSCTL_SETUP(sysctl_mqueue_setup
, "sysctl mqueue setup")
1125 const struct sysctlnode
*node
= NULL
;
1127 sysctl_createv(clog
, 0, NULL
, NULL
,
1129 CTLTYPE_NODE
, "kern", NULL
,
1132 sysctl_createv(clog
, 0, NULL
, NULL
,
1133 CTLFLAG_PERMANENT
|CTLFLAG_IMMEDIATE
,
1134 CTLTYPE_INT
, "posix_msg",
1135 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its "
1136 "Message Passing option to which the "
1137 "system attempts to conform"),
1138 NULL
, _POSIX_MESSAGE_PASSING
, NULL
, 0,
1139 CTL_KERN
, CTL_CREATE
, CTL_EOL
);
1140 sysctl_createv(clog
, 0, NULL
, &node
,
1142 CTLTYPE_NODE
, "mqueue",
1143 SYSCTL_DESCR("Message queue options"),
1145 CTL_KERN
, CTL_CREATE
, CTL_EOL
);
1150 sysctl_createv(clog
, 0, &node
, NULL
,
1151 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1152 CTLTYPE_INT
, "mq_open_max",
1153 SYSCTL_DESCR("Maximal number of message queue descriptors "
1154 "that process could open"),
1155 NULL
, 0, &mq_open_max
, 0,
1156 CTL_CREATE
, CTL_EOL
);
1157 sysctl_createv(clog
, 0, &node
, NULL
,
1158 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1159 CTLTYPE_INT
, "mq_prio_max",
1160 SYSCTL_DESCR("Maximal priority of the message"),
1161 NULL
, 0, &mq_prio_max
, 0,
1162 CTL_CREATE
, CTL_EOL
);
1163 sysctl_createv(clog
, 0, &node
, NULL
,
1164 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1165 CTLTYPE_INT
, "mq_max_msgsize",
1166 SYSCTL_DESCR("Maximal allowed size of the message"),
1167 NULL
, 0, &mq_max_msgsize
, 0,
1168 CTL_CREATE
, CTL_EOL
);
1169 sysctl_createv(clog
, 0, &node
, NULL
,
1170 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1171 CTLTYPE_INT
, "mq_def_maxmsg",
1172 SYSCTL_DESCR("Default maximal message count"),
1173 NULL
, 0, &mq_def_maxmsg
, 0,
1174 CTL_CREATE
, CTL_EOL
);
1175 sysctl_createv(clog
, 0, &node
, NULL
,
1176 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1177 CTLTYPE_INT
, "mq_max_maxmsg",
1178 SYSCTL_DESCR("Maximal allowed message count"),
1179 NULL
, 0, &mq_max_maxmsg
, 0,
1180 CTL_CREATE
, CTL_EOL
);
1189 mqueue_print_list(void (*pr
)(const char *, ...))
1193 (*pr
)("Global list of the message queues:\n");
1194 (*pr
)("%20s %10s %8s %8s %3s %4s %4s %4s\n",
1195 "Name", "Ptr", "Mode", "Flags", "Ref",
1196 "MaxMsg", "MsgSze", "CurMsg");
1197 LIST_FOREACH(mq
, &mqueue_head
, mq_list
) {
1198 (*pr
)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n",
1199 mq
->mq_name
, mq
, mq
->mq_mode
,
1200 mq
->mq_attrib
.mq_flags
, mq
->mq_refcnt
,
1201 mq
->mq_attrib
.mq_maxmsg
, mq
->mq_attrib
.mq_msgsize
,
1202 mq
->mq_attrib
.mq_curmsgs
);
1206 #endif /* defined(DDB) */