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