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/uipc_sem.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: uipc_sem.c,v 1.10 2005/02/26 21:34:55 perry Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of Wasabi Systems, Inc.
    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 /*
   40  * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
   41  * All rights reserved.
   42  *
   43  * Redistribution and use in source and binary forms, with or without
   44  * modification, are permitted provided that the following conditions
   45  * are met:
   46  * 1. Redistributions of source code must retain the above copyright
   47  *    notice, this list of conditions and the following disclaimer.
   48  * 2. Redistributions in binary form must reproduce the above copyright
   49  *    notice, this list of conditions and the following disclaimer in the
   50  *    documentation and/or other materials provided with the distribution.
   51  *
   52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   62  * SUCH DAMAGE.
   63  */
   64 
   65 #include <sys/cdefs.h>
   66 __KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.10 2005/02/26 21:34:55 perry Exp $");
   67 
   68 #include "opt_posix.h"
   69 
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 #include <sys/kernel.h>
   73 #include <sys/proc.h>
   74 #include <sys/lock.h>
   75 #include <sys/ksem.h>
   76 #include <sys/sa.h>
   77 #include <sys/syscall.h>
   78 #include <sys/stat.h>
   79 #include <sys/malloc.h>
   80 #include <sys/fcntl.h>
   81 
   82 #include <sys/mount.h>
   83 
   84 #include <sys/syscallargs.h>
   85 
   86 #ifndef SEM_MAX
   87 #define SEM_MAX 30
   88 #endif
   89 
   90 #define SEM_MAX_NAMELEN 14
   91 #define SEM_VALUE_MAX (~0U)
   92 
   93 #define SEM_TO_ID(x)    ((intptr_t)(x))
   94 
   95 MALLOC_DEFINE(M_SEM, "p1003_1b_sem", "p1003_1b semaphores");
   96 
   97 /*
   98  * Note: to read the ks_name member, you need either the ks_interlock
   99  * or the ksem_slock.  To write the ks_name member, you need both.  Make
  100  * sure the order is ksem_slock -> ks_interlock.
  101  */
  102 struct ksem {
  103         LIST_ENTRY(ksem) ks_entry;      /* global list entry */
  104         struct simplelock ks_interlock; /* lock on this ksem */
  105         char *ks_name;                  /* if named, this is the name */
  106         unsigned int ks_ref;            /* number of references */
  107         mode_t ks_mode;                 /* protection bits */
  108         uid_t ks_uid;                   /* creator uid */
  109         gid_t ks_gid;                   /* creator gid */
  110         unsigned int ks_value;          /* current value */
  111         unsigned int ks_waiters;        /* number of waiters */
  112 };
  113 
  114 struct ksem_ref {
  115         LIST_ENTRY(ksem_ref) ksr_list;
  116         struct ksem *ksr_ksem;
  117 };
  118 
  119 struct ksem_proc {
  120         struct lock kp_lock;
  121         LIST_HEAD(, ksem_ref) kp_ksems;
  122 };
  123 
  124 /*
  125  * ksem_slock protects ksem_head and nsems.  Only named semaphores go
  126  * onto ksem_head.
  127  */
  128 static struct simplelock ksem_slock;
  129 static LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
  130 static int nsems = 0;
  131 
  132 static void
  133 ksem_free(struct ksem *ks)
  134 {
  135 
  136         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  137         /*
  138          * If the ksem is anonymous (or has been unlinked), then
  139          * this is the end if its life.
  140          */
  141         if (ks->ks_name == NULL) {
  142                 simple_unlock(&ks->ks_interlock);
  143                 free(ks, M_SEM);
  144 
  145                 simple_lock(&ksem_slock);
  146                 nsems--;
  147                 simple_unlock(&ksem_slock);
  148                 return;
  149         }
  150         simple_unlock(&ks->ks_interlock);
  151 }
  152 
  153 static __inline void
  154 ksem_addref(struct ksem *ks)
  155 {
  156 
  157         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  158         ks->ks_ref++;
  159         KASSERT(ks->ks_ref != 0);       /* XXX KDASSERT */
  160 }
  161 
  162 static __inline void
  163 ksem_delref(struct ksem *ks)
  164 {
  165 
  166         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  167         KASSERT(ks->ks_ref != 0);       /* XXX KDASSERT */
  168         if (--ks->ks_ref == 0) {
  169                 ksem_free(ks);
  170                 return;
  171         }
  172         simple_unlock(&ks->ks_interlock);
  173 }
  174 
  175 static struct ksem_proc *
  176 ksem_proc_alloc(void)
  177 {
  178         struct ksem_proc *kp;
  179 
  180         kp = malloc(sizeof(*kp), M_SEM, M_WAITOK);
  181         lockinit(&kp->kp_lock, PWAIT, "ksproc", 0, 0);
  182         LIST_INIT(&kp->kp_ksems);
  183 
  184         return (kp);
  185 }
  186 
  187 static void
  188 ksem_add_proc(struct proc *p, struct ksem *ks)
  189 {
  190         struct ksem_proc *kp;
  191         struct ksem_ref *ksr;
  192 
  193         if (p->p_ksems == NULL) {
  194                 kp = ksem_proc_alloc();
  195                 p->p_ksems = kp;
  196         } else
  197                 kp = p->p_ksems;
  198 
  199         ksr = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
  200         ksr->ksr_ksem = ks;
  201 
  202         lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
  203         LIST_INSERT_HEAD(&kp->kp_ksems, ksr, ksr_list);
  204         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  205 }
  206 
  207 /* We MUST have a write lock on the ksem_proc list! */
  208 static struct ksem_ref *
  209 ksem_drop_proc(struct ksem_proc *kp, struct ksem *ks)
  210 {
  211         struct ksem_ref *ksr;
  212 
  213         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  214         LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
  215                 if (ksr->ksr_ksem == ks) {
  216                         ksem_delref(ks);
  217                         LIST_REMOVE(ksr, ksr_list);
  218                         return (ksr);
  219                 }
  220         }
  221 #ifdef DIAGNOSTIC
  222         panic("ksem_drop_proc: ksem_proc %p ksem %p", kp, ks);
  223 #endif
  224         return (NULL);
  225 }
  226 
  227 static int
  228 ksem_perm(struct proc *p, struct ksem *ks)
  229 {
  230         struct ucred *uc;
  231 
  232         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  233         uc = p->p_ucred;
  234         if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
  235             (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
  236             (ks->ks_mode & S_IWOTH) != 0 || suser(uc, &p->p_acflag) == 0)
  237                 return (0);
  238         return (EPERM);
  239 }
  240 
  241 static struct ksem *
  242 ksem_lookup_byname(const char *name)
  243 {
  244         struct ksem *ks;
  245 
  246         LOCK_ASSERT(simple_lock_held(&ksem_slock));
  247         LIST_FOREACH(ks, &ksem_head, ks_entry) {
  248                 if (strcmp(ks->ks_name, name) == 0) {
  249                         simple_lock(&ks->ks_interlock);
  250                         return (ks);
  251                 }
  252         }
  253         return (NULL);
  254 }
  255 
  256 static int
  257 ksem_create(struct proc *p, const char *name, struct ksem **ksret,
  258     mode_t mode, unsigned int value)
  259 {
  260         struct ksem *ret;
  261         struct ucred *uc;
  262         size_t len;
  263 
  264         uc = p->p_ucred;
  265         if (value > SEM_VALUE_MAX)
  266                 return (EINVAL);
  267         ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
  268         if (name != NULL) {
  269                 len = strlen(name);
  270                 if (len > SEM_MAX_NAMELEN) {
  271                         free(ret, M_SEM);
  272                         return (ENAMETOOLONG);
  273                 }
  274                 /* name must start with a '/' but not contain one. */
  275                 if (*name != '/' || len < 2 || strchr(name + 1, '/') != NULL) {
  276                         free(ret, M_SEM);
  277                         return (EINVAL);
  278                 }
  279                 ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
  280                 strlcpy(ret->ks_name, name, len + 1);
  281         } else
  282                 ret->ks_name = NULL;
  283         ret->ks_mode = mode;
  284         ret->ks_value = value;
  285         ret->ks_ref = 1;
  286         ret->ks_waiters = 0;
  287         ret->ks_uid = uc->cr_uid;
  288         ret->ks_gid = uc->cr_gid;
  289         simple_lock_init(&ret->ks_interlock);
  290 
  291         simple_lock(&ksem_slock);
  292         if (nsems >= SEM_MAX) {
  293                 simple_unlock(&ksem_slock);
  294                 if (ret->ks_name != NULL)
  295                         free(ret->ks_name, M_SEM);
  296                 free(ret, M_SEM);
  297                 return (ENFILE);
  298         }
  299         nsems++;
  300         simple_unlock(&ksem_slock);
  301 
  302         *ksret = ret;
  303         return (0);
  304 }
  305 
  306 int
  307 sys__ksem_init(struct lwp *l, void *v, register_t *retval)
  308 {
  309         struct sys__ksem_init_args /* {
  310                 unsigned int value;
  311                 semid_t *idp;
  312         } */ *uap = v;
  313         struct ksem *ks;
  314         semid_t id;
  315         int error;
  316 
  317         /* Note the mode does not matter for anonymous semaphores. */
  318         error = ksem_create(l->l_proc, NULL, &ks, 0, SCARG(uap, value));
  319         if (error)
  320                 return (error);
  321         id = SEM_TO_ID(ks);
  322         error = copyout(&id, SCARG(uap, idp), sizeof(id));
  323         if (error) {
  324                 simple_lock(&ks->ks_interlock);
  325                 ksem_delref(ks);
  326                 return (error);
  327         }
  328 
  329         ksem_add_proc(l->l_proc, ks);
  330 
  331         return (0);
  332 }
  333 
  334 int
  335 sys__ksem_open(struct lwp *l, void *v, register_t *retval)
  336 {
  337         struct sys__ksem_open_args /* {
  338                 const char *name;
  339                 int oflag;
  340                 mode_t mode;
  341                 unsigned int value;
  342                 semid_t *idp;
  343         } */ *uap = v;
  344         char name[SEM_MAX_NAMELEN + 1];
  345         size_t done;
  346         int error;
  347         struct ksem *ksnew, *ks;
  348         semid_t id;
  349 
  350         error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
  351         if (error)
  352                 return (error);
  353 
  354         ksnew = NULL;
  355         simple_lock(&ksem_slock);
  356         ks = ksem_lookup_byname(name);
  357 
  358         /* Found one? */
  359         if (ks != NULL) {
  360                 /* Check for exclusive create. */
  361                 if (SCARG(uap, oflag) & O_EXCL) {
  362                         simple_unlock(&ks->ks_interlock);
  363                         simple_unlock(&ksem_slock);
  364                         return (EEXIST);
  365                 }
  366  found_one:
  367                 /*
  368                  * Verify permissions.  If we can access it, add
  369                  * this process's reference.
  370                  */
  371                 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  372                 error = ksem_perm(l->l_proc, ks);
  373                 if (error == 0)
  374                         ksem_addref(ks);
  375                 simple_unlock(&ks->ks_interlock);
  376                 simple_unlock(&ksem_slock);
  377                 if (error)
  378                         return (error);
  379 
  380                 id = SEM_TO_ID(ks);
  381                 error = copyout(&id, SCARG(uap, idp), sizeof(id));
  382                 if (error) {
  383                         simple_lock(&ks->ks_interlock);
  384                         ksem_delref(ks);
  385                         return (error);
  386                 }
  387 
  388                 ksem_add_proc(l->l_proc, ks);
  389 
  390                 return (0);
  391         }
  392 
  393         /*
  394          * didn't ask for creation? error.
  395          */
  396         if ((SCARG(uap, oflag) & O_CREAT) == 0) {
  397                 simple_unlock(&ksem_slock);
  398                 return (ENOENT);
  399         }
  400 
  401         /*
  402          * We may block during creation, so drop the lock.
  403          */
  404         simple_unlock(&ksem_slock);
  405         error = ksem_create(l->l_proc, name, &ksnew, SCARG(uap, mode),
  406             SCARG(uap, value));
  407         if (error != 0)
  408                 return (error);
  409 
  410         id = SEM_TO_ID(ksnew);
  411         error = copyout(&id, SCARG(uap, idp), sizeof(id));
  412         if (error) {
  413                 free(ksnew->ks_name, M_SEM);
  414                 ksnew->ks_name = NULL;
  415 
  416                 simple_lock(&ksnew->ks_interlock);
  417                 ksem_delref(ksnew);
  418                 return (error);
  419         }
  420 
  421         /*
  422          * We need to make sure we haven't lost a race while
  423          * allocating during creation.
  424          */
  425         simple_lock(&ksem_slock);
  426         if ((ks = ksem_lookup_byname(name)) != NULL) {
  427                 if (SCARG(uap, oflag) & O_EXCL) {
  428                         simple_unlock(&ks->ks_interlock);
  429                         simple_unlock(&ksem_slock);
  430 
  431                         free(ksnew->ks_name, M_SEM);
  432                         ksnew->ks_name = NULL;
  433 
  434                         simple_lock(&ksnew->ks_interlock);
  435                         ksem_delref(ksnew);
  436                         return (EEXIST);
  437                 }
  438                 goto found_one;
  439         } else {
  440                 /* ksnew already has its initial reference. */
  441                 LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
  442                 simple_unlock(&ksem_slock);
  443 
  444                 ksem_add_proc(l->l_proc, ksnew);
  445         }
  446         return (error);
  447 }
  448 
  449 /* We must have a read lock on the ksem_proc list! */
  450 static struct ksem *
  451 ksem_lookup_proc(struct ksem_proc *kp, semid_t id)
  452 {
  453         struct ksem_ref *ksr;
  454 
  455         LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
  456                 if (id == (semid_t) ksr->ksr_ksem) {
  457                         simple_lock(&ksr->ksr_ksem->ks_interlock);
  458                         return (ksr->ksr_ksem);
  459                 }
  460         }
  461 
  462         return (NULL);
  463 }
  464 
  465 int
  466 sys__ksem_unlink(struct lwp *l, void *v, register_t *retval)
  467 {
  468         struct sys__ksem_unlink_args /* {
  469                 const char *name;
  470         } */ *uap = v;
  471         char name[SEM_MAX_NAMELEN + 1], *cp;
  472         size_t done;
  473         struct ksem *ks;
  474         int error;
  475 
  476         error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
  477         if (error)
  478                 return error;
  479 
  480         simple_lock(&ksem_slock);
  481         ks = ksem_lookup_byname(name);
  482         if (ks == NULL) {
  483                 simple_unlock(&ksem_slock);
  484                 return (ENOENT);
  485         }
  486 
  487         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  488 
  489         LIST_REMOVE(ks, ks_entry);
  490         cp = ks->ks_name;
  491         ks->ks_name = NULL;
  492 
  493         simple_unlock(&ksem_slock);
  494 
  495         if (ks->ks_ref == 0)
  496                 ksem_free(ks);
  497         else
  498                 simple_unlock(&ks->ks_interlock);
  499 
  500         free(cp, M_SEM);
  501 
  502         return (0);
  503 }
  504 
  505 int
  506 sys__ksem_close(struct lwp *l, void *v, register_t *retval)
  507 {
  508         struct sys__ksem_close_args /* {
  509                 semid_t id;
  510         } */ *uap = v;
  511         struct ksem_proc *kp;
  512         struct ksem_ref *ksr;
  513         struct ksem *ks;
  514 
  515         if ((kp = l->l_proc->p_ksems) == NULL)
  516                 return (EINVAL);
  517 
  518         lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
  519 
  520         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  521         if (ks == NULL) {
  522                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  523                 return (EINVAL);
  524         }
  525 
  526         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  527         if (ks->ks_name == NULL) {
  528                 simple_unlock(&ks->ks_interlock);
  529                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  530                 return (EINVAL);
  531         }
  532 
  533         ksr = ksem_drop_proc(kp, ks);
  534         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  535         free(ksr, M_SEM);
  536 
  537         return (0);
  538 }
  539 
  540 int
  541 sys__ksem_post(struct lwp *l, void *v, register_t *retval)
  542 {
  543         struct sys__ksem_post_args /* {
  544                 semid_t id;
  545         } */ *uap = v;
  546         struct ksem_proc *kp;
  547         struct ksem *ks;
  548         int error;
  549 
  550         if ((kp = l->l_proc->p_ksems) == NULL)
  551                 return (EINVAL);
  552 
  553         lockmgr(&kp->kp_lock, LK_SHARED, NULL);
  554         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  555         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  556         if (ks == NULL)
  557                 return (EINVAL);
  558 
  559         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  560         if (ks->ks_value == SEM_VALUE_MAX) {
  561                 error = EOVERFLOW;
  562                 goto out;
  563         }
  564         ++ks->ks_value;
  565         if (ks->ks_waiters)
  566                 wakeup(ks);
  567         error = 0;
  568  out:
  569         simple_unlock(&ks->ks_interlock);
  570         return (error);
  571 }
  572 
  573 static int
  574 ksem_wait(struct lwp *l, semid_t id, int tryflag)
  575 {
  576         struct ksem_proc *kp;
  577         struct ksem *ks;
  578         int error;
  579 
  580         if ((kp = l->l_proc->p_ksems) == NULL)
  581                 return (EINVAL);
  582 
  583         lockmgr(&kp->kp_lock, LK_SHARED, NULL);
  584         ks = ksem_lookup_proc(kp, id);
  585         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  586         if (ks == NULL)
  587                 return (EINVAL);
  588 
  589         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  590         ksem_addref(ks);
  591         while (ks->ks_value == 0) {
  592                 ks->ks_waiters++;
  593                 error = tryflag ? EAGAIN : ltsleep(ks, PCATCH, "psem", 0,
  594                     &ks->ks_interlock);
  595                 ks->ks_waiters--;
  596                 if (error)
  597                         goto out;
  598         }
  599         ks->ks_value--;
  600         error = 0;
  601  out:
  602         ksem_delref(ks);
  603         return (error);
  604 }
  605 
  606 int
  607 sys__ksem_wait(struct lwp *l, void *v, register_t *retval)
  608 {
  609         struct sys__ksem_wait_args /* {
  610                 semid_t id;
  611         } */ *uap = v;
  612 
  613         return ksem_wait(l, SCARG(uap, id), 0);
  614 }
  615 
  616 int
  617 sys__ksem_trywait(struct lwp *l, void *v, register_t *retval)
  618 {
  619         struct sys__ksem_trywait_args /* {
  620                 semid_t id;
  621         } */ *uap = v;
  622 
  623         return ksem_wait(l, SCARG(uap, id), 1);
  624 }
  625 
  626 int
  627 sys__ksem_getvalue(struct lwp *l, void *v, register_t *retval)
  628 {
  629         struct sys__ksem_getvalue_args /* {
  630                 semid_t id;
  631                 unsigned int *value;
  632         } */ *uap = v;
  633         struct ksem_proc *kp;
  634         struct ksem *ks;
  635         unsigned int val;
  636 
  637         if ((kp = l->l_proc->p_ksems) == NULL)
  638                 return (EINVAL);
  639 
  640         lockmgr(&kp->kp_lock, LK_SHARED, NULL);
  641         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  642         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  643         if (ks == NULL)
  644                 return (EINVAL);
  645 
  646         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  647         val = ks->ks_value;
  648         simple_unlock(&ks->ks_interlock);
  649 
  650         return (copyout(&val, SCARG(uap, value), sizeof(val)));
  651 }
  652 
  653 int
  654 sys__ksem_destroy(struct lwp *l, void *v, register_t *retval)
  655 {
  656         struct sys__ksem_destroy_args /*{
  657                 semid_t id;
  658         } */ *uap = v;
  659         struct ksem_proc *kp;
  660         struct ksem_ref *ksr;
  661         struct ksem *ks;
  662 
  663         if ((kp = l->l_proc->p_ksems) == NULL)
  664                 return (EINVAL);
  665 
  666         lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
  667 
  668         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  669         if (ks == NULL) {
  670                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  671                 return (EINVAL);
  672         }
  673 
  674         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  675 
  676         /*
  677          * XXX This misses named semaphores which have been unlink'd,
  678          * XXX but since behavior of destroying a named semaphore is
  679          * XXX undefined, this is technically allowed.
  680          */
  681         if (ks->ks_name != NULL) {
  682                 simple_unlock(&ks->ks_interlock);
  683                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  684                 return (EINVAL);
  685         }
  686 
  687         if (ks->ks_waiters) {
  688                 simple_unlock(&ks->ks_interlock);
  689                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  690                 return (EBUSY);
  691         }
  692 
  693         ksr = ksem_drop_proc(kp, ks);
  694         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  695         free(ksr, M_SEM);
  696 
  697         return (0);
  698 }
  699 
  700 static void
  701 ksem_forkhook(struct proc *p2, struct proc *p1)
  702 {
  703         struct ksem_proc *kp1, *kp2;
  704         struct ksem_ref *ksr, *ksr1;
  705 
  706         if ((kp1 = p1->p_ksems) == NULL) {
  707                 p2->p_ksems = NULL;
  708                 return;
  709         }
  710 
  711         p2->p_ksems = kp2 = ksem_proc_alloc();
  712 
  713         lockmgr(&kp1->kp_lock, LK_SHARED, NULL);
  714 
  715         if (!LIST_EMPTY(&kp1->kp_ksems)) {
  716                 LIST_FOREACH(ksr, &kp1->kp_ksems, ksr_list) {
  717                         ksr1 = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
  718                         ksr1->ksr_ksem = ksr->ksr_ksem;
  719                         simple_lock(&ksr->ksr_ksem->ks_interlock);
  720                         ksem_addref(ksr->ksr_ksem);
  721                         simple_unlock(&ksr->ksr_ksem->ks_interlock);
  722                         LIST_INSERT_HEAD(&kp2->kp_ksems, ksr1, ksr_list);
  723                 }
  724         }
  725 
  726         lockmgr(&kp1->kp_lock, LK_RELEASE, NULL);
  727 }
  728 
  729 static void
  730 ksem_exithook(struct proc *p, void *arg)
  731 {
  732         struct ksem_proc *kp;
  733         struct ksem_ref *ksr;
  734 
  735         if ((kp = p->p_ksems) == NULL)
  736                 return;
  737 
  738         /* Don't bother locking; process is dying. */
  739 
  740         while ((ksr = LIST_FIRST(&kp->kp_ksems)) != NULL) {
  741                 LIST_REMOVE(ksr, ksr_list);
  742                 simple_lock(&ksr->ksr_ksem->ks_interlock);
  743                 ksem_delref(ksr->ksr_ksem);
  744                 free(ksr, M_SEM);
  745         }
  746 }
  747 
  748 void
  749 ksem_init(void)
  750 {
  751 
  752         simple_lock_init(&ksem_slock);
  753         exithook_establish(ksem_exithook, NULL);
  754         exechook_establish(ksem_exithook, NULL);
  755         forkhook_establish(ksem_forkhook);
  756 }

Cache object: 0be7b55d0fe66fb8f70be00ad69c47b7


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