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/compat/mach/mach_semaphore.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: mach_semaphore.c,v 1.19 2008/04/28 20:23:44 martin Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Emmanuel Dreyfus
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: mach_semaphore.c,v 1.19 2008/04/28 20:23:44 martin Exp $");
   34 
   35 #include <sys/types.h>
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/signal.h>
   39 #include <sys/pool.h>
   40 #include <sys/rwlock.h>
   41 #include <sys/malloc.h>
   42 #include <sys/proc.h>
   43 
   44 #include <compat/mach/mach_types.h>
   45 #include <compat/mach/mach_message.h>
   46 #include <compat/mach/mach_semaphore.h>
   47 #include <compat/mach/mach_clock.h>
   48 #include <compat/mach/mach_errno.h>
   49 #include <compat/mach/mach_port.h>
   50 #include <compat/mach/mach_services.h>
   51 #include <compat/mach/mach_syscallargs.h>
   52 
   53 /* Semaphore list, lock, pools */
   54 static LIST_HEAD(mach_semaphore_list, mach_semaphore) mach_semaphore_list;
   55 static krwlock_t mach_semaphore_list_lock;
   56 static struct pool mach_semaphore_list_pool;
   57 static struct pool mach_waiting_lwp_pool;
   58 
   59 /* Function to manipulate them */
   60 static struct mach_semaphore *mach_semaphore_get(int, int);
   61 static void mach_semaphore_put(struct mach_semaphore *);
   62 static struct mach_waiting_lwp *mach_waiting_lwp_get
   63     (struct lwp *, struct mach_semaphore *);
   64 static void mach_waiting_lwp_put
   65     (struct mach_waiting_lwp *, struct mach_semaphore *, int);
   66 
   67 int
   68 mach_sys_semaphore_wait_trap(struct lwp *l, const struct mach_sys_semaphore_wait_trap_args *uap, register_t *retval)
   69 {
   70         /* {
   71                 syscallarg(mach_port_name_t) wait_name;
   72         } */
   73         struct mach_semaphore *ms;
   74         struct mach_waiting_lwp *mwl;
   75         struct mach_right *mr;
   76         mach_port_t mn;
   77         int blocked = 0;
   78 
   79         mn = SCARG(uap, wait_name);
   80         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
   81                 return EPERM;
   82 
   83         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
   84                 return EINVAL;
   85 
   86         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
   87 
   88         rw_enter(&ms->ms_lock, RW_WRITER);
   89         ms->ms_value--;
   90         if (ms->ms_value < 0)
   91                 blocked = 1;
   92         rw_exit(&ms->ms_lock);
   93 
   94         if (blocked != 0) {
   95                 mwl = mach_waiting_lwp_get(l, ms);
   96                 while (ms->ms_value < 0)
   97                         tsleep(mwl, PZERO|PCATCH, "sem_wait", 0);
   98                 mach_waiting_lwp_put(mwl, ms, 0);
   99         }
  100         return 0;
  101 }
  102 
  103 int
  104 mach_sys_semaphore_signal_trap(struct lwp *l, const struct mach_sys_semaphore_signal_trap_args *uap, register_t *retval)
  105 {
  106         /* {
  107                 syscallarg(mach_port_name_t) signal_name;
  108         } */
  109         struct mach_semaphore *ms;
  110         struct mach_waiting_lwp *mwl;
  111         struct mach_right *mr;
  112         mach_port_t mn;
  113         int unblocked = 0;
  114 
  115         mn = SCARG(uap, signal_name);
  116         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
  117                 return EPERM;
  118 
  119         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  120                 return EINVAL;
  121 
  122         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  123 
  124         rw_enter(&ms->ms_lock, RW_WRITER);
  125         ms->ms_value++;
  126         if (ms->ms_value >= 0)
  127                 unblocked = 1;
  128         rw_exit(&ms->ms_lock);
  129 
  130         if (unblocked != 0) {
  131                 rw_enter(&ms->ms_lock, RW_READER);
  132                 mwl = TAILQ_FIRST(&ms->ms_waiting);
  133                 wakeup(mwl);
  134                 rw_exit(&ms->ms_lock);
  135         }
  136         return 0;
  137 }
  138 
  139 int
  140 mach_semaphore_create(struct mach_trap_args *args)
  141 {
  142         mach_semaphore_create_request_t *req = args->smsg;
  143         mach_semaphore_create_reply_t *rep = args->rmsg;
  144         size_t *msglen = args->rsize;
  145         struct lwp *l = args->l;
  146         struct mach_semaphore *ms;
  147         struct mach_port *mp;
  148         struct mach_right *mr;
  149 
  150         ms = mach_semaphore_get(req->req_value, req->req_policy);
  151 
  152         mp = mach_port_get();
  153         mp->mp_datatype = MACH_MP_SEMAPHORE;
  154         mp->mp_data = (void *)ms;
  155 
  156         mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
  157 
  158         *msglen = sizeof(*rep);
  159         mach_set_header(rep, req, *msglen);
  160         mach_add_port_desc(rep, mr->mr_name);
  161         mach_set_trailer(rep, *msglen);
  162 
  163         return 0;
  164 }
  165 
  166 int
  167 mach_semaphore_destroy(struct mach_trap_args *args)
  168 {
  169         mach_semaphore_destroy_request_t *req = args->smsg;
  170         mach_semaphore_destroy_reply_t *rep = args->rmsg;
  171         struct lwp *l = args->l;
  172         size_t *msglen = args->rsize;
  173         struct mach_semaphore *ms;
  174         struct mach_right *mr;
  175         mach_port_t mn;
  176 
  177         mn = req->req_sem.name;
  178         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
  179                 return mach_msg_error(args, EPERM);
  180 
  181         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  182                 return mach_msg_error(args, EINVAL);
  183 
  184         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  185         mach_semaphore_put(ms);
  186         mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
  187 
  188         *msglen = sizeof(*rep);
  189         mach_set_header(rep, req, *msglen);
  190 
  191         rep->rep_retval = 0;
  192 
  193         mach_set_trailer(rep, *msglen);
  194 
  195         return 0;
  196 }
  197 
  198 void
  199 mach_semaphore_init(void)
  200 {
  201         LIST_INIT(&mach_semaphore_list);
  202         rw_init(&mach_semaphore_list_lock);
  203         pool_init(&mach_semaphore_list_pool, sizeof (struct mach_semaphore),
  204             0, 0, 0, "mach_sem_pool", NULL, IPL_NONE);
  205         pool_init(&mach_waiting_lwp_pool, sizeof (struct mach_waiting_lwp),
  206             0, 0, 0, "mach_waitp_pool", NULL, IPL_NONE);
  207 
  208         return;
  209 }
  210 
  211 static struct mach_semaphore *
  212 mach_semaphore_get(int value, int policy)
  213 {
  214         struct mach_semaphore *ms;
  215 
  216         ms = (struct mach_semaphore *)pool_get(&mach_semaphore_list_pool,
  217             M_WAITOK);
  218         ms->ms_value = value;
  219         ms->ms_policy = policy;
  220         TAILQ_INIT(&ms->ms_waiting);
  221         rw_init(&ms->ms_lock);
  222 
  223         rw_enter(&mach_semaphore_list_lock, RW_WRITER);
  224         LIST_INSERT_HEAD(&mach_semaphore_list, ms, ms_list);
  225         rw_exit(&mach_semaphore_list_lock);
  226 
  227         return ms;
  228 }
  229 
  230 static void
  231 mach_semaphore_put(struct mach_semaphore *ms)
  232 {
  233         struct mach_waiting_lwp *mwl;
  234 
  235         rw_enter(&ms->ms_lock, RW_WRITER);
  236         while ((mwl = TAILQ_FIRST(&ms->ms_waiting)) != NULL)
  237                 mach_waiting_lwp_put(mwl, ms, 0);
  238         rw_exit(&ms->ms_lock);
  239         rw_destroy(&ms->ms_lock);
  240 
  241         rw_enter(&mach_semaphore_list_lock, RW_WRITER);
  242         LIST_REMOVE(ms, ms_list);
  243         rw_exit(&mach_semaphore_list_lock);
  244 
  245         pool_put(&mach_semaphore_list_pool, ms);
  246 
  247         return;
  248 }
  249 
  250 static struct mach_waiting_lwp *
  251 mach_waiting_lwp_get(struct lwp *l, struct mach_semaphore *ms)
  252 {
  253         struct mach_waiting_lwp *mwl;
  254 
  255         mwl = (struct mach_waiting_lwp *)pool_get(&mach_waiting_lwp_pool,
  256             M_WAITOK);
  257         mwl->mwl_l = l;
  258 
  259         rw_enter(&ms->ms_lock, RW_WRITER);
  260         TAILQ_INSERT_TAIL(&ms->ms_waiting, mwl, mwl_list);
  261         rw_exit(&ms->ms_lock);
  262 
  263         return mwl;
  264 }
  265 
  266 static void
  267 mach_waiting_lwp_put(struct mach_waiting_lwp *mwl, struct mach_semaphore *ms, int locked)
  268 {
  269         if (!locked)
  270                 rw_enter(&ms->ms_lock, RW_WRITER);
  271         TAILQ_REMOVE(&ms->ms_waiting, mwl, mwl_list);
  272         if (!locked)
  273                 rw_exit(&ms->ms_lock);
  274         pool_put(&mach_waiting_lwp_pool, mwl);
  275 
  276         return;
  277 }
  278 
  279 /*
  280  * Cleanup after process exit. Need improvements, there
  281  * can be some memory leaks here.
  282  */
  283 void
  284 mach_semaphore_cleanup(struct lwp *l)
  285 {
  286         struct mach_semaphore *ms;
  287         struct mach_waiting_lwp *mwl;
  288 
  289         rw_enter(&mach_semaphore_list_lock, RW_READER);
  290         LIST_FOREACH(ms, &mach_semaphore_list, ms_list) {
  291                 rw_enter(&ms->ms_lock, RW_WRITER);
  292                 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
  293                         if (mwl->mwl_l == l) {
  294                                 mach_waiting_lwp_put(mwl, ms, 0);
  295                                 ms->ms_value++;
  296                                 if (ms->ms_value >= 0)
  297                                         wakeup(TAILQ_FIRST(&ms->ms_waiting));
  298                         }
  299                 rw_exit(&ms->ms_lock);
  300         }
  301         rw_exit(&mach_semaphore_list_lock);
  302 
  303         return;
  304 }
  305 
  306 int
  307 mach_sys_semaphore_wait_signal_trap(struct lwp *l, const struct mach_sys_semaphore_wait_signal_trap_args *uap, register_t *retval)
  308 {
  309         /* {
  310                 syscallarg(mach_port_name_t) wait_name;
  311                 syscallarg(mach_port_name_t) signal_name;
  312         } */
  313         struct mach_sys_semaphore_wait_trap_args cupwait;
  314         struct mach_sys_semaphore_signal_trap_args cupsig;
  315         int error;
  316 
  317         SCARG(&cupsig, signal_name) = SCARG(uap, signal_name);
  318         if ((error = mach_sys_semaphore_signal_trap(l, &cupsig, retval)) != 0)
  319                 return error;
  320 
  321         SCARG(&cupwait, wait_name) = SCARG(uap, wait_name);
  322         if ((error = mach_sys_semaphore_wait_trap(l, &cupwait, retval)) != 0)
  323                 return error;
  324 
  325         return 0;
  326 }
  327 
  328 
  329 int
  330 mach_sys_semaphore_signal_thread_trap(struct lwp *l, const struct mach_sys_semaphore_signal_thread_trap_args *uap, register_t *retval)
  331 {
  332         /* {
  333                 syscallarg(mach_port_name_t) signal_name;
  334                 syscallarg(mach_port_name_t) thread;
  335         } */
  336         struct mach_right *mr;
  337         struct mach_semaphore *ms;
  338         mach_port_t mn;
  339         struct mach_waiting_lwp *mwl;
  340         int unblocked = 0;
  341 
  342         /*
  343          * Get the semaphore
  344          */
  345         mn = SCARG(uap, signal_name);
  346         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  347                 return EINVAL;
  348 
  349         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  350                 return EINVAL;
  351 
  352         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  353 
  354         /*
  355          * Get the thread, and check that it is waiting for our semaphore
  356          * If no thread was supplied, pick up the first one.
  357          */
  358         mn = SCARG(uap, thread);
  359         if (mn != 0) {
  360                 if ((mr = mach_right_check(mn, l,
  361                     MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  362                         return EINVAL;
  363 
  364                 if (mr->mr_port->mp_datatype != MACH_MP_LWP)
  365                         return EINVAL;
  366 
  367                 rw_enter(&ms->ms_lock, RW_WRITER);
  368                 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
  369                         if (mwl->mwl_l == (struct lwp *)mr->mr_port->mp_data)
  370                                 break;
  371         } else {
  372                 rw_enter(&ms->ms_lock, RW_WRITER);
  373                 mwl = TAILQ_FIRST(&ms->ms_waiting);
  374         }
  375 
  376         /*
  377          * No thread was awaiting for this semaphore,
  378          * exit without touching the semaphore.
  379          */
  380         if (mwl == NULL) {
  381                 rw_exit(&ms->ms_lock);
  382                 return 0; /* Should be KERN_NOT_WAITING */
  383         }
  384 
  385         ms->ms_value++;
  386         if (ms->ms_value >= 0)
  387                 unblocked = 1;
  388         rw_exit(&ms->ms_lock);
  389 
  390         if (unblocked != 0)
  391                 wakeup(mwl);
  392 
  393         return 0;
  394 }
  395 
  396 
  397 int
  398 mach_sys_semaphore_signal_all_trap(struct lwp *l, const struct mach_sys_semaphore_signal_all_trap_args *uap, register_t *retval)
  399 {
  400         /* {
  401                 syscallarg(mach_port_name_t) signal_name;
  402         } */
  403         struct mach_right *mr;
  404         struct mach_semaphore *ms;
  405         mach_port_t mn;
  406         struct mach_waiting_lwp *mwl;
  407         int unblocked = 0;
  408 
  409         /*
  410          * Get the semaphore
  411          */
  412         mn = SCARG(uap, signal_name);
  413         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  414                 return EINVAL;
  415 
  416         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  417                 return EINVAL;
  418 
  419         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  420 
  421         rw_enter(&ms->ms_lock, RW_WRITER);
  422         ms->ms_value++;
  423         if (ms->ms_value >= 0)
  424                 unblocked = 1;
  425 
  426         /*
  427          * Wakeup all threads sleeping on it.
  428          */
  429         if (unblocked != 0)
  430                 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
  431                         wakeup(mwl);
  432 
  433         rw_exit(&ms->ms_lock);
  434 
  435         return 0;
  436 }
  437 
  438 

Cache object: 4aa59136a428f7d5b01baee3dcab588c


[ 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.