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.14 2006/11/16 01:32:44 christos 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.14 2006/11/16 01:32:44 christos 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(struct lwp *l, void *v,
   76     register_t *retval)
   77 {
   78         struct mach_sys_semaphore_wait_trap_args /* {
   79                 syscallarg(mach_port_name_t) wait_name;
   80         } */ *uap = v;
   81         struct mach_semaphore *ms;
   82         struct mach_waiting_lwp *mwl;
   83         struct mach_right *mr;
   84         mach_port_t mn;
   85         int blocked = 0;
   86 
   87         mn = SCARG(uap, wait_name);
   88         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
   89                 return EPERM;
   90 
   91         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
   92                 return EINVAL;
   93 
   94         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
   95 
   96         lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
   97         ms->ms_value--;
   98         if (ms->ms_value < 0)
   99                 blocked = 1;
  100         lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  101 
  102         if (blocked != 0) {
  103                 mwl = mach_waiting_lwp_get(l, ms);
  104                 while (ms->ms_value < 0)
  105                         tsleep(mwl, PZERO|PCATCH, "sem_wait", 0);
  106                 mach_waiting_lwp_put(mwl, ms, 0);
  107         }
  108         return 0;
  109 }
  110 
  111 int
  112 mach_sys_semaphore_signal_trap(struct lwp *l, void *v,
  113     register_t *retval)
  114 {
  115         struct mach_sys_semaphore_signal_trap_args /* {
  116                 syscallarg(mach_port_name_t) signal_name;
  117         } */ *uap = v;
  118         struct mach_semaphore *ms;
  119         struct mach_waiting_lwp *mwl;
  120         struct mach_right *mr;
  121         mach_port_t mn;
  122         int unblocked = 0;
  123 
  124         mn = SCARG(uap, signal_name);
  125         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
  126                 return EPERM;
  127 
  128         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  129                 return EINVAL;
  130 
  131         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  132 
  133         lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
  134         ms->ms_value++;
  135         if (ms->ms_value >= 0)
  136                 unblocked = 1;
  137         lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  138 
  139         if (unblocked != 0) {
  140                 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
  141                 mwl = TAILQ_FIRST(&ms->ms_waiting);
  142                 wakeup(mwl);
  143                 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  144         }
  145         return 0;
  146 }
  147 
  148 int
  149 mach_semaphore_create(args)
  150         struct mach_trap_args *args;
  151 {
  152         mach_semaphore_create_request_t *req = args->smsg;
  153         mach_semaphore_create_reply_t *rep = args->rmsg;
  154         size_t *msglen = args->rsize;
  155         struct lwp *l = args->l;
  156         struct mach_semaphore *ms;
  157         struct mach_port *mp;
  158         struct mach_right *mr;
  159 
  160         ms = mach_semaphore_get(req->req_value, req->req_policy);
  161 
  162         mp = mach_port_get();
  163         mp->mp_datatype = MACH_MP_SEMAPHORE;
  164         mp->mp_data = (void *)ms;
  165 
  166         mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
  167 
  168         *msglen = sizeof(*rep);
  169         mach_set_header(rep, req, *msglen);
  170         mach_add_port_desc(rep, mr->mr_name);
  171         mach_set_trailer(rep, *msglen);
  172 
  173         return 0;
  174 }
  175 
  176 int
  177 mach_semaphore_destroy(args)
  178         struct mach_trap_args *args;
  179 {
  180         mach_semaphore_destroy_request_t *req = args->smsg;
  181         mach_semaphore_destroy_reply_t *rep = args->rmsg;
  182         struct lwp *l = args->l;
  183         size_t *msglen = args->rsize;
  184         struct mach_semaphore *ms;
  185         struct mach_right *mr;
  186         mach_port_t mn;
  187 
  188         mn = req->req_sem.name;
  189         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
  190                 return mach_msg_error(args, EPERM);
  191 
  192         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  193                 return mach_msg_error(args, EINVAL);
  194 
  195         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  196         mach_semaphore_put(ms);
  197         mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
  198 
  199         *msglen = sizeof(*rep);
  200         mach_set_header(rep, req, *msglen);
  201 
  202         rep->rep_retval = 0;
  203 
  204         mach_set_trailer(rep, *msglen);
  205 
  206         return 0;
  207 }
  208 
  209 void
  210 mach_semaphore_init(void)
  211 {
  212         LIST_INIT(&mach_semaphore_list);
  213         lockinit(&mach_semaphore_list_lock, PZERO|PCATCH, "mach_sem", 0, 0);
  214         pool_init(&mach_semaphore_list_pool, sizeof (struct mach_semaphore),
  215             0, 0, 0, "mach_sem_pool", NULL);
  216         pool_init(&mach_waiting_lwp_pool, sizeof (struct mach_waiting_lwp),
  217             0, 0, 0, "mach_waitp_pool", NULL);
  218 
  219         return;
  220 }
  221 
  222 static struct mach_semaphore *
  223 mach_semaphore_get(value, policy)
  224         int value;
  225         int policy;
  226 {
  227         struct mach_semaphore *ms;
  228 
  229         ms = (struct mach_semaphore *)pool_get(&mach_semaphore_list_pool,
  230             M_WAITOK);
  231         ms->ms_value = value;
  232         ms->ms_policy = policy;
  233         TAILQ_INIT(&ms->ms_waiting);
  234         lockinit(&ms->ms_lock, PZERO|PCATCH, "mach_waitp", 0, 0);
  235 
  236         lockmgr(&mach_semaphore_list_lock, LK_EXCLUSIVE, NULL);
  237         LIST_INSERT_HEAD(&mach_semaphore_list, ms, ms_list);
  238         lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
  239 
  240         return ms;
  241 }
  242 
  243 static void
  244 mach_semaphore_put(ms)
  245         struct mach_semaphore *ms;
  246 {
  247         struct mach_waiting_lwp *mwl;
  248 
  249         lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
  250         while ((mwl = TAILQ_FIRST(&ms->ms_waiting)) != NULL)
  251                 mach_waiting_lwp_put(mwl, ms, 0);
  252         lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  253         lockmgr(&ms->ms_lock, LK_DRAIN, NULL);
  254 
  255         lockmgr(&mach_semaphore_list_lock, LK_EXCLUSIVE, NULL);
  256         LIST_REMOVE(ms, ms_list);
  257         lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
  258 
  259         pool_put(&mach_semaphore_list_pool, ms);
  260 
  261         return;
  262 }
  263 
  264 static struct mach_waiting_lwp *
  265 mach_waiting_lwp_get(l, ms)
  266         struct lwp *l;
  267         struct mach_semaphore *ms;
  268 {
  269         struct mach_waiting_lwp *mwl;
  270 
  271         mwl = (struct mach_waiting_lwp *)pool_get(&mach_waiting_lwp_pool,
  272             M_WAITOK);
  273         mwl->mwl_l = l;
  274 
  275         lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
  276         TAILQ_INSERT_TAIL(&ms->ms_waiting, mwl, mwl_list);
  277         lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  278 
  279         return mwl;
  280 }
  281 
  282 static void
  283 mach_waiting_lwp_put(mwl, ms, locked)
  284         struct mach_waiting_lwp *mwl;
  285         struct mach_semaphore *ms;
  286         int locked;
  287 {
  288         if (!locked)
  289                 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
  290         TAILQ_REMOVE(&ms->ms_waiting, mwl, mwl_list);
  291         if (!locked)
  292                 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  293         pool_put(&mach_waiting_lwp_pool, mwl);
  294 
  295         return;
  296 }
  297 
  298 /*
  299  * Cleanup after process exit. Need improvements, there
  300  * can be some memory leaks here.
  301  */
  302 void
  303 mach_semaphore_cleanup(l)
  304         struct lwp *l;
  305 {
  306         struct mach_semaphore *ms;
  307         struct mach_waiting_lwp *mwl;
  308 
  309         lockmgr(&mach_semaphore_list_lock, LK_SHARED, NULL);
  310         LIST_FOREACH(ms, &mach_semaphore_list, ms_list) {
  311                 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
  312                 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
  313                         if (mwl->mwl_l == l) {
  314                                 lockmgr(&ms->ms_lock, LK_UPGRADE, NULL);
  315                                 mach_waiting_lwp_put(mwl, ms, 0);
  316                                 ms->ms_value++;
  317                                 if (ms->ms_value >= 0)
  318                                         wakeup(TAILQ_FIRST(&ms->ms_waiting));
  319                         }
  320                 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  321         }
  322         lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
  323 
  324         return;
  325 }
  326 
  327 int
  328 mach_sys_semaphore_wait_signal_trap(l, v, retval)
  329         struct lwp *l;
  330         void *v;
  331         register_t *retval;
  332 {
  333         struct mach_sys_semaphore_wait_signal_trap_args /* {
  334                 syscallarg(mach_port_name_t) wait_name;
  335                 syscallarg(mach_port_name_t) signal_name;
  336         } */ *uap = v;
  337         struct mach_sys_semaphore_wait_trap_args cupwait;
  338         struct mach_sys_semaphore_signal_trap_args cupsig;
  339         int error;
  340 
  341         SCARG(&cupsig, signal_name) = SCARG(uap, signal_name);
  342         if ((error = mach_sys_semaphore_signal_trap(l, &cupsig, retval)) != 0)
  343                 return error;
  344 
  345         SCARG(&cupwait, wait_name) = SCARG(uap, wait_name);
  346         if ((error = mach_sys_semaphore_wait_trap(l, &cupwait, retval)) != 0)
  347                 return error;
  348 
  349         return 0;
  350 }
  351 
  352 
  353 int
  354 mach_sys_semaphore_signal_thread_trap(struct lwp *l, void *v,
  355     register_t *retval)
  356 {
  357         struct mach_sys_semaphore_signal_thread_trap_args /* {
  358                 syscallarg(mach_port_name_t) signal_name;
  359                 syscallarg(mach_port_name_t) thread;
  360         } */ *uap = v;
  361         struct mach_right *mr;
  362         struct mach_semaphore *ms;
  363         mach_port_t mn;
  364         struct mach_waiting_lwp *mwl;
  365         int unblocked = 0;
  366 
  367         /*
  368          * Get the semaphore
  369          */
  370         mn = SCARG(uap, signal_name);
  371         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  372                 return EINVAL;
  373 
  374         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  375                 return EINVAL;
  376 
  377         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  378 
  379         /*
  380          * Get the thread, and check that it is waiting for our semaphore
  381          * If no thread was supplied, pick up the first one.
  382          */
  383         mn = SCARG(uap, thread);
  384         if (mn != 0) {
  385                 if ((mr = mach_right_check(mn, l,
  386                     MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  387                         return EINVAL;
  388 
  389                 if (mr->mr_port->mp_datatype != MACH_MP_LWP)
  390                         return EINVAL;
  391 
  392                 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
  393                 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
  394                         if (mwl->mwl_l == (struct lwp *)mr->mr_port->mp_data)
  395                                 break;
  396         } else {
  397                 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
  398                 mwl = TAILQ_FIRST(&ms->ms_waiting);
  399         }
  400 
  401         /*
  402          * No thread was awaiting for this semaphore,
  403          * exit without touching the semaphore.
  404          */
  405         if (mwl == NULL) {
  406                 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  407                 return 0; /* Should be KERN_NOT_WAITING */
  408         }
  409 
  410         lockmgr(&ms->ms_lock, LK_UPGRADE, NULL);
  411         ms->ms_value++;
  412         if (ms->ms_value >= 0)
  413                 unblocked = 1;
  414         lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  415 
  416         if (unblocked != 0)
  417                 wakeup(mwl);
  418 
  419         return 0;
  420 }
  421 
  422 
  423 int
  424 mach_sys_semaphore_signal_all_trap(struct lwp *l, void *v,
  425     register_t *retval)
  426 {
  427         struct mach_sys_semaphore_signal_all_trap_args /* {
  428                 syscallarg(mach_port_name_t) signal_name;
  429         } */ *uap = v;
  430         struct mach_right *mr;
  431         struct mach_semaphore *ms;
  432         mach_port_t mn;
  433         struct mach_waiting_lwp *mwl;
  434         int unblocked = 0;
  435 
  436         /*
  437          * Get the semaphore
  438          */
  439         mn = SCARG(uap, signal_name);
  440         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  441                 return EINVAL;
  442 
  443         if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
  444                 return EINVAL;
  445 
  446         ms = (struct mach_semaphore *)mr->mr_port->mp_data;
  447 
  448         lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
  449         ms->ms_value++;
  450         if (ms->ms_value >= 0)
  451                 unblocked = 1;
  452         lockmgr(&ms->ms_lock, LK_DOWNGRADE, NULL);
  453 
  454         /*
  455          * Wakeup all threads sleeping on it.
  456          */
  457         if (unblocked != 0)
  458                 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
  459                         wakeup(mwl);
  460 
  461         lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
  462 
  463         return 0;
  464 }
  465 
  466 

Cache object: b6dc4e05328289e30ba3a677eb244752


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