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 /*-
    2  * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: src/sys/kern/uipc_sem.c,v 1.12.2.3 2005/03/13 13:02:56 rwatson Exp $");
   29 
   30 #include "opt_posix.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/sysproto.h>
   35 #include <sys/eventhandler.h>
   36 #include <sys/kernel.h>
   37 #include <sys/proc.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/module.h>
   41 #include <sys/condvar.h>
   42 #include <sys/sem.h>
   43 #include <sys/uio.h>
   44 #include <sys/syscall.h>
   45 #include <sys/stat.h>
   46 #include <sys/sysent.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/time.h>
   49 #include <sys/malloc.h>
   50 #include <sys/fcntl.h>
   51 
   52 #include <posix4/posix4.h>
   53 #include <posix4/semaphore.h>
   54 #include <posix4/_semaphore.h>
   55 
   56 static struct ksem *sem_lookup_byname(const char *name);
   57 static int sem_create(struct thread *td, const char *name,
   58     struct ksem **ksret, mode_t mode, unsigned int value);
   59 static void sem_free(struct ksem *ksnew);
   60 static int sem_perm(struct thread *td, struct ksem *ks);
   61 static void sem_enter(struct proc *p, struct ksem *ks);
   62 static int sem_leave(struct proc *p, struct ksem *ks);
   63 static void sem_exithook(void *arg, struct proc *p);
   64 static int sem_hasopen(struct thread *td, struct ksem *ks);
   65 
   66 static int kern_sem_close(struct thread *td, semid_t id);
   67 static int kern_sem_post(struct thread *td, semid_t id);
   68 static int kern_sem_wait(struct thread *td, semid_t id, int tryflag,
   69     struct timespec *abstime);
   70 static int kern_sem_init(struct thread *td, int dir, unsigned int value,
   71     semid_t *idp);
   72 static int kern_sem_open(struct thread *td, int dir, const char *name,
   73     int oflag, mode_t mode, unsigned int value, semid_t *idp);
   74 static int kern_sem_unlink(struct thread *td, const char *name);
   75 
   76 #ifndef SEM_MAX
   77 #define SEM_MAX 30
   78 #endif
   79 
   80 #define SEM_MAX_NAMELEN 14
   81 
   82 #define SEM_TO_ID(x)    ((intptr_t)(x))
   83 #define ID_TO_SEM(x)    id_to_sem(x)
   84 
   85 struct kuser {
   86         pid_t ku_pid;
   87         LIST_ENTRY(kuser) ku_next;
   88 };
   89 
   90 struct ksem {
   91         LIST_ENTRY(ksem) ks_entry;      /* global list entry */
   92         int ks_onlist;                  /* boolean if on a list (ks_entry) */
   93         char *ks_name;                  /* if named, this is the name */
   94         int ks_ref;                     /* number of references */
   95         mode_t ks_mode;                 /* protection bits */
   96         uid_t ks_uid;                   /* creator uid */
   97         gid_t ks_gid;                   /* creator gid */
   98         unsigned int ks_value;          /* current value */
   99         struct cv ks_cv;                /* waiters sleep here */
  100         int ks_waiters;                 /* number of waiters */
  101         LIST_HEAD(, kuser) ks_users;    /* pids using this sem */
  102 };
  103 
  104 /*
  105  * available semaphores go here, this includes sem_init and any semaphores
  106  * created via sem_open that have not yet been unlinked.
  107  */
  108 LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
  109 /*
  110  * semaphores still in use but have been sem_unlink()'d go here.
  111  */
  112 LIST_HEAD(, ksem) ksem_deadhead = LIST_HEAD_INITIALIZER(&ksem_deadhead);
  113 
  114 static struct mtx sem_lock;
  115 static MALLOC_DEFINE(M_SEM, "sems", "semaphore data");
  116 
  117 static int nsems = 0;
  118 SYSCTL_DECL(_p1003_1b);
  119 SYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0, "");
  120 
  121 static eventhandler_tag sem_exit_tag, sem_exec_tag;
  122 
  123 #ifdef SEM_DEBUG
  124 #define DP(x)   printf x
  125 #else
  126 #define DP(x)
  127 #endif
  128 
  129 static __inline
  130 void
  131 sem_ref(struct ksem *ks)
  132 {
  133 
  134         mtx_assert(&sem_lock, MA_OWNED);
  135         ks->ks_ref++;
  136         DP(("sem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
  137 }
  138 
  139 static __inline
  140 void
  141 sem_rel(struct ksem *ks)
  142 {
  143 
  144         mtx_assert(&sem_lock, MA_OWNED);
  145         DP(("sem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
  146         if (--ks->ks_ref == 0)
  147                 sem_free(ks);
  148 }
  149 
  150 static __inline struct ksem *id_to_sem(semid_t id);
  151 
  152 static __inline
  153 struct ksem *
  154 id_to_sem(id)
  155         semid_t id;
  156 {
  157         struct ksem *ks;
  158 
  159         mtx_assert(&sem_lock, MA_OWNED);
  160         DP(("id_to_sem: id = %0x,%p\n", id, (struct ksem *)id));
  161         LIST_FOREACH(ks, &ksem_head, ks_entry) {
  162                 DP(("id_to_sem: ks = %p\n", ks));
  163                 if (ks == (struct ksem *)id)
  164                         return (ks);
  165         }
  166         return (NULL);
  167 }
  168 
  169 static struct ksem *
  170 sem_lookup_byname(name)
  171         const char *name;
  172 {
  173         struct ksem *ks;
  174 
  175         mtx_assert(&sem_lock, MA_OWNED);
  176         LIST_FOREACH(ks, &ksem_head, ks_entry)
  177                 if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
  178                         return (ks);
  179         return (NULL);
  180 }
  181 
  182 static int
  183 sem_create(td, name, ksret, mode, value)
  184         struct thread *td;
  185         const char *name;
  186         struct ksem **ksret;
  187         mode_t mode;
  188         unsigned int value;
  189 {
  190         struct ksem *ret;
  191         struct proc *p;
  192         struct ucred *uc;
  193         size_t len;
  194         int error;
  195 
  196         DP(("sem_create\n"));
  197         p = td->td_proc;
  198         uc = td->td_ucred;
  199         if (value > SEM_VALUE_MAX)
  200                 return (EINVAL);
  201         ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
  202         if (name != NULL) {
  203                 len = strlen(name);
  204                 if (len > SEM_MAX_NAMELEN) {
  205                         free(ret, M_SEM);
  206                         return (ENAMETOOLONG);
  207                 }
  208                 /* name must start with a '/' but not contain one. */
  209                 if (*name != '/' || len < 2 || index(name + 1, '/') != NULL) {
  210                         free(ret, M_SEM);
  211                         return (EINVAL);
  212                 }
  213                 ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
  214                 strcpy(ret->ks_name, name);
  215         } else {
  216                 ret->ks_name = NULL;
  217         }
  218         ret->ks_mode = mode;
  219         ret->ks_value = value;
  220         ret->ks_ref = 1;
  221         ret->ks_waiters = 0;
  222         ret->ks_uid = uc->cr_uid;
  223         ret->ks_gid = uc->cr_gid;
  224         ret->ks_onlist = 0;
  225         cv_init(&ret->ks_cv, "sem");
  226         LIST_INIT(&ret->ks_users);
  227         if (name != NULL)
  228                 sem_enter(td->td_proc, ret);
  229         *ksret = ret;
  230         mtx_lock(&sem_lock);
  231         if (nsems >= p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX)) {
  232                 sem_leave(td->td_proc, ret);
  233                 sem_free(ret);
  234                 error = ENFILE;
  235         } else {
  236                 nsems++;
  237                 error = 0;
  238         }
  239         mtx_unlock(&sem_lock);
  240         return (error);
  241 }
  242 
  243 #ifndef _SYS_SYSPROTO_H_
  244 struct ksem_init_args {
  245         unsigned int value;
  246         semid_t *idp;
  247 };
  248 int ksem_init(struct thread *td, struct ksem_init_args *uap);
  249 #endif
  250 int
  251 ksem_init(td, uap)
  252         struct thread *td;
  253         struct ksem_init_args *uap;
  254 {
  255         int error;
  256 
  257         error = kern_sem_init(td, UIO_USERSPACE, uap->value, uap->idp);
  258         return (error);
  259 }
  260 
  261 static int
  262 kern_sem_init(td, dir, value, idp)
  263         struct thread *td;
  264         int dir;
  265         unsigned int value;
  266         semid_t *idp;
  267 {
  268         struct ksem *ks;
  269         semid_t id;
  270         int error;
  271 
  272         error = sem_create(td, NULL, &ks, S_IRWXU | S_IRWXG, value);
  273         if (error)
  274                 return (error);
  275         id = SEM_TO_ID(ks);
  276         if (dir == UIO_USERSPACE) {
  277                 error = copyout(&id, idp, sizeof(id));
  278                 if (error) {
  279                         mtx_lock(&sem_lock);
  280                         sem_rel(ks);
  281                         mtx_unlock(&sem_lock);
  282                         return (error);
  283                 }
  284         } else {
  285                 *idp = id;
  286         }
  287         mtx_lock(&sem_lock);
  288         LIST_INSERT_HEAD(&ksem_head, ks, ks_entry);
  289         ks->ks_onlist = 1;
  290         mtx_unlock(&sem_lock);
  291         return (error);
  292 }
  293 
  294 #ifndef _SYS_SYSPROTO_H_
  295 struct ksem_open_args {
  296         char *name;
  297         int oflag;
  298         mode_t mode;
  299         unsigned int value;
  300         semid_t *idp;   
  301 };
  302 int ksem_open(struct thread *td, struct ksem_open_args *uap);
  303 #endif
  304 int
  305 ksem_open(td, uap)
  306         struct thread *td;
  307         struct ksem_open_args *uap;
  308 {
  309         char name[SEM_MAX_NAMELEN + 1];
  310         size_t done;
  311         int error;
  312 
  313         error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
  314         if (error)
  315                 return (error);
  316         DP((">>> sem_open start\n"));
  317         error = kern_sem_open(td, UIO_USERSPACE,
  318             name, uap->oflag, uap->mode, uap->value, uap->idp);
  319         DP(("<<< sem_open end\n"));
  320         return (error);
  321 }
  322 
  323 static int
  324 kern_sem_open(td, dir, name, oflag, mode, value, idp)
  325         struct thread *td;
  326         int dir;
  327         const char *name;
  328         int oflag;
  329         mode_t mode;
  330         unsigned int value;
  331         semid_t *idp;
  332 {
  333         struct ksem *ksnew, *ks;
  334         int error;
  335         semid_t id;
  336 
  337         ksnew = NULL;
  338         mtx_lock(&sem_lock);
  339         ks = sem_lookup_byname(name);
  340         /*
  341          * If we found it but O_EXCL is set, error.
  342          */
  343         if (ks != NULL && (oflag & O_EXCL) != 0) {
  344                 mtx_unlock(&sem_lock);
  345                 return (EEXIST);
  346         }
  347         /*
  348          * If we didn't find it...
  349          */
  350         if (ks == NULL) {
  351                 /*
  352                  * didn't ask for creation? error.
  353                  */
  354                 if ((oflag & O_CREAT) == 0) {
  355                         mtx_unlock(&sem_lock);
  356                         return (ENOENT);
  357                 }
  358                 /*
  359                  * We may block during creation, so drop the lock.
  360                  */
  361                 mtx_unlock(&sem_lock);
  362                 error = sem_create(td, name, &ksnew, mode, value);
  363                 if (error != 0)
  364                         return (error);
  365                 id = SEM_TO_ID(ksnew);
  366                 if (dir == UIO_USERSPACE) {
  367                         DP(("about to copyout! %d to %p\n", id, idp));
  368                         error = copyout(&id, idp, sizeof(id));
  369                         if (error) {
  370                                 mtx_lock(&sem_lock);
  371                                 sem_leave(td->td_proc, ksnew);
  372                                 sem_rel(ksnew);
  373                                 mtx_unlock(&sem_lock);
  374                                 return (error);
  375                         }
  376                 } else {
  377                         DP(("about to set! %d to %p\n", id, idp));
  378                         *idp = id;
  379                 }
  380                 /*
  381                  * We need to make sure we haven't lost a race while
  382                  * allocating during creation.
  383                  */
  384                 mtx_lock(&sem_lock);
  385                 ks = sem_lookup_byname(name);
  386                 if (ks != NULL) {
  387                         /* we lost... */
  388                         sem_leave(td->td_proc, ksnew);
  389                         sem_rel(ksnew);
  390                         /* we lost and we can't loose... */
  391                         if ((oflag & O_EXCL) != 0) {
  392                                 mtx_unlock(&sem_lock);
  393                                 return (EEXIST);
  394                         }
  395                 } else {
  396                         DP(("sem_create: about to add to list...\n"));
  397                         LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry); 
  398                         DP(("sem_create: setting list bit...\n"));
  399                         ksnew->ks_onlist = 1;
  400                         DP(("sem_create: done, about to unlock...\n"));
  401                 }
  402                 mtx_unlock(&sem_lock);
  403         } else {
  404                 /*
  405                  * if we aren't the creator, then enforce permissions.
  406                  */
  407                 error = sem_perm(td, ks);
  408                 if (!error)
  409                         sem_ref(ks);
  410                 mtx_unlock(&sem_lock);
  411                 if (error)
  412                         return (error);
  413                 id = SEM_TO_ID(ks);
  414                 if (dir == UIO_USERSPACE) {
  415                         error = copyout(&id, idp, sizeof(id));
  416                         if (error) {
  417                                 mtx_lock(&sem_lock);
  418                                 sem_rel(ks);
  419                                 mtx_unlock(&sem_lock);
  420                                 return (error);
  421                         }
  422                 } else {
  423                         *idp = id;
  424                 }
  425                 sem_enter(td->td_proc, ks);
  426                 mtx_lock(&sem_lock);
  427                 sem_rel(ks);
  428                 mtx_unlock(&sem_lock);
  429         }
  430         return (error);
  431 }
  432 
  433 static int
  434 sem_perm(td, ks)
  435         struct thread *td;
  436         struct ksem *ks;
  437 {
  438         struct ucred *uc;
  439 
  440         uc = td->td_ucred;
  441         DP(("sem_perm: uc(%d,%d) ks(%d,%d,%o)\n",
  442             uc->cr_uid, uc->cr_gid,
  443              ks->ks_uid, ks->ks_gid, ks->ks_mode));
  444         if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
  445             (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
  446             (ks->ks_mode & S_IWOTH) != 0 || suser(td) == 0)
  447                 return (0);
  448         return (EPERM);
  449 }
  450 
  451 static void
  452 sem_free(struct ksem *ks)
  453 {
  454 
  455         nsems--;
  456         if (ks->ks_onlist)
  457                 LIST_REMOVE(ks, ks_entry);
  458         if (ks->ks_name != NULL)
  459                 free(ks->ks_name, M_SEM);
  460         cv_destroy(&ks->ks_cv);
  461         free(ks, M_SEM);
  462 }
  463 
  464 static __inline struct kuser *sem_getuser(struct proc *p, struct ksem *ks);
  465 
  466 static __inline struct kuser *
  467 sem_getuser(p, ks)
  468         struct proc *p;
  469         struct ksem *ks;
  470 {
  471         struct kuser *k;
  472 
  473         LIST_FOREACH(k, &ks->ks_users, ku_next)
  474                 if (k->ku_pid == p->p_pid)
  475                         return (k);
  476         return (NULL);
  477 }
  478 
  479 static int
  480 sem_hasopen(td, ks)
  481         struct thread *td;
  482         struct ksem *ks;
  483 {
  484         
  485         return ((ks->ks_name == NULL && sem_perm(td, ks) == 0)
  486             || sem_getuser(td->td_proc, ks) != NULL);
  487 }
  488 
  489 static int
  490 sem_leave(p, ks)
  491         struct proc *p;
  492         struct ksem *ks;
  493 {
  494         struct kuser *k;
  495 
  496         DP(("sem_leave: ks = %p\n", ks));
  497         k = sem_getuser(p, ks);
  498         DP(("sem_leave: ks = %p, k = %p\n", ks, k));
  499         if (k != NULL) {
  500                 LIST_REMOVE(k, ku_next);
  501                 sem_rel(ks);
  502                 DP(("sem_leave: about to free k\n"));
  503                 free(k, M_SEM);
  504                 DP(("sem_leave: returning\n"));
  505                 return (0);
  506         }
  507         return (EINVAL);
  508 }
  509 
  510 static void
  511 sem_enter(p, ks)
  512         struct proc *p;
  513         struct ksem *ks;
  514 {
  515         struct kuser *ku, *k;
  516 
  517         ku = malloc(sizeof(*ku), M_SEM, M_WAITOK);
  518         ku->ku_pid = p->p_pid;
  519         mtx_lock(&sem_lock);
  520         k = sem_getuser(p, ks);
  521         if (k != NULL) {
  522                 mtx_unlock(&sem_lock);
  523                 free(ku, M_TEMP);
  524                 return;
  525         }
  526         LIST_INSERT_HEAD(&ks->ks_users, ku, ku_next);
  527         sem_ref(ks);
  528         mtx_unlock(&sem_lock);
  529 }
  530 
  531 #ifndef _SYS_SYSPROTO_H_
  532 struct ksem_unlink_args {
  533         char *name;
  534 };
  535 int ksem_unlink(struct thread *td, struct ksem_unlink_args *uap);
  536 #endif
  537         
  538 int
  539 ksem_unlink(td, uap)
  540         struct thread *td;
  541         struct ksem_unlink_args *uap;
  542 {
  543         char name[SEM_MAX_NAMELEN + 1];
  544         size_t done;
  545         int error;
  546 
  547         error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
  548         return (error ? error :
  549             kern_sem_unlink(td, name));
  550 }
  551 
  552 static int
  553 kern_sem_unlink(td, name)
  554         struct thread *td;
  555         const char *name;
  556 {
  557         struct ksem *ks;
  558         int error;
  559 
  560         mtx_lock(&sem_lock);
  561         ks = sem_lookup_byname(name);
  562         if (ks == NULL)
  563                 error = ENOENT;
  564         else
  565                 error = sem_perm(td, ks);
  566         DP(("sem_unlink: '%s' ks = %p, error = %d\n", name, ks, error));
  567         if (error == 0) {
  568                 LIST_REMOVE(ks, ks_entry);
  569                 LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry); 
  570                 sem_rel(ks);
  571         }
  572         mtx_unlock(&sem_lock);
  573         return (error);
  574 }
  575 
  576 #ifndef _SYS_SYSPROTO_H_
  577 struct ksem_close_args {
  578         semid_t id;
  579 };
  580 int ksem_close(struct thread *td, struct ksem_close_args *uap);
  581 #endif
  582 
  583 int
  584 ksem_close(struct thread *td, struct ksem_close_args *uap)
  585 {
  586 
  587         return (kern_sem_close(td, uap->id));
  588 }
  589 
  590 static int
  591 kern_sem_close(td, id)
  592         struct thread *td;
  593         semid_t id;
  594 {
  595         struct ksem *ks;
  596         int error;
  597 
  598         error = EINVAL;
  599         mtx_lock(&sem_lock);
  600         ks = ID_TO_SEM(id);
  601         /* this is not a valid operation for unnamed sems */
  602         if (ks != NULL && ks->ks_name != NULL)
  603                 error = sem_leave(td->td_proc, ks);
  604         mtx_unlock(&sem_lock);
  605         return (error);
  606 }
  607 
  608 #ifndef _SYS_SYSPROTO_H_
  609 struct ksem_post_args {
  610         semid_t id;
  611 };
  612 int ksem_post(struct thread *td, struct ksem_post_args *uap);
  613 #endif
  614 int
  615 ksem_post(td, uap)
  616         struct thread *td;
  617         struct ksem_post_args *uap;
  618 {
  619 
  620         return (kern_sem_post(td, uap->id));
  621 }
  622 
  623 static int
  624 kern_sem_post(td, id)
  625         struct thread *td;
  626         semid_t id;
  627 {
  628         struct ksem *ks;
  629         int error;
  630 
  631         mtx_lock(&sem_lock);
  632         ks = ID_TO_SEM(id);
  633         if (ks == NULL || !sem_hasopen(td, ks)) {
  634                 error = EINVAL;
  635                 goto err;
  636         }
  637         if (ks->ks_value == SEM_VALUE_MAX) {
  638                 error = EOVERFLOW;
  639                 goto err;
  640         }
  641         ++ks->ks_value;
  642         if (ks->ks_waiters > 0)
  643                 cv_signal(&ks->ks_cv);
  644         error = 0;
  645 err:
  646         mtx_unlock(&sem_lock);
  647         return (error);
  648 }
  649 
  650 #ifndef _SYS_SYSPROTO_H_
  651 struct ksem_wait_args {
  652         semid_t id;
  653 };
  654 int ksem_wait(struct thread *td, struct ksem_wait_args *uap);
  655 #endif
  656 
  657 int
  658 ksem_wait(td, uap)
  659         struct thread *td;
  660         struct ksem_wait_args *uap;
  661 {
  662 
  663         return (kern_sem_wait(td, uap->id, 0, NULL));
  664 }
  665 
  666 #ifndef _SYS_SYSPROTO_H_
  667 struct ksem_timedwait_args {
  668         semid_t id;
  669         struct timespec *abstime;
  670 };
  671 int ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap);
  672 #endif
  673 int
  674 ksem_timedwait(td, uap)
  675         struct thread *td;
  676         struct ksem_timedwait_args *uap;
  677 {
  678         struct timespec abstime;
  679         struct timespec *ts;
  680         int error;
  681 
  682         /* We allow a null timespec (wait forever). */
  683         if (uap->abstime == NULL)
  684                 ts = NULL;
  685         else {
  686                 error = copyin(uap->abstime, &abstime, sizeof(abstime));
  687                 if (error != 0)
  688                         return (error);
  689                 if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
  690                         return (EINVAL);
  691                 ts = &abstime;
  692         }
  693         return (kern_sem_wait(td, uap->id, 0, ts));
  694 }
  695 
  696 #ifndef _SYS_SYSPROTO_H_
  697 struct ksem_trywait_args {
  698         semid_t id;
  699 };
  700 int ksem_trywait(struct thread *td, struct ksem_trywait_args *uap);
  701 #endif
  702 int
  703 ksem_trywait(td, uap)
  704         struct thread *td;
  705         struct ksem_trywait_args *uap;
  706 {
  707 
  708         return (kern_sem_wait(td, uap->id, 1, NULL));
  709 }
  710 
  711 static int
  712 kern_sem_wait(td, id, tryflag, abstime)
  713         struct thread *td;
  714         semid_t id;
  715         int tryflag;
  716         struct timespec *abstime;
  717 {
  718         struct timespec ts1, ts2;
  719         struct timeval tv;
  720         struct ksem *ks;
  721         int error;
  722 
  723         DP((">>> kern_sem_wait entered!\n"));
  724         mtx_lock(&sem_lock);
  725         ks = ID_TO_SEM(id);
  726         if (ks == NULL) {
  727                 DP(("kern_sem_wait ks == NULL\n"));
  728                 error = EINVAL;
  729                 goto err;
  730         }
  731         sem_ref(ks);
  732         if (!sem_hasopen(td, ks)) {
  733                 DP(("kern_sem_wait hasopen failed\n"));
  734                 error = EINVAL;
  735                 goto err;
  736         }
  737         DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
  738         if (ks->ks_value == 0) {
  739                 ks->ks_waiters++;
  740                 if (tryflag != 0)
  741                         error = EAGAIN;
  742                 else if (abstime == NULL)
  743                         error = cv_wait_sig(&ks->ks_cv, &sem_lock);
  744                 else {
  745                         for (;;) {
  746                                 ts1 = *abstime;
  747                                 getnanotime(&ts2);
  748                                 timespecsub(&ts1, &ts2);
  749                                 TIMESPEC_TO_TIMEVAL(&tv, &ts1);
  750                                 if (tv.tv_sec < 0) {
  751                                         error = ETIMEDOUT;
  752                                         break;
  753                                 }
  754                                 error = cv_timedwait_sig(&ks->ks_cv,
  755                                     &sem_lock, tvtohz(&tv));
  756                                 if (error != EWOULDBLOCK)
  757                                         break;
  758                         }
  759                 }
  760                 ks->ks_waiters--;
  761                 if (error)
  762                         goto err;
  763         }
  764         ks->ks_value--;
  765         error = 0;
  766 err:
  767         if (ks != NULL)
  768                 sem_rel(ks);
  769         mtx_unlock(&sem_lock);
  770         DP(("<<< kern_sem_wait leaving, error = %d\n", error));
  771         return (error);
  772 }
  773 
  774 #ifndef _SYS_SYSPROTO_H_
  775 struct ksem_getvalue_args {
  776         semid_t id;
  777         int *val;
  778 };
  779 int ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap);
  780 #endif
  781 int
  782 ksem_getvalue(td, uap)
  783         struct thread *td;
  784         struct ksem_getvalue_args *uap;
  785 {
  786         struct ksem *ks;
  787         int error, val;
  788 
  789         mtx_lock(&sem_lock);
  790         ks = ID_TO_SEM(uap->id);
  791         if (ks == NULL || !sem_hasopen(td, ks)) {
  792                 mtx_unlock(&sem_lock);
  793                 return (EINVAL);
  794         }
  795         val = ks->ks_value;
  796         mtx_unlock(&sem_lock);
  797         error = copyout(&val, uap->val, sizeof(val));
  798         return (error);
  799 }
  800 
  801 #ifndef _SYS_SYSPROTO_H_
  802 struct ksem_destroy_args {
  803         semid_t id;
  804 };
  805 int ksem_destroy(struct thread *td, struct ksem_destroy_args *uap);
  806 #endif
  807 int
  808 ksem_destroy(td, uap)
  809         struct thread *td;
  810         struct ksem_destroy_args *uap;
  811 {
  812         struct ksem *ks;
  813         int error;
  814 
  815         mtx_lock(&sem_lock);
  816         ks = ID_TO_SEM(uap->id);
  817         if (ks == NULL || !sem_hasopen(td, ks) ||
  818             ks->ks_name != NULL) {
  819                 error = EINVAL;
  820                 goto err;
  821         }
  822         if (ks->ks_waiters != 0) {
  823                 error = EBUSY;
  824                 goto err;
  825         }
  826         sem_rel(ks);
  827         error = 0;
  828 err:
  829         mtx_unlock(&sem_lock);
  830         return (error);
  831 }
  832 
  833 static void
  834 sem_exithook(arg, p)
  835         void *arg;
  836         struct proc *p;
  837 {
  838         struct ksem *ks, *ksnext;
  839 
  840         mtx_lock(&sem_lock);
  841         ks = LIST_FIRST(&ksem_head);
  842         while (ks != NULL) {
  843                 ksnext = LIST_NEXT(ks, ks_entry);
  844                 sem_leave(p, ks);
  845                 ks = ksnext;
  846         }
  847         ks = LIST_FIRST(&ksem_deadhead);
  848         while (ks != NULL) {
  849                 ksnext = LIST_NEXT(ks, ks_entry);
  850                 sem_leave(p, ks);
  851                 ks = ksnext;
  852         }
  853         mtx_unlock(&sem_lock);
  854 }
  855 
  856 static int
  857 sem_modload(struct module *module, int cmd, void *arg)
  858 {
  859         int error = 0;
  860 
  861         switch (cmd) {
  862         case MOD_LOAD:
  863                 mtx_init(&sem_lock, "sem", "semaphore", MTX_DEF);
  864                 p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
  865                 p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
  866                 sem_exit_tag = EVENTHANDLER_REGISTER(process_exit, sem_exithook,
  867                     NULL, EVENTHANDLER_PRI_ANY);
  868                 sem_exec_tag = EVENTHANDLER_REGISTER(process_exec, sem_exithook,
  869                     NULL, EVENTHANDLER_PRI_ANY);
  870                 break;
  871         case MOD_UNLOAD:
  872                 if (nsems != 0) {
  873                         error = EOPNOTSUPP;
  874                         break;
  875                 }
  876                 EVENTHANDLER_DEREGISTER(process_exit, sem_exit_tag);
  877                 EVENTHANDLER_DEREGISTER(process_exec, sem_exec_tag);
  878                 mtx_destroy(&sem_lock);
  879                 break;
  880         case MOD_SHUTDOWN:
  881                 break;
  882         default:
  883                 error = EINVAL;
  884                 break;
  885         }
  886         return (error);
  887 }
  888 
  889 static moduledata_t sem_mod = {
  890         "sem",
  891         &sem_modload,
  892         NULL
  893 };
  894 
  895 SYSCALL_MODULE_HELPER(ksem_init);
  896 SYSCALL_MODULE_HELPER(ksem_open);
  897 SYSCALL_MODULE_HELPER(ksem_unlink);
  898 SYSCALL_MODULE_HELPER(ksem_close);
  899 SYSCALL_MODULE_HELPER(ksem_post);
  900 SYSCALL_MODULE_HELPER(ksem_wait);
  901 SYSCALL_MODULE_HELPER(ksem_timedwait);
  902 SYSCALL_MODULE_HELPER(ksem_trywait);
  903 SYSCALL_MODULE_HELPER(ksem_getvalue);
  904 SYSCALL_MODULE_HELPER(ksem_destroy);
  905 
  906 DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
  907 MODULE_VERSION(sem, 1);

Cache object: 4daa331e6621576b4708ceb5b5c7e6ae


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