sys_mqueue.c revision 1.11.2.1 1 /* $NetBSD: sys_mqueue.c,v 1.11.2.1 2008/10/19 22:17:28 haad Exp $ */
2
3 /*
4 * Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Implementation of POSIX message queues.
31 * Defined in the Base Definitions volume of IEEE Std 1003.1-2001.
32 *
33 * Locking
34 *
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.
38 *
39 * Lock order:
40 * mqlist_mtx
41 * -> mqueue::mq_mtx
42 */
43
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.11.2.1 2008/10/19 22:17:28 haad Exp $");
46
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>
52 #include <sys/file.h>
53 #include <sys/filedesc.h>
54 #include <sys/kauth.h>
55 #include <sys/kernel.h>
56 #include <sys/kmem.h>
57 #include <sys/lwp.h>
58 #include <sys/mqueue.h>
59 #include <sys/mutex.h>
60 #include <sys/pool.h>
61 #include <sys/poll.h>
62 #include <sys/proc.h>
63 #include <sys/queue.h>
64 #include <sys/select.h>
65 #include <sys/signal.h>
66 #include <sys/signalvar.h>
67 #include <sys/stat.h>
68 #include <sys/sysctl.h>
69 #include <sys/syscallargs.h>
70 #include <sys/systm.h>
71 #include <sys/unistd.h>
72 #include <sys/vnode.h>
73
74 /* System-wide limits. */
75 static u_int mq_open_max = MQ_OPEN_MAX;
76 static u_int mq_prio_max = MQ_PRIO_MAX;
77
78 static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE;
79 static u_int mq_def_maxmsg = 32;
80
81 static kmutex_t mqlist_mtx;
82 static pool_cache_t mqmsg_cache;
83 static LIST_HEAD(, mqueue) mqueue_head =
84 LIST_HEAD_INITIALIZER(mqueue_head);
85
86 static int mq_poll_fop(file_t *, int);
87 static int mq_close_fop(file_t *);
88
89 #define FNOVAL -1
90
91 static const struct fileops mqops = {
92 fbadop_read, fbadop_write, fbadop_ioctl, fnullop_fcntl, mq_poll_fop,
93 fbadop_stat, mq_close_fop, fnullop_kqfilter
94 };
95
96 /*
97 * Initialize POSIX message queue subsystem.
98 */
99 void
100 mqueue_sysinit(void)
101 {
102
103 mqmsg_cache = pool_cache_init(MQ_DEF_MSGSIZE, coherency_unit,
104 0, 0, "mqmsgpl", NULL, IPL_NONE, NULL, NULL, NULL);
105 mutex_init(&mqlist_mtx, MUTEX_DEFAULT, IPL_NONE);
106 }
107
108 /*
109 * Free the message.
110 */
111 static void
112 mqueue_freemsg(struct mq_msg *msg, const size_t size)
113 {
114
115 if (size > MQ_DEF_MSGSIZE)
116 kmem_free(msg, size);
117 else
118 pool_cache_put(mqmsg_cache, msg);
119 }
120
121 /*
122 * Destroy the message queue.
123 */
124 static void
125 mqueue_destroy(struct mqueue *mq)
126 {
127 struct mq_msg *msg;
128
129 while ((msg = TAILQ_FIRST(&mq->mq_head)) != NULL) {
130 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue);
131 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
132 }
133 seldestroy(&mq->mq_rsel);
134 seldestroy(&mq->mq_wsel);
135 cv_destroy(&mq->mq_send_cv);
136 cv_destroy(&mq->mq_recv_cv);
137 mutex_destroy(&mq->mq_mtx);
138 kmem_free(mq, sizeof(struct mqueue));
139 }
140
141 /*
142 * Lookup for file name in general list of message queues.
143 * => locks the message queue
144 */
145 static void *
146 mqueue_lookup(char *name)
147 {
148 struct mqueue *mq;
149 KASSERT(mutex_owned(&mqlist_mtx));
150
151 LIST_FOREACH(mq, &mqueue_head, mq_list) {
152 if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) {
153 mutex_enter(&mq->mq_mtx);
154 return mq;
155 }
156 }
157
158 return NULL;
159 }
160
161 /*
162 * Check access against message queue.
163 */
164 static inline int
165 mqueue_access(struct lwp *l, struct mqueue *mq, int access)
166 {
167 mode_t acc_mode = 0;
168
169 KASSERT(mutex_owned(&mq->mq_mtx));
170 KASSERT(access != FNOVAL);
171
172 /* Note the difference between VREAD/VWRITE and FREAD/FWRITE */
173 if (access & FREAD)
174 acc_mode |= VREAD;
175 if (access & FWRITE)
176 acc_mode |= VWRITE;
177
178 return vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid,
179 acc_mode, l->l_cred);
180 }
181
182 /*
183 * Get the mqueue from the descriptor.
184 * => locks the message queue, if found
185 * => increments the reference on file entry
186 */
187 static int
188 mqueue_get(struct lwp *l, mqd_t mqd, int access, file_t **fpr)
189 {
190 file_t *fp;
191 struct mqueue *mq;
192
193 /* Get the file and descriptor */
194 fp = fd_getfile((int)mqd);
195 if (fp == NULL)
196 return EBADF;
197
198 /* Increment the reference of file entry, and lock the mqueue */
199 mq = fp->f_data;
200 *fpr = fp;
201 mutex_enter(&mq->mq_mtx);
202 if (access == FNOVAL) {
203 KASSERT(mutex_owned(&mq->mq_mtx));
204 return 0;
205 }
206
207 /* Check the access mode and permission */
208 if ((fp->f_flag & access) != access || mqueue_access(l, mq, access)) {
209 mutex_exit(&mq->mq_mtx);
210 fd_putfile((int)mqd);
211 return EPERM;
212 }
213 return 0;
214 }
215
216 /*
217 * Converter from struct timespec to the ticks.
218 * Used by mq_timedreceive(), mq_timedsend().
219 */
220 static int
221 abstimeout2timo(const void *uaddr, int *timo)
222 {
223 struct timespec ts;
224 int error;
225
226 error = copyin(uaddr, &ts, sizeof(struct timespec));
227 if (error)
228 return error;
229
230 /*
231 * According to POSIX, validation check is needed only in case of
232 * blocking. Thus, set the invalid value right now, and fail latter.
233 */
234 error = itimespecfix(&ts);
235 *timo = (error == 0) ? tstohz(&ts) : -1;
236
237 return 0;
238 }
239
240 static int
241 mq_poll_fop(file_t *fp, int events)
242 {
243 struct mqueue *mq = fp->f_data;
244 int revents = 0;
245
246 mutex_enter(&mq->mq_mtx);
247 if (events & (POLLIN | POLLRDNORM)) {
248 /* Ready for receiving, if there are messages in the queue */
249 if (mq->mq_attrib.mq_curmsgs)
250 revents |= (POLLIN | POLLRDNORM);
251 else
252 selrecord(curlwp, &mq->mq_rsel);
253 }
254 if (events & (POLLOUT | POLLWRNORM)) {
255 /* Ready for sending, if the message queue is not full */
256 if (mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg)
257 revents |= (POLLOUT | POLLWRNORM);
258 else
259 selrecord(curlwp, &mq->mq_wsel);
260 }
261 mutex_exit(&mq->mq_mtx);
262
263 return revents;
264 }
265
266 static int
267 mq_close_fop(file_t *fp)
268 {
269 struct proc *p = curproc;
270 struct mqueue *mq = fp->f_data;
271 bool destroy;
272
273 mutex_enter(&mqlist_mtx);
274 mutex_enter(&mq->mq_mtx);
275
276 /* Decrease the counters */
277 p->p_mqueue_cnt--;
278 mq->mq_refcnt--;
279
280 /* Remove notification if registered for this process */
281 if (mq->mq_notify_proc == p)
282 mq->mq_notify_proc = NULL;
283
284 /*
285 * If this is the last reference and mqueue is marked for unlink,
286 * remove and later destroy the message queue.
287 */
288 if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
289 LIST_REMOVE(mq, mq_list);
290 destroy = true;
291 } else
292 destroy = false;
293
294 mutex_exit(&mq->mq_mtx);
295 mutex_exit(&mqlist_mtx);
296
297 if (destroy)
298 mqueue_destroy(mq);
299
300 return 0;
301 }
302
303 /*
304 * General mqueue system calls.
305 */
306
307 int
308 sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap,
309 register_t *retval)
310 {
311 /* {
312 syscallarg(const char *) name;
313 syscallarg(int) oflag;
314 syscallarg(mode_t) mode;
315 syscallarg(struct mq_attr) attr;
316 } */
317 struct proc *p = l->l_proc;
318 struct mqueue *mq, *mq_new = NULL;
319 file_t *fp;
320 char *name;
321 int mqd, error, oflag;
322
323 /* Check access mode flags */
324 oflag = SCARG(uap, oflag);
325 if ((oflag & O_ACCMODE) == 0)
326 return EINVAL;
327
328 /* Get the name from the user-space */
329 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP);
330 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
331 if (error) {
332 kmem_free(name, MQ_NAMELEN);
333 return error;
334 }
335
336 if (oflag & O_CREAT) {
337 struct cwdinfo *cwdi = p->p_cwdi;
338 struct mq_attr attr;
339
340 /* Check the limit */
341 if (p->p_mqueue_cnt == mq_open_max) {
342 kmem_free(name, MQ_NAMELEN);
343 return EMFILE;
344 }
345
346 /* Check for mqueue attributes */
347 if (SCARG(uap, attr)) {
348 error = copyin(SCARG(uap, attr), &attr,
349 sizeof(struct mq_attr));
350 if (error) {
351 kmem_free(name, MQ_NAMELEN);
352 return error;
353 }
354 if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 ||
355 attr.mq_msgsize > mq_max_msgsize) {
356 kmem_free(name, MQ_NAMELEN);
357 return EINVAL;
358 }
359 attr.mq_curmsgs = 0;
360 } else {
361 memset(&attr, 0, sizeof(struct mq_attr));
362 attr.mq_maxmsg = mq_def_maxmsg;
363 attr.mq_msgsize =
364 MQ_DEF_MSGSIZE - sizeof(struct mq_msg);
365 }
366
367 /*
368 * Allocate new mqueue, initialize data structures,
369 * copy the name, attributes and set the flag.
370 */
371 mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP);
372
373 mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE);
374 cv_init(&mq_new->mq_send_cv, "mqsendcv");
375 cv_init(&mq_new->mq_recv_cv, "mqrecvcv");
376 TAILQ_INIT(&mq_new->mq_head);
377 selinit(&mq_new->mq_rsel);
378 selinit(&mq_new->mq_wsel);
379
380 strlcpy(mq_new->mq_name, name, MQ_NAMELEN);
381 memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr));
382 mq_new->mq_attrib.mq_flags = oflag;
383
384 /* Store mode and effective UID with GID */
385 mq_new->mq_mode = ((SCARG(uap, mode) &
386 ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT;
387 mq_new->mq_euid = kauth_cred_geteuid(l->l_cred);
388 mq_new->mq_egid = kauth_cred_getegid(l->l_cred);
389 }
390
391 /* Allocate file structure and descriptor */
392 error = fd_allocfile(&fp, &mqd);
393 if (error) {
394 if (mq_new)
395 mqueue_destroy(mq_new);
396 kmem_free(name, MQ_NAMELEN);
397 return error;
398 }
399 fp->f_type = DTYPE_MQUEUE;
400 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE);
401 fp->f_ops = &mqops;
402
403 /* Look up for mqueue with such name */
404 mutex_enter(&mqlist_mtx);
405 mq = mqueue_lookup(name);
406 if (mq) {
407 KASSERT(mutex_owned(&mq->mq_mtx));
408
409 /* Check if mqueue is not marked as unlinking */
410 if (mq->mq_attrib.mq_flags & MQ_UNLINK) {
411 error = EACCES;
412 goto exit;
413 }
414 /* Fail if O_EXCL is set, and mqueue already exists */
415 if ((oflag & O_CREAT) && (oflag & O_EXCL)) {
416 error = EEXIST;
417 goto exit;
418 }
419 /* Check the permission */
420 if (mqueue_access(l, mq, fp->f_flag)) {
421 error = EACCES;
422 goto exit;
423 }
424 } else {
425 /* Fail if mqueue neither exists, nor we create it */
426 if ((oflag & O_CREAT) == 0) {
427 mutex_exit(&mqlist_mtx);
428 KASSERT(mq_new == NULL);
429 fd_abort(p, fp, mqd);
430 kmem_free(name, MQ_NAMELEN);
431 return ENOENT;
432 }
433
434 /* Check the limit */
435 if (p->p_mqueue_cnt == mq_open_max) {
436 error = EMFILE;
437 goto exit;
438 }
439
440 /* Insert the queue to the list */
441 mq = mq_new;
442 mutex_enter(&mq->mq_mtx);
443 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list);
444 mq_new = NULL;
445 }
446
447 /* Increase the counters, and make descriptor ready */
448 p->p_mqueue_cnt++;
449 mq->mq_refcnt++;
450 fp->f_data = mq;
451 exit:
452 mutex_exit(&mq->mq_mtx);
453 mutex_exit(&mqlist_mtx);
454
455 if (mq_new)
456 mqueue_destroy(mq_new);
457 if (error) {
458 fd_abort(p, fp, mqd);
459 } else {
460 fd_affix(p, fp, mqd);
461 *retval = mqd;
462 }
463 kmem_free(name, MQ_NAMELEN);
464
465 return error;
466 }
467
468 int
469 sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap,
470 register_t *retval)
471 {
472
473 return sys_close(l, (const void *)uap, retval);
474 }
475
476 /*
477 * Primary mq_receive1() function.
478 */
479 static int
480 mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len,
481 unsigned *msg_prio, int t, ssize_t *mlen)
482 {
483 file_t *fp = NULL;
484 struct mqueue *mq;
485 struct mq_msg *msg = NULL;
486 int error;
487
488 /* Get the message queue */
489 error = mqueue_get(l, mqdes, FREAD, &fp);
490 if (error)
491 return error;
492 mq = fp->f_data;
493
494 /* Check the message size limits */
495 if (msg_len < mq->mq_attrib.mq_msgsize) {
496 error = EMSGSIZE;
497 goto error;
498 }
499
500 /* Check if queue is empty */
501 while (TAILQ_EMPTY(&mq->mq_head)) {
502 if (mq->mq_attrib.mq_flags & O_NONBLOCK) {
503 error = EAGAIN;
504 goto error;
505 }
506 if (t < 0) {
507 error = EINVAL;
508 goto error;
509 }
510 /*
511 * Block until someone sends the message.
512 * While doing this, notification should not be sent.
513 */
514 mq->mq_attrib.mq_flags |= MQ_RECEIVE;
515 error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t);
516 mq->mq_attrib.mq_flags &= ~MQ_RECEIVE;
517 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
518 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR;
519 goto error;
520 }
521 }
522
523 /* Remove the message from the queue */
524 msg = TAILQ_FIRST(&mq->mq_head);
525 KASSERT(msg != NULL);
526 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue);
527
528 /* Decrement the counter and signal waiter, if any */
529 mq->mq_attrib.mq_curmsgs--;
530 cv_signal(&mq->mq_recv_cv);
531
532 /* Ready for sending now */
533 selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0);
534 error:
535 mutex_exit(&mq->mq_mtx);
536 fd_putfile((int)mqdes);
537 if (error)
538 return error;
539
540 /*
541 * Copy the data to the user-space.
542 * Note: According to POSIX, no message should be removed from the
543 * queue in case of fail - this would be violated.
544 */
545 *mlen = msg->msg_len;
546 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len);
547 if (error == 0 && msg_prio)
548 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned));
549 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
550
551 return error;
552 }
553
554 int
555 sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap,
556 register_t *retval)
557 {
558 /* {
559 syscallarg(mqd_t) mqdes;
560 syscallarg(char *) msg_ptr;
561 syscallarg(size_t) msg_len;
562 syscallarg(unsigned *) msg_prio;
563 } */
564 int error;
565 ssize_t mlen;
566
567 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
568 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen);
569 if (error == 0)
570 *retval = mlen;
571
572 return error;
573 }
574
575 int
576 sys_mq_timedreceive(struct lwp *l, const struct sys_mq_timedreceive_args *uap,
577 register_t *retval)
578 {
579 /* {
580 syscallarg(mqd_t) mqdes;
581 syscallarg(char *) msg_ptr;
582 syscallarg(size_t) msg_len;
583 syscallarg(unsigned *) msg_prio;
584 syscallarg(const struct timespec *) abs_timeout;
585 } */
586 int error, t;
587 ssize_t mlen;
588
589 /* Get and convert time value */
590 if (SCARG(uap, abs_timeout)) {
591 error = abstimeout2timo(SCARG(uap, abs_timeout), &t);
592 if (error)
593 return error;
594 } else
595 t = 0;
596
597 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
598 SCARG(uap, msg_len), SCARG(uap, msg_prio), t, &mlen);
599 if (error == 0)
600 *retval = mlen;
601
602 return error;
603 }
604
605 /*
606 * Primary mq_send1() function.
607 */
608 static int
609 mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len,
610 unsigned msg_prio, int t)
611 {
612 file_t *fp = NULL;
613 struct mqueue *mq;
614 struct mq_msg *msg, *pos_msg;
615 struct proc *notify = NULL;
616 ksiginfo_t ksi;
617 size_t size;
618 int error;
619
620 /* Check the priority range */
621 if (msg_prio >= mq_prio_max)
622 return EINVAL;
623
624 /* Allocate a new message */
625 size = sizeof(struct mq_msg) + msg_len;
626 if (size > mq_max_msgsize)
627 return EMSGSIZE;
628
629 if (size > MQ_DEF_MSGSIZE)
630 msg = kmem_alloc(size, KM_SLEEP);
631 else
632 msg = pool_cache_get(mqmsg_cache, PR_WAITOK);
633
634 /* Get the data from user-space */
635 error = copyin(msg_ptr, msg->msg_ptr, msg_len);
636 if (error) {
637 mqueue_freemsg(msg, size);
638 return error;
639 }
640 msg->msg_len = msg_len;
641 msg->msg_prio = msg_prio;
642
643 /* Get the mqueue */
644 error = mqueue_get(l, mqdes, FWRITE, &fp);
645 if (error) {
646 mqueue_freemsg(msg, size);
647 return error;
648 }
649 mq = fp->f_data;
650
651 /* Check the message size limit */
652 if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) {
653 error = EMSGSIZE;
654 goto error;
655 }
656
657 /* Check if queue is full */
658 while (mq->mq_attrib.mq_curmsgs >= mq->mq_attrib.mq_maxmsg) {
659 if (mq->mq_attrib.mq_flags & O_NONBLOCK) {
660 error = EAGAIN;
661 goto error;
662 }
663 if (t < 0) {
664 error = EINVAL;
665 goto error;
666 }
667 /* Block until queue becomes available */
668 error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t);
669 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
670 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error;
671 goto error;
672 }
673 }
674 KASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg);
675
676 /* Insert message into the queue, according to the priority */
677 TAILQ_FOREACH(pos_msg, &mq->mq_head, msg_queue)
678 if (msg->msg_prio > pos_msg->msg_prio)
679 break;
680 if (pos_msg == NULL)
681 TAILQ_INSERT_TAIL(&mq->mq_head, msg, msg_queue);
682 else
683 TAILQ_INSERT_BEFORE(pos_msg, msg, msg_queue);
684
685 /* Check for the notify */
686 if (mq->mq_attrib.mq_curmsgs == 0 && mq->mq_notify_proc &&
687 (mq->mq_attrib.mq_flags & MQ_RECEIVE) == 0) {
688 /* Initialize the signal */
689 KSI_INIT(&ksi);
690 ksi.ksi_signo = mq->mq_sig_notify.sigev_signo;
691 ksi.ksi_code = SI_MESGQ;
692 ksi.ksi_value = mq->mq_sig_notify.sigev_value;
693 /* Unregister the process */
694 notify = mq->mq_notify_proc;
695 mq->mq_notify_proc = NULL;
696 }
697
698 /* Increment the counter and signal waiter, if any */
699 mq->mq_attrib.mq_curmsgs++;
700 cv_signal(&mq->mq_send_cv);
701
702 /* Ready for receiving now */
703 selnotify(&mq->mq_rsel, POLLIN | POLLRDNORM, 0);
704 error:
705 mutex_exit(&mq->mq_mtx);
706 fd_putfile((int)mqdes);
707
708 if (error) {
709 mqueue_freemsg(msg, size);
710 } else if (notify) {
711 /* Send the notify, if needed */
712 mutex_enter(proc_lock);
713 kpsignal(notify, &ksi, NULL);
714 mutex_exit(proc_lock);
715 }
716
717 return error;
718 }
719
720 int
721 sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap,
722 register_t *retval)
723 {
724 /* {
725 syscallarg(mqd_t) mqdes;
726 syscallarg(const char *) msg_ptr;
727 syscallarg(size_t) msg_len;
728 syscallarg(unsigned) msg_prio;
729 } */
730
731 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
732 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0);
733 }
734
735 int
736 sys_mq_timedsend(struct lwp *l, const struct sys_mq_timedsend_args *uap,
737 register_t *retval)
738 {
739 /* {
740 syscallarg(mqd_t) mqdes;
741 syscallarg(const char *) msg_ptr;
742 syscallarg(size_t) msg_len;
743 syscallarg(unsigned) msg_prio;
744 syscallarg(const struct timespec *) abs_timeout;
745 } */
746 int t;
747
748 /* Get and convert time value */
749 if (SCARG(uap, abs_timeout)) {
750 int error = abstimeout2timo(SCARG(uap, abs_timeout), &t);
751 if (error)
752 return error;
753 } else
754 t = 0;
755
756 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
757 SCARG(uap, msg_len), SCARG(uap, msg_prio), t);
758 }
759
760 int
761 sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap,
762 register_t *retval)
763 {
764 /* {
765 syscallarg(mqd_t) mqdes;
766 syscallarg(const struct sigevent *) notification;
767 } */
768 file_t *fp = NULL;
769 struct mqueue *mq;
770 struct sigevent sig;
771 int error;
772
773 if (SCARG(uap, notification)) {
774 /* Get the signal from user-space */
775 error = copyin(SCARG(uap, notification), &sig,
776 sizeof(struct sigevent));
777 if (error)
778 return error;
779 }
780
781 error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp);
782 if (error)
783 return error;
784 mq = fp->f_data;
785
786 if (SCARG(uap, notification)) {
787 /* Register notification: set the signal and target process */
788 if (mq->mq_notify_proc == NULL) {
789 memcpy(&mq->mq_sig_notify, &sig,
790 sizeof(struct sigevent));
791 mq->mq_notify_proc = l->l_proc;
792 } else {
793 /* Fail if someone else already registered */
794 error = EBUSY;
795 }
796 } else {
797 /* Unregister the notification */
798 mq->mq_notify_proc = NULL;
799 }
800 mutex_exit(&mq->mq_mtx);
801 fd_putfile((int)SCARG(uap, mqdes));
802
803 return error;
804 }
805
806 int
807 sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap,
808 register_t *retval)
809 {
810 /* {
811 syscallarg(mqd_t) mqdes;
812 syscallarg(struct mq_attr *) mqstat;
813 } */
814 file_t *fp = NULL;
815 struct mqueue *mq;
816 struct mq_attr attr;
817 int error;
818
819 /* Get the message queue */
820 error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp);
821 if (error)
822 return error;
823 mq = fp->f_data;
824 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
825 mutex_exit(&mq->mq_mtx);
826 fd_putfile((int)SCARG(uap, mqdes));
827
828 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr));
829 }
830
831 int
832 sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap,
833 register_t *retval)
834 {
835 /* {
836 syscallarg(mqd_t) mqdes;
837 syscallarg(const struct mq_attr *) mqstat;
838 syscallarg(struct mq_attr *) omqstat;
839 } */
840 file_t *fp = NULL;
841 struct mqueue *mq;
842 struct mq_attr attr;
843 int error, nonblock;
844
845 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr));
846 if (error)
847 return error;
848 nonblock = (attr.mq_flags & O_NONBLOCK);
849
850 /* Get the message queue */
851 error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp);
852 if (error)
853 return error;
854 mq = fp->f_data;
855
856 /* Copy the old attributes, if needed */
857 if (SCARG(uap, omqstat))
858 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
859
860 /* Ignore everything, except O_NONBLOCK */
861 if (nonblock)
862 mq->mq_attrib.mq_flags |= O_NONBLOCK;
863 else
864 mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
865
866 mutex_exit(&mq->mq_mtx);
867 fd_putfile((int)SCARG(uap, mqdes));
868
869 /*
870 * Copy the data to the user-space.
871 * Note: According to POSIX, the new attributes should not be set in
872 * case of fail - this would be violated.
873 */
874 if (SCARG(uap, omqstat))
875 error = copyout(&attr, SCARG(uap, omqstat),
876 sizeof(struct mq_attr));
877
878 return error;
879 }
880
881 int
882 sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap,
883 register_t *retval)
884 {
885 /* {
886 syscallarg(const char *) name;
887 } */
888 struct mqueue *mq;
889 char *name;
890 int error, refcnt = 0;
891
892 /* Get the name from the user-space */
893 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP);
894 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
895 if (error) {
896 kmem_free(name, MQ_NAMELEN);
897 return error;
898 }
899
900 /* Lookup for this file */
901 mutex_enter(&mqlist_mtx);
902 mq = mqueue_lookup(name);
903 if (mq == NULL) {
904 error = ENOENT;
905 goto error;
906 }
907
908 /* Check the permissions */
909 if (mqueue_access(l, mq, FWRITE)) {
910 mutex_exit(&mq->mq_mtx);
911 error = EACCES;
912 goto error;
913 }
914
915 /* Mark message queue as unlinking, before leaving the window */
916 mq->mq_attrib.mq_flags |= MQ_UNLINK;
917
918 /* Wake up all waiters, if there are such */
919 cv_broadcast(&mq->mq_send_cv);
920 cv_broadcast(&mq->mq_recv_cv);
921
922 selnotify(&mq->mq_rsel, POLLHUP, 0);
923 selnotify(&mq->mq_wsel, POLLHUP, 0);
924
925 refcnt = mq->mq_refcnt;
926 if (refcnt == 0)
927 LIST_REMOVE(mq, mq_list);
928
929 mutex_exit(&mq->mq_mtx);
930 error:
931 mutex_exit(&mqlist_mtx);
932
933 /*
934 * If there are no references - destroy the message
935 * queue, otherwise, the last mq_close() will do that.
936 */
937 if (error == 0 && refcnt == 0)
938 mqueue_destroy(mq);
939
940 kmem_free(name, MQ_NAMELEN);
941 return error;
942 }
943
944 /*
945 * SysCtl.
946 */
947
948 SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup")
949 {
950 const struct sysctlnode *node = NULL;
951
952 sysctl_createv(clog, 0, NULL, NULL,
953 CTLFLAG_PERMANENT,
954 CTLTYPE_NODE, "kern", NULL,
955 NULL, 0, NULL, 0,
956 CTL_KERN, CTL_EOL);
957 sysctl_createv(clog, 0, NULL, NULL,
958 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
959 CTLTYPE_INT, "posix_msg",
960 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its "
961 "Message Passing option to which the "
962 "system attempts to conform"),
963 NULL, _POSIX_MESSAGE_PASSING, NULL, 0,
964 CTL_KERN, CTL_CREATE, CTL_EOL);
965 sysctl_createv(clog, 0, NULL, &node,
966 CTLFLAG_PERMANENT,
967 CTLTYPE_NODE, "mqueue",
968 SYSCTL_DESCR("Message queue options"),
969 NULL, 0, NULL, 0,
970 CTL_KERN, CTL_CREATE, CTL_EOL);
971
972 if (node == NULL)
973 return;
974
975 sysctl_createv(clog, 0, &node, NULL,
976 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
977 CTLTYPE_INT, "mq_open_max",
978 SYSCTL_DESCR("Maximal number of message queue descriptors "
979 "that process could open"),
980 NULL, 0, &mq_open_max, 0,
981 CTL_CREATE, CTL_EOL);
982 sysctl_createv(clog, 0, &node, NULL,
983 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
984 CTLTYPE_INT, "mq_prio_max",
985 SYSCTL_DESCR("Maximal priority of the message"),
986 NULL, 0, &mq_prio_max, 0,
987 CTL_CREATE, CTL_EOL);
988 sysctl_createv(clog, 0, &node, NULL,
989 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
990 CTLTYPE_INT, "mq_max_msgsize",
991 SYSCTL_DESCR("Maximal allowed size of the message"),
992 NULL, 0, &mq_max_msgsize, 0,
993 CTL_CREATE, CTL_EOL);
994 sysctl_createv(clog, 0, &node, NULL,
995 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
996 CTLTYPE_INT, "mq_def_maxmsg",
997 SYSCTL_DESCR("Default maximal message count"),
998 NULL, 0, &mq_def_maxmsg, 0,
999 CTL_CREATE, CTL_EOL);
1000 }
1001
1002 /*
1003 * Debugging.
1004 */
1005 #if defined(DDB)
1006
1007 void
1008 mqueue_print_list(void (*pr)(const char *, ...))
1009 {
1010 struct mqueue *mq;
1011
1012 (*pr)("Global list of the message queues:\n");
1013 (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n",
1014 "Name", "Ptr", "Mode", "Flags", "Ref",
1015 "MaxMsg", "MsgSze", "CurMsg");
1016 LIST_FOREACH(mq, &mqueue_head, mq_list) {
1017 (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n",
1018 mq->mq_name, mq, mq->mq_mode,
1019 mq->mq_attrib.mq_flags, mq->mq_refcnt,
1020 mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize,
1021 mq->mq_attrib.mq_curmsgs);
1022 }
1023 }
1024
1025 #endif /* defined(DDB) */
1026