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

Cache object: fbd91450c882c3caf81f08f3d91130de


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