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.18 2006/11/01 10:17:59 yamt 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.18 2006/11/01 10:17:59 yamt 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 #include <sys/kauth.h>
   82 
   83 #include <sys/mount.h>
   84 
   85 #include <sys/syscallargs.h>
   86 
   87 #ifndef SEM_MAX
   88 #define SEM_MAX 30
   89 #endif
   90 
   91 #define SEM_MAX_NAMELEN 14
   92 #define SEM_VALUE_MAX (~0U)
   93 #define SEM_HASHTBL_SIZE 13
   94 
   95 #define SEM_TO_ID(x)    (((x)->ks_id))
   96 #define SEM_HASH(id)    ((id) % SEM_HASHTBL_SIZE)
   97 
   98 MALLOC_DEFINE(M_SEM, "p1003_1b_sem", "p1003_1b semaphores");
   99 
  100 /*
  101  * Note: to read the ks_name member, you need either the ks_interlock
  102  * or the ksem_slock.  To write the ks_name member, you need both.  Make
  103  * sure the order is ksem_slock -> ks_interlock.
  104  */
  105 struct ksem {
  106         LIST_ENTRY(ksem) ks_entry;      /* global list entry */
  107         LIST_ENTRY(ksem) ks_hash;       /* hash list entry */
  108         struct simplelock ks_interlock; /* lock on this ksem */
  109         char *ks_name;                  /* if named, this is the name */
  110         unsigned int ks_ref;            /* number of references */
  111         mode_t ks_mode;                 /* protection bits */
  112         uid_t ks_uid;                   /* creator uid */
  113         gid_t ks_gid;                   /* creator gid */
  114         unsigned int ks_value;          /* current value */
  115         unsigned int ks_waiters;        /* number of waiters */
  116         semid_t ks_id;                  /* unique identifier */
  117 };
  118 
  119 struct ksem_ref {
  120         LIST_ENTRY(ksem_ref) ksr_list;
  121         struct ksem *ksr_ksem;
  122 };
  123 
  124 struct ksem_proc {
  125         struct lock kp_lock;
  126         LIST_HEAD(, ksem_ref) kp_ksems;
  127 };
  128 
  129 LIST_HEAD(ksem_list, ksem);
  130 
  131 /*
  132  * ksem_slock protects ksem_head and nsems.  Only named semaphores go
  133  * onto ksem_head.
  134  */
  135 static struct simplelock ksem_slock;
  136 static struct ksem_list ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
  137 static struct ksem_list ksem_hash[SEM_HASHTBL_SIZE];
  138 static int nsems = 0;
  139 
  140 /*
  141  * ksem_counter is the last assigned semid_t.  It needs to be COMPAT_NETBSD32
  142  * friendly, even though semid_t itself is defined as uintptr_t.
  143  */
  144 static uint32_t ksem_counter = 1;
  145 
  146 static specificdata_key_t ksem_specificdata_key;
  147 
  148 static void
  149 ksem_free(struct ksem *ks)
  150 {
  151 
  152         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  153         /*
  154          * If the ksem is anonymous (or has been unlinked), then
  155          * this is the end if its life.
  156          */
  157         if (ks->ks_name == NULL) {
  158                 simple_unlock(&ks->ks_interlock);
  159 
  160                 simple_lock(&ksem_slock);
  161                 nsems--;
  162                 LIST_REMOVE(ks, ks_hash);
  163                 simple_unlock(&ksem_slock);
  164 
  165                 free(ks, M_SEM);
  166                 return;
  167         }
  168         simple_unlock(&ks->ks_interlock);
  169 }
  170 
  171 static inline void
  172 ksem_addref(struct ksem *ks)
  173 {
  174 
  175         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  176         ks->ks_ref++;
  177         KASSERT(ks->ks_ref != 0);       /* XXX KDASSERT */
  178 }
  179 
  180 static inline void
  181 ksem_delref(struct ksem *ks)
  182 {
  183 
  184         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  185         KASSERT(ks->ks_ref != 0);       /* XXX KDASSERT */
  186         if (--ks->ks_ref == 0) {
  187                 ksem_free(ks);
  188                 return;
  189         }
  190         simple_unlock(&ks->ks_interlock);
  191 }
  192 
  193 static struct ksem_proc *
  194 ksem_proc_alloc(void)
  195 {
  196         struct ksem_proc *kp;
  197 
  198         kp = malloc(sizeof(*kp), M_SEM, M_WAITOK);
  199         lockinit(&kp->kp_lock, PWAIT, "ksproc", 0, 0);
  200         LIST_INIT(&kp->kp_ksems);
  201 
  202         return (kp);
  203 }
  204 
  205 static void
  206 ksem_proc_dtor(void *arg)
  207 {
  208         struct ksem_proc *kp = arg;
  209         struct ksem_ref *ksr;
  210 
  211         lockmgr(&kp->kp_lock, LK_DRAIN, NULL);
  212 
  213         while ((ksr = LIST_FIRST(&kp->kp_ksems)) != NULL) {
  214                 LIST_REMOVE(ksr, ksr_list);
  215                 simple_lock(&ksr->ksr_ksem->ks_interlock);
  216                 ksem_delref(ksr->ksr_ksem);
  217                 free(ksr, M_SEM);
  218         }
  219 
  220         free(kp, M_SEM);
  221 }
  222 
  223 static void
  224 ksem_add_proc(struct proc *p, struct ksem *ks)
  225 {
  226         struct ksem_proc *kp;
  227         struct ksem_ref *ksr;
  228 
  229         kp = proc_getspecific(p, ksem_specificdata_key);
  230         if (kp == NULL) {
  231                 kp = ksem_proc_alloc();
  232                 proc_setspecific(p, ksem_specificdata_key, kp);
  233         }
  234 
  235         ksr = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
  236         ksr->ksr_ksem = ks;
  237 
  238         lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
  239         LIST_INSERT_HEAD(&kp->kp_ksems, ksr, ksr_list);
  240         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  241 }
  242 
  243 /* We MUST have a write lock on the ksem_proc list! */
  244 static struct ksem_ref *
  245 ksem_drop_proc(struct ksem_proc *kp, struct ksem *ks)
  246 {
  247         struct ksem_ref *ksr;
  248 
  249         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  250         LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
  251                 if (ksr->ksr_ksem == ks) {
  252                         ksem_delref(ks);
  253                         LIST_REMOVE(ksr, ksr_list);
  254                         return (ksr);
  255                 }
  256         }
  257 #ifdef DIAGNOSTIC
  258         panic("ksem_drop_proc: ksem_proc %p ksem %p", kp, ks);
  259 #endif
  260         return (NULL);
  261 }
  262 
  263 static int
  264 ksem_perm(struct lwp *l, struct ksem *ks)
  265 {
  266         kauth_cred_t uc;
  267 
  268         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  269         uc = l->l_cred;
  270         if ((kauth_cred_geteuid(uc) == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
  271             (kauth_cred_getegid(uc) == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
  272             (ks->ks_mode & S_IWOTH) != 0 ||
  273             kauth_authorize_generic(uc, KAUTH_GENERIC_ISSUSER, &l->l_acflag) == 0)
  274                 return (0);
  275         return (EPERM);
  276 }
  277 
  278 static struct ksem *
  279 ksem_lookup_byid(semid_t id)
  280 {
  281         struct ksem *ks;
  282 
  283         LOCK_ASSERT(simple_lock_held(&ksem_slock));
  284         LIST_FOREACH(ks, &ksem_hash[SEM_HASH(id)], ks_hash) {
  285                 if (ks->ks_id == id)
  286                         return ks;
  287         }
  288         return NULL;
  289 }
  290 
  291 static struct ksem *
  292 ksem_lookup_byname(const char *name)
  293 {
  294         struct ksem *ks;
  295 
  296         LOCK_ASSERT(simple_lock_held(&ksem_slock));
  297         LIST_FOREACH(ks, &ksem_head, ks_entry) {
  298                 if (strcmp(ks->ks_name, name) == 0) {
  299                         simple_lock(&ks->ks_interlock);
  300                         return (ks);
  301                 }
  302         }
  303         return (NULL);
  304 }
  305 
  306 static int
  307 ksem_create(struct lwp *l, const char *name, struct ksem **ksret,
  308     mode_t mode, unsigned int value)
  309 {
  310         struct ksem *ret;
  311         kauth_cred_t uc;
  312         size_t len;
  313 
  314         uc = l->l_cred;
  315         if (value > SEM_VALUE_MAX)
  316                 return (EINVAL);
  317         ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
  318         if (name != NULL) {
  319                 len = strlen(name);
  320                 if (len > SEM_MAX_NAMELEN) {
  321                         free(ret, M_SEM);
  322                         return (ENAMETOOLONG);
  323                 }
  324                 /* name must start with a '/' but not contain one. */
  325                 if (*name != '/' || len < 2 || strchr(name + 1, '/') != NULL) {
  326                         free(ret, M_SEM);
  327                         return (EINVAL);
  328                 }
  329                 ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
  330                 strlcpy(ret->ks_name, name, len + 1);
  331         } else
  332                 ret->ks_name = NULL;
  333         ret->ks_mode = mode;
  334         ret->ks_value = value;
  335         ret->ks_ref = 1;
  336         ret->ks_waiters = 0;
  337         ret->ks_uid = kauth_cred_geteuid(uc);
  338         ret->ks_gid = kauth_cred_getegid(uc);
  339         simple_lock_init(&ret->ks_interlock);
  340 
  341         simple_lock(&ksem_slock);
  342         if (nsems >= SEM_MAX) {
  343                 simple_unlock(&ksem_slock);
  344                 if (ret->ks_name != NULL)
  345                         free(ret->ks_name, M_SEM);
  346                 free(ret, M_SEM);
  347                 return (ENFILE);
  348         }
  349         nsems++;
  350         while (ksem_lookup_byid(ksem_counter) != NULL) {
  351                 ksem_counter++;
  352                 /* 0 is a special value for libpthread */
  353                 if (ksem_counter == 0)
  354                         ksem_counter++;
  355         }
  356         ret->ks_id = ksem_counter;
  357         LIST_INSERT_HEAD(&ksem_hash[SEM_HASH(ret->ks_id)], ret, ks_hash);
  358         simple_unlock(&ksem_slock);
  359 
  360         *ksret = ret;
  361         return (0);
  362 }
  363 
  364 int
  365 sys__ksem_init(struct lwp *l, void *v, register_t *retval)
  366 {
  367         struct sys__ksem_init_args /* {
  368                 unsigned int value;
  369                 semid_t *idp;
  370         } */ *uap = v;
  371 
  372         return do_ksem_init(l, SCARG(uap, value), SCARG(uap, idp), copyout);
  373 }
  374 
  375 int
  376 do_ksem_init(struct lwp *l, unsigned int value, semid_t *idp,
  377     copyout_t docopyout)
  378 {
  379         struct ksem *ks;
  380         semid_t id;
  381         int error;
  382 
  383         /* Note the mode does not matter for anonymous semaphores. */
  384         error = ksem_create(l, NULL, &ks, 0, value);
  385         if (error)
  386                 return (error);
  387         id = SEM_TO_ID(ks);
  388         error = (*docopyout)(&id, idp, sizeof(id));
  389         if (error) {
  390                 simple_lock(&ks->ks_interlock);
  391                 ksem_delref(ks);
  392                 return (error);
  393         }
  394 
  395         ksem_add_proc(l->l_proc, ks);
  396 
  397         return (0);
  398 }
  399 
  400 int
  401 sys__ksem_open(struct lwp *l, void *v, register_t *retval)
  402 {
  403         struct sys__ksem_open_args /* {
  404                 const char *name;
  405                 int oflag;
  406                 mode_t mode;
  407                 unsigned int value;
  408                 semid_t *idp;
  409         } */ *uap = v;
  410 
  411         return do_ksem_open(l, SCARG(uap, name), SCARG(uap, oflag),
  412             SCARG(uap, mode), SCARG(uap, value), SCARG(uap, idp), copyout);
  413 }
  414 
  415 int
  416 do_ksem_open(struct lwp *l, const char *semname, int oflag, mode_t mode,
  417      unsigned int value, semid_t *idp, copyout_t docopyout)
  418 {
  419         char name[SEM_MAX_NAMELEN + 1];
  420         size_t done;
  421         int error;
  422         struct ksem *ksnew, *ks;
  423         semid_t id;
  424 
  425         error = copyinstr(semname, name, sizeof(name), &done);
  426         if (error)
  427                 return (error);
  428 
  429         ksnew = NULL;
  430         simple_lock(&ksem_slock);
  431         ks = ksem_lookup_byname(name);
  432 
  433         /* Found one? */
  434         if (ks != NULL) {
  435                 /* Check for exclusive create. */
  436                 if (oflag & O_EXCL) {
  437                         simple_unlock(&ks->ks_interlock);
  438                         simple_unlock(&ksem_slock);
  439                         return (EEXIST);
  440                 }
  441  found_one:
  442                 /*
  443                  * Verify permissions.  If we can access it, add
  444                  * this process's reference.
  445                  */
  446                 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  447                 error = ksem_perm(l, ks);
  448                 if (error == 0)
  449                         ksem_addref(ks);
  450                 simple_unlock(&ks->ks_interlock);
  451                 simple_unlock(&ksem_slock);
  452                 if (error)
  453                         return (error);
  454 
  455                 id = SEM_TO_ID(ks);
  456                 error = (*docopyout)(&id, idp, sizeof(id));
  457                 if (error) {
  458                         simple_lock(&ks->ks_interlock);
  459                         ksem_delref(ks);
  460                         return (error);
  461                 }
  462 
  463                 ksem_add_proc(l->l_proc, ks);
  464 
  465                 return (0);
  466         }
  467 
  468         /*
  469          * didn't ask for creation? error.
  470          */
  471         if ((oflag & O_CREAT) == 0) {
  472                 simple_unlock(&ksem_slock);
  473                 return (ENOENT);
  474         }
  475 
  476         /*
  477          * We may block during creation, so drop the lock.
  478          */
  479         simple_unlock(&ksem_slock);
  480         error = ksem_create(l, name, &ksnew, mode, value);
  481         if (error != 0)
  482                 return (error);
  483 
  484         id = SEM_TO_ID(ksnew);
  485         error = (*docopyout)(&id, idp, sizeof(id));
  486         if (error) {
  487                 free(ksnew->ks_name, M_SEM);
  488                 ksnew->ks_name = NULL;
  489 
  490                 simple_lock(&ksnew->ks_interlock);
  491                 ksem_delref(ksnew);
  492                 return (error);
  493         }
  494 
  495         /*
  496          * We need to make sure we haven't lost a race while
  497          * allocating during creation.
  498          */
  499         simple_lock(&ksem_slock);
  500         if ((ks = ksem_lookup_byname(name)) != NULL) {
  501                 if (oflag & O_EXCL) {
  502                         simple_unlock(&ks->ks_interlock);
  503                         simple_unlock(&ksem_slock);
  504 
  505                         free(ksnew->ks_name, M_SEM);
  506                         ksnew->ks_name = NULL;
  507 
  508                         simple_lock(&ksnew->ks_interlock);
  509                         ksem_delref(ksnew);
  510                         return (EEXIST);
  511                 }
  512                 goto found_one;
  513         } else {
  514                 /* ksnew already has its initial reference. */
  515                 LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
  516                 simple_unlock(&ksem_slock);
  517 
  518                 ksem_add_proc(l->l_proc, ksnew);
  519         }
  520         return (error);
  521 }
  522 
  523 /* We must have a read lock on the ksem_proc list! */
  524 static struct ksem *
  525 ksem_lookup_proc(struct ksem_proc *kp, semid_t id)
  526 {
  527         struct ksem_ref *ksr;
  528 
  529         LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
  530                 if (id == SEM_TO_ID(ksr->ksr_ksem)) {
  531                         simple_lock(&ksr->ksr_ksem->ks_interlock);
  532                         return (ksr->ksr_ksem);
  533                 }
  534         }
  535 
  536         return (NULL);
  537 }
  538 
  539 int
  540 sys__ksem_unlink(struct lwp *l, void *v, register_t *retval)
  541 {
  542         struct sys__ksem_unlink_args /* {
  543                 const char *name;
  544         } */ *uap = v;
  545         char name[SEM_MAX_NAMELEN + 1], *cp;
  546         size_t done;
  547         struct ksem *ks;
  548         int error;
  549 
  550         error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
  551         if (error)
  552                 return error;
  553 
  554         simple_lock(&ksem_slock);
  555         ks = ksem_lookup_byname(name);
  556         if (ks == NULL) {
  557                 simple_unlock(&ksem_slock);
  558                 return (ENOENT);
  559         }
  560 
  561         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  562 
  563         LIST_REMOVE(ks, ks_entry);
  564         cp = ks->ks_name;
  565         ks->ks_name = NULL;
  566 
  567         simple_unlock(&ksem_slock);
  568 
  569         if (ks->ks_ref == 0)
  570                 ksem_free(ks);
  571         else
  572                 simple_unlock(&ks->ks_interlock);
  573 
  574         free(cp, M_SEM);
  575 
  576         return (0);
  577 }
  578 
  579 int
  580 sys__ksem_close(struct lwp *l, void *v, register_t *retval)
  581 {
  582         struct sys__ksem_close_args /* {
  583                 semid_t id;
  584         } */ *uap = v;
  585         struct ksem_proc *kp;
  586         struct ksem_ref *ksr;
  587         struct ksem *ks;
  588 
  589         kp = proc_getspecific(l->l_proc, ksem_specificdata_key);
  590         if (kp == NULL)
  591                 return (EINVAL);
  592 
  593         lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
  594 
  595         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  596         if (ks == NULL) {
  597                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  598                 return (EINVAL);
  599         }
  600 
  601         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  602         if (ks->ks_name == NULL) {
  603                 simple_unlock(&ks->ks_interlock);
  604                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  605                 return (EINVAL);
  606         }
  607 
  608         ksr = ksem_drop_proc(kp, ks);
  609         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  610         free(ksr, M_SEM);
  611 
  612         return (0);
  613 }
  614 
  615 int
  616 sys__ksem_post(struct lwp *l, void *v, register_t *retval)
  617 {
  618         struct sys__ksem_post_args /* {
  619                 semid_t id;
  620         } */ *uap = v;
  621         struct ksem_proc *kp;
  622         struct ksem *ks;
  623         int error;
  624 
  625         kp = proc_getspecific(l->l_proc, ksem_specificdata_key);
  626         if (kp == NULL)
  627                 return (EINVAL);
  628 
  629         lockmgr(&kp->kp_lock, LK_SHARED, NULL);
  630         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  631         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  632         if (ks == NULL)
  633                 return (EINVAL);
  634 
  635         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  636         if (ks->ks_value == SEM_VALUE_MAX) {
  637                 error = EOVERFLOW;
  638                 goto out;
  639         }
  640         ++ks->ks_value;
  641         if (ks->ks_waiters)
  642                 wakeup(ks);
  643         error = 0;
  644  out:
  645         simple_unlock(&ks->ks_interlock);
  646         return (error);
  647 }
  648 
  649 static int
  650 ksem_wait(struct lwp *l, semid_t id, int tryflag)
  651 {
  652         struct ksem_proc *kp;
  653         struct ksem *ks;
  654         int error;
  655 
  656         kp = proc_getspecific(l->l_proc, ksem_specificdata_key);
  657         if (kp == NULL)
  658                 return (EINVAL);
  659 
  660         lockmgr(&kp->kp_lock, LK_SHARED, NULL);
  661         ks = ksem_lookup_proc(kp, id);
  662         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  663         if (ks == NULL)
  664                 return (EINVAL);
  665 
  666         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  667         ksem_addref(ks);
  668         while (ks->ks_value == 0) {
  669                 ks->ks_waiters++;
  670                 error = tryflag ? EAGAIN : ltsleep(ks, PCATCH, "psem", 0,
  671                     &ks->ks_interlock);
  672                 ks->ks_waiters--;
  673                 if (error)
  674                         goto out;
  675         }
  676         ks->ks_value--;
  677         error = 0;
  678  out:
  679         ksem_delref(ks);
  680         return (error);
  681 }
  682 
  683 int
  684 sys__ksem_wait(struct lwp *l, void *v, register_t *retval)
  685 {
  686         struct sys__ksem_wait_args /* {
  687                 semid_t id;
  688         } */ *uap = v;
  689 
  690         return ksem_wait(l, SCARG(uap, id), 0);
  691 }
  692 
  693 int
  694 sys__ksem_trywait(struct lwp *l, void *v, register_t *retval)
  695 {
  696         struct sys__ksem_trywait_args /* {
  697                 semid_t id;
  698         } */ *uap = v;
  699 
  700         return ksem_wait(l, SCARG(uap, id), 1);
  701 }
  702 
  703 int
  704 sys__ksem_getvalue(struct lwp *l, void *v, register_t *retval)
  705 {
  706         struct sys__ksem_getvalue_args /* {
  707                 semid_t id;
  708                 unsigned int *value;
  709         } */ *uap = v;
  710         struct ksem_proc *kp;
  711         struct ksem *ks;
  712         unsigned int val;
  713 
  714         kp = proc_getspecific(l->l_proc, ksem_specificdata_key);
  715         if (kp == NULL)
  716                 return (EINVAL);
  717 
  718         lockmgr(&kp->kp_lock, LK_SHARED, NULL);
  719         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  720         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  721         if (ks == NULL)
  722                 return (EINVAL);
  723 
  724         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  725         val = ks->ks_value;
  726         simple_unlock(&ks->ks_interlock);
  727 
  728         return (copyout(&val, SCARG(uap, value), sizeof(val)));
  729 }
  730 
  731 int
  732 sys__ksem_destroy(struct lwp *l, void *v, register_t *retval)
  733 {
  734         struct sys__ksem_destroy_args /*{
  735                 semid_t id;
  736         } */ *uap = v;
  737         struct ksem_proc *kp;
  738         struct ksem_ref *ksr;
  739         struct ksem *ks;
  740 
  741         kp = proc_getspecific(l->l_proc, ksem_specificdata_key);
  742         if (kp == NULL)
  743                 return (EINVAL);
  744 
  745         lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
  746 
  747         ks = ksem_lookup_proc(kp, SCARG(uap, id));
  748         if (ks == NULL) {
  749                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  750                 return (EINVAL);
  751         }
  752 
  753         LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
  754 
  755         /*
  756          * XXX This misses named semaphores which have been unlink'd,
  757          * XXX but since behavior of destroying a named semaphore is
  758          * XXX undefined, this is technically allowed.
  759          */
  760         if (ks->ks_name != NULL) {
  761                 simple_unlock(&ks->ks_interlock);
  762                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  763                 return (EINVAL);
  764         }
  765 
  766         if (ks->ks_waiters) {
  767                 simple_unlock(&ks->ks_interlock);
  768                 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  769                 return (EBUSY);
  770         }
  771 
  772         ksr = ksem_drop_proc(kp, ks);
  773         lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
  774         free(ksr, M_SEM);
  775 
  776         return (0);
  777 }
  778 
  779 static void
  780 ksem_forkhook(struct proc *p2, struct proc *p1)
  781 {
  782         struct ksem_proc *kp1, *kp2;
  783         struct ksem_ref *ksr, *ksr1;
  784 
  785         kp1 = proc_getspecific(p1, ksem_specificdata_key);
  786         if (kp1 == NULL)
  787                 return;
  788 
  789         kp2 = ksem_proc_alloc();
  790 
  791         lockmgr(&kp1->kp_lock, LK_SHARED, NULL);
  792 
  793         if (!LIST_EMPTY(&kp1->kp_ksems)) {
  794                 LIST_FOREACH(ksr, &kp1->kp_ksems, ksr_list) {
  795                         ksr1 = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
  796                         ksr1->ksr_ksem = ksr->ksr_ksem;
  797                         simple_lock(&ksr->ksr_ksem->ks_interlock);
  798                         ksem_addref(ksr->ksr_ksem);
  799                         simple_unlock(&ksr->ksr_ksem->ks_interlock);
  800                         LIST_INSERT_HEAD(&kp2->kp_ksems, ksr1, ksr_list);
  801                 }
  802         }
  803 
  804         lockmgr(&kp1->kp_lock, LK_RELEASE, NULL);
  805 
  806         proc_setspecific(p2, ksem_specificdata_key, kp2);
  807 }
  808 
  809 static void
  810 ksem_exechook(struct proc *p, void *arg)
  811 {
  812         struct ksem_proc *kp;
  813 
  814         kp = proc_getspecific(p, ksem_specificdata_key);
  815         if (kp != NULL) {
  816                 proc_setspecific(p, ksem_specificdata_key, NULL);
  817                 ksem_proc_dtor(kp);
  818         }
  819 }
  820 
  821 void
  822 ksem_init(void)
  823 {
  824         int i, error;
  825 
  826         simple_lock_init(&ksem_slock);
  827         exechook_establish(ksem_exechook, NULL);
  828         forkhook_establish(ksem_forkhook);
  829 
  830         for (i = 0; i < SEM_HASHTBL_SIZE; i++)
  831                 LIST_INIT(&ksem_hash[i]);
  832 
  833         error = proc_specific_key_create(&ksem_specificdata_key,
  834                                          ksem_proc_dtor);
  835         KASSERT(error == 0);
  836 }

Cache object: 5d8fefee437897f3743e1dcd53dc470f


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