The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/sys_mqueue.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 79761ebe32aa83c036a67eeab712cd03


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.