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: releng/5.3/sys/kern/uipc_sem.c 136588 2004-10-16 08:43:07Z cvs2svn $");
   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         ks->ks_ref++;
  135         DP(("sem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
  136 }
  137 
  138 static __inline
  139 void
  140 sem_rel(struct ksem *ks)
  141 {
  142 
  143         DP(("sem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
  144         if (--ks->ks_ref == 0)
  145                 sem_free(ks);
  146 }
  147 
  148 static __inline struct ksem *id_to_sem(semid_t id);
  149 
  150 static __inline
  151 struct ksem *
  152 id_to_sem(id)
  153         semid_t id;
  154 {
  155         struct ksem *ks;
  156 
  157         DP(("id_to_sem: id = %0x,%p\n", id, (struct ksem *)id));
  158         LIST_FOREACH(ks, &ksem_head, ks_entry) {
  159                 DP(("id_to_sem: ks = %p\n", ks));
  160                 if (ks == (struct ksem *)id)
  161                         return (ks);
  162         }
  163         return (NULL);
  164 }
  165 
  166 static struct ksem *
  167 sem_lookup_byname(name)
  168         const char *name;
  169 {
  170         struct ksem *ks;
  171 
  172         LIST_FOREACH(ks, &ksem_head, ks_entry)
  173                 if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
  174                         return (ks);
  175         return (NULL);
  176 }
  177 
  178 static int
  179 sem_create(td, name, ksret, mode, value)
  180         struct thread *td;
  181         const char *name;
  182         struct ksem **ksret;
  183         mode_t mode;
  184         unsigned int value;
  185 {
  186         struct ksem *ret;
  187         struct proc *p;
  188         struct ucred *uc;
  189         size_t len;
  190         int error;
  191 
  192         DP(("sem_create\n"));
  193         p = td->td_proc;
  194         uc = td->td_ucred;
  195         if (value > SEM_VALUE_MAX)
  196                 return (EINVAL);
  197         ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
  198         if (name != NULL) {
  199                 len = strlen(name);
  200                 if (len > SEM_MAX_NAMELEN) {
  201                         free(ret, M_SEM);
  202                         return (ENAMETOOLONG);
  203                 }
  204                 /* name must start with a '/' but not contain one. */
  205                 if (*name != '/' || len < 2 || index(name + 1, '/') != NULL) {
  206                         free(ret, M_SEM);
  207                         return (EINVAL);
  208                 }
  209                 ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
  210                 strcpy(ret->ks_name, name);
  211         } else {
  212                 ret->ks_name = NULL;
  213         }
  214         ret->ks_mode = mode;
  215         ret->ks_value = value;
  216         ret->ks_ref = 1;
  217         ret->ks_waiters = 0;
  218         ret->ks_uid = uc->cr_uid;
  219         ret->ks_gid = uc->cr_gid;
  220         ret->ks_onlist = 0;
  221         cv_init(&ret->ks_cv, "sem");
  222         LIST_INIT(&ret->ks_users);
  223         if (name != NULL)
  224                 sem_enter(td->td_proc, ret);
  225         *ksret = ret;
  226         mtx_lock(&sem_lock);
  227         if (nsems >= p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX)) {
  228                 sem_leave(td->td_proc, ret);
  229                 sem_free(ret);
  230                 error = ENFILE;
  231         } else {
  232                 nsems++;
  233                 error = 0;
  234         }
  235         mtx_unlock(&sem_lock);
  236         return (error);
  237 }
  238 
  239 #ifndef _SYS_SYSPROTO_H_
  240 struct ksem_init_args {
  241         unsigned int value;
  242         semid_t *idp;
  243 };
  244 int ksem_init(struct thread *td, struct ksem_init_args *uap);
  245 #endif
  246 int
  247 ksem_init(td, uap)
  248         struct thread *td;
  249         struct ksem_init_args *uap;
  250 {
  251         int error;
  252 
  253         error = kern_sem_init(td, UIO_USERSPACE, uap->value, uap->idp);
  254         return (error);
  255 }
  256 
  257 static int
  258 kern_sem_init(td, dir, value, idp)
  259         struct thread *td;
  260         int dir;
  261         unsigned int value;
  262         semid_t *idp;
  263 {
  264         struct ksem *ks;
  265         semid_t id;
  266         int error;
  267 
  268         error = sem_create(td, NULL, &ks, S_IRWXU | S_IRWXG, value);
  269         if (error)
  270                 return (error);
  271         id = SEM_TO_ID(ks);
  272         if (dir == UIO_USERSPACE) {
  273                 error = copyout(&id, idp, sizeof(id));
  274                 if (error) {
  275                         mtx_lock(&sem_lock);
  276                         sem_rel(ks);
  277                         mtx_unlock(&sem_lock);
  278                         return (error);
  279                 }
  280         } else {
  281                 *idp = id;
  282         }
  283         mtx_lock(&sem_lock);
  284         LIST_INSERT_HEAD(&ksem_head, ks, ks_entry);
  285         ks->ks_onlist = 1;
  286         mtx_unlock(&sem_lock);
  287         return (error);
  288 }
  289 
  290 #ifndef _SYS_SYSPROTO_H_
  291 struct ksem_open_args {
  292         char *name;
  293         int oflag;
  294         mode_t mode;
  295         unsigned int value;
  296         semid_t *idp;   
  297 };
  298 int ksem_open(struct thread *td, struct ksem_open_args *uap);
  299 #endif
  300 int
  301 ksem_open(td, uap)
  302         struct thread *td;
  303         struct ksem_open_args *uap;
  304 {
  305         char name[SEM_MAX_NAMELEN + 1];
  306         size_t done;
  307         int error;
  308 
  309         error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
  310         if (error)
  311                 return (error);
  312         DP((">>> sem_open start\n"));
  313         error = kern_sem_open(td, UIO_USERSPACE,
  314             name, uap->oflag, uap->mode, uap->value, uap->idp);
  315         DP(("<<< sem_open end\n"));
  316         return (error);
  317 }
  318 
  319 static int
  320 kern_sem_open(td, dir, name, oflag, mode, value, idp)
  321         struct thread *td;
  322         int dir;
  323         const char *name;
  324         int oflag;
  325         mode_t mode;
  326         unsigned int value;
  327         semid_t *idp;
  328 {
  329         struct ksem *ksnew, *ks;
  330         int error;
  331         semid_t id;
  332 
  333         ksnew = NULL;
  334         mtx_lock(&sem_lock);
  335         ks = sem_lookup_byname(name);
  336         /*
  337          * If we found it but O_EXCL is set, error.
  338          */
  339         if (ks != NULL && (oflag & O_EXCL) != 0) {
  340                 mtx_unlock(&sem_lock);
  341                 return (EEXIST);
  342         }
  343         /*
  344          * If we didn't find it...
  345          */
  346         if (ks == NULL) {
  347                 /*
  348                  * didn't ask for creation? error.
  349                  */
  350                 if ((oflag & O_CREAT) == 0) {
  351                         mtx_unlock(&sem_lock);
  352                         return (ENOENT);
  353                 }
  354                 /*
  355                  * We may block during creation, so drop the lock.
  356                  */
  357                 mtx_unlock(&sem_lock);
  358                 error = sem_create(td, name, &ksnew, mode, value);
  359                 if (error != 0)
  360                         return (error);
  361                 id = SEM_TO_ID(ksnew);
  362                 if (dir == UIO_USERSPACE) {
  363                         DP(("about to copyout! %d to %p\n", id, idp));
  364                         error = copyout(&id, idp, sizeof(id));
  365                         if (error) {
  366                                 mtx_lock(&sem_lock);
  367                                 sem_leave(td->td_proc, ksnew);
  368                                 sem_rel(ksnew);
  369                                 mtx_unlock(&sem_lock);
  370                                 return (error);
  371                         }
  372                 } else {
  373                         DP(("about to set! %d to %p\n", id, idp));
  374                         *idp = id;
  375                 }
  376                 /*
  377                  * We need to make sure we haven't lost a race while
  378                  * allocating during creation.
  379                  */
  380                 mtx_lock(&sem_lock);
  381                 ks = sem_lookup_byname(name);
  382                 if (ks != NULL) {
  383                         /* we lost... */
  384                         sem_leave(td->td_proc, ksnew);
  385                         sem_rel(ksnew);
  386                         /* we lost and we can't loose... */
  387                         if ((oflag & O_EXCL) != 0) {
  388                                 mtx_unlock(&sem_lock);
  389                                 return (EEXIST);
  390                         }
  391                 } else {
  392                         DP(("sem_create: about to add to list...\n"));
  393                         LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry); 
  394                         DP(("sem_create: setting list bit...\n"));
  395                         ksnew->ks_onlist = 1;
  396                         DP(("sem_create: done, about to unlock...\n"));
  397                 }
  398                 mtx_unlock(&sem_lock);
  399         } else {
  400                 /*
  401                  * if we aren't the creator, then enforce permissions.
  402                  */
  403                 error = sem_perm(td, ks);
  404                 if (!error)
  405                         sem_ref(ks);
  406                 mtx_unlock(&sem_lock);
  407                 if (error)
  408                         return (error);
  409                 id = SEM_TO_ID(ks);
  410                 if (dir == UIO_USERSPACE) {
  411                         error = copyout(&id, idp, sizeof(id));
  412                         if (error) {
  413                                 mtx_lock(&sem_lock);
  414                                 sem_rel(ks);
  415                                 mtx_unlock(&sem_lock);
  416                                 return (error);
  417                         }
  418                 } else {
  419                         *idp = id;
  420                 }
  421                 sem_enter(td->td_proc, ks);
  422                 mtx_lock(&sem_lock);
  423                 sem_rel(ks);
  424                 mtx_unlock(&sem_lock);
  425         }
  426         return (error);
  427 }
  428 
  429 static int
  430 sem_perm(td, ks)
  431         struct thread *td;
  432         struct ksem *ks;
  433 {
  434         struct ucred *uc;
  435 
  436         uc = td->td_ucred;
  437         DP(("sem_perm: uc(%d,%d) ks(%d,%d,%o)\n",
  438             uc->cr_uid, uc->cr_gid,
  439              ks->ks_uid, ks->ks_gid, ks->ks_mode));
  440         if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
  441             (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
  442             (ks->ks_mode & S_IWOTH) != 0 || suser(td) == 0)
  443                 return (0);
  444         return (EPERM);
  445 }
  446 
  447 static void
  448 sem_free(struct ksem *ks)
  449 {
  450 
  451         nsems--;
  452         if (ks->ks_onlist)
  453                 LIST_REMOVE(ks, ks_entry);
  454         if (ks->ks_name != NULL)
  455                 free(ks->ks_name, M_SEM);
  456         cv_destroy(&ks->ks_cv);
  457         free(ks, M_SEM);
  458 }
  459 
  460 static __inline struct kuser *sem_getuser(struct proc *p, struct ksem *ks);
  461 
  462 static __inline struct kuser *
  463 sem_getuser(p, ks)
  464         struct proc *p;
  465         struct ksem *ks;
  466 {
  467         struct kuser *k;
  468 
  469         LIST_FOREACH(k, &ks->ks_users, ku_next)
  470                 if (k->ku_pid == p->p_pid)
  471                         return (k);
  472         return (NULL);
  473 }
  474 
  475 static int
  476 sem_hasopen(td, ks)
  477         struct thread *td;
  478         struct ksem *ks;
  479 {
  480         
  481         return ((ks->ks_name == NULL && sem_perm(td, ks) == 0)
  482             || sem_getuser(td->td_proc, ks) != NULL);
  483 }
  484 
  485 static int
  486 sem_leave(p, ks)
  487         struct proc *p;
  488         struct ksem *ks;
  489 {
  490         struct kuser *k;
  491 
  492         DP(("sem_leave: ks = %p\n", ks));
  493         k = sem_getuser(p, ks);
  494         DP(("sem_leave: ks = %p, k = %p\n", ks, k));
  495         if (k != NULL) {
  496                 LIST_REMOVE(k, ku_next);
  497                 sem_rel(ks);
  498                 DP(("sem_leave: about to free k\n"));
  499                 free(k, M_SEM);
  500                 DP(("sem_leave: returning\n"));
  501                 return (0);
  502         }
  503         return (EINVAL);
  504 }
  505 
  506 static void
  507 sem_enter(p, ks)
  508         struct proc *p;
  509         struct ksem *ks;
  510 {
  511         struct kuser *ku, *k;
  512 
  513         ku = malloc(sizeof(*ku), M_SEM, M_WAITOK);
  514         ku->ku_pid = p->p_pid;
  515         mtx_lock(&sem_lock);
  516         k = sem_getuser(p, ks);
  517         if (k != NULL) {
  518                 mtx_unlock(&sem_lock);
  519                 free(ku, M_TEMP);
  520                 return;
  521         }
  522         LIST_INSERT_HEAD(&ks->ks_users, ku, ku_next);
  523         sem_ref(ks);
  524         mtx_unlock(&sem_lock);
  525 }
  526 
  527 #ifndef _SYS_SYSPROTO_H_
  528 struct ksem_unlink_args {
  529         char *name;
  530 };
  531 int ksem_unlink(struct thread *td, struct ksem_unlink_args *uap);
  532 #endif
  533         
  534 int
  535 ksem_unlink(td, uap)
  536         struct thread *td;
  537         struct ksem_unlink_args *uap;
  538 {
  539         char name[SEM_MAX_NAMELEN + 1];
  540         size_t done;
  541         int error;
  542 
  543         error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
  544         return (error ? error :
  545             kern_sem_unlink(td, name));
  546 }
  547 
  548 static int
  549 kern_sem_unlink(td, name)
  550         struct thread *td;
  551         const char *name;
  552 {
  553         struct ksem *ks;
  554         int error;
  555 
  556         mtx_lock(&sem_lock);
  557         ks = sem_lookup_byname(name);
  558         if (ks == NULL)
  559                 error = ENOENT;
  560         else
  561                 error = sem_perm(td, ks);
  562         DP(("sem_unlink: '%s' ks = %p, error = %d\n", name, ks, error));
  563         if (error == 0) {
  564                 LIST_REMOVE(ks, ks_entry);
  565                 LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry); 
  566                 sem_rel(ks);
  567         }
  568         mtx_unlock(&sem_lock);
  569         return (error);
  570 }
  571 
  572 #ifndef _SYS_SYSPROTO_H_
  573 struct ksem_close_args {
  574         semid_t id;
  575 };
  576 int ksem_close(struct thread *td, struct ksem_close_args *uap);
  577 #endif
  578 
  579 int
  580 ksem_close(struct thread *td, struct ksem_close_args *uap)
  581 {
  582 
  583         return (kern_sem_close(td, uap->id));
  584 }
  585 
  586 static int
  587 kern_sem_close(td, id)
  588         struct thread *td;
  589         semid_t id;
  590 {
  591         struct ksem *ks;
  592         int error;
  593 
  594         error = EINVAL;
  595         mtx_lock(&sem_lock);
  596         ks = ID_TO_SEM(id);
  597         /* this is not a valid operation for unnamed sems */
  598         if (ks != NULL && ks->ks_name != NULL)
  599                 error = sem_leave(td->td_proc, ks);
  600         mtx_unlock(&sem_lock);
  601         return (error);
  602 }
  603 
  604 #ifndef _SYS_SYSPROTO_H_
  605 struct ksem_post_args {
  606         semid_t id;
  607 };
  608 int ksem_post(struct thread *td, struct ksem_post_args *uap);
  609 #endif
  610 int
  611 ksem_post(td, uap)
  612         struct thread *td;
  613         struct ksem_post_args *uap;
  614 {
  615 
  616         return (kern_sem_post(td, uap->id));
  617 }
  618 
  619 static int
  620 kern_sem_post(td, id)
  621         struct thread *td;
  622         semid_t id;
  623 {
  624         struct ksem *ks;
  625         int error;
  626 
  627         mtx_lock(&sem_lock);
  628         ks = ID_TO_SEM(id);
  629         if (ks == NULL || !sem_hasopen(td, ks)) {
  630                 error = EINVAL;
  631                 goto err;
  632         }
  633         if (ks->ks_value == SEM_VALUE_MAX) {
  634                 error = EOVERFLOW;
  635                 goto err;
  636         }
  637         ++ks->ks_value;
  638         if (ks->ks_waiters > 0)
  639                 cv_signal(&ks->ks_cv);
  640         error = 0;
  641 err:
  642         mtx_unlock(&sem_lock);
  643         return (error);
  644 }
  645 
  646 #ifndef _SYS_SYSPROTO_H_
  647 struct ksem_wait_args {
  648         semid_t id;
  649 };
  650 int ksem_wait(struct thread *td, struct ksem_wait_args *uap);
  651 #endif
  652 
  653 int
  654 ksem_wait(td, uap)
  655         struct thread *td;
  656         struct ksem_wait_args *uap;
  657 {
  658 
  659         return (kern_sem_wait(td, uap->id, 0, NULL));
  660 }
  661 
  662 #ifndef _SYS_SYSPROTO_H_
  663 struct ksem_timedwait_args {
  664         semid_t id;
  665         struct timespec *abstime;
  666 };
  667 int ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap);
  668 #endif
  669 int
  670 ksem_timedwait(td, uap)
  671         struct thread *td;
  672         struct ksem_timedwait_args *uap;
  673 {
  674         struct timespec abstime;
  675         struct timespec *ts;
  676         int error;
  677 
  678         /* We allow a null timespec (wait forever). */
  679         if (uap->abstime == NULL)
  680                 ts = NULL;
  681         else {
  682                 error = copyin(uap->abstime, &abstime, sizeof(abstime));
  683                 if (error != 0)
  684                         return (error);
  685                 if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
  686                         return (EINVAL);
  687                 ts = &abstime;
  688         }
  689         return (kern_sem_wait(td, uap->id, 0, ts));
  690 }
  691 
  692 #ifndef _SYS_SYSPROTO_H_
  693 struct ksem_trywait_args {
  694         semid_t id;
  695 };
  696 int ksem_trywait(struct thread *td, struct ksem_trywait_args *uap);
  697 #endif
  698 int
  699 ksem_trywait(td, uap)
  700         struct thread *td;
  701         struct ksem_trywait_args *uap;
  702 {
  703 
  704         return (kern_sem_wait(td, uap->id, 1, NULL));
  705 }
  706 
  707 static int
  708 kern_sem_wait(td, id, tryflag, abstime)
  709         struct thread *td;
  710         semid_t id;
  711         int tryflag;
  712         struct timespec *abstime;
  713 {
  714         struct timespec ts1, ts2;
  715         struct timeval tv;
  716         struct ksem *ks;
  717         int error;
  718 
  719         DP((">>> kern_sem_wait entered!\n"));
  720         mtx_lock(&sem_lock);
  721         ks = ID_TO_SEM(id);
  722         if (ks == NULL) {
  723                 DP(("kern_sem_wait ks == NULL\n"));
  724                 error = EINVAL;
  725                 goto err;
  726         }
  727         sem_ref(ks);
  728         if (!sem_hasopen(td, ks)) {
  729                 DP(("kern_sem_wait hasopen failed\n"));
  730                 error = EINVAL;
  731                 goto err;
  732         }
  733         DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
  734         if (ks->ks_value == 0) {
  735                 ks->ks_waiters++;
  736                 if (tryflag != 0)
  737                         error = EAGAIN;
  738                 else if (abstime == NULL)
  739                         error = cv_wait_sig(&ks->ks_cv, &sem_lock);
  740                 else {
  741                         for (;;) {
  742                                 ts1 = *abstime;
  743                                 getnanotime(&ts2);
  744                                 timespecsub(&ts1, &ts2);
  745                                 TIMESPEC_TO_TIMEVAL(&tv, &ts1);
  746                                 if (tv.tv_sec < 0) {
  747                                         error = ETIMEDOUT;
  748                                         break;
  749                                 }
  750                                 error = cv_timedwait_sig(&ks->ks_cv,
  751                                     &sem_lock, tvtohz(&tv));
  752                                 if (error != EWOULDBLOCK)
  753                                         break;
  754                         }
  755                 }
  756                 ks->ks_waiters--;
  757                 if (error)
  758                         goto err;
  759         }
  760         ks->ks_value--;
  761         error = 0;
  762 err:
  763         if (ks != NULL)
  764                 sem_rel(ks);
  765         mtx_unlock(&sem_lock);
  766         DP(("<<< kern_sem_wait leaving, error = %d\n", error));
  767         return (error);
  768 }
  769 
  770 #ifndef _SYS_SYSPROTO_H_
  771 struct ksem_getvalue_args {
  772         semid_t id;
  773         int *val;
  774 };
  775 int ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap);
  776 #endif
  777 int
  778 ksem_getvalue(td, uap)
  779         struct thread *td;
  780         struct ksem_getvalue_args *uap;
  781 {
  782         struct ksem *ks;
  783         int error, val;
  784 
  785         mtx_lock(&sem_lock);
  786         ks = ID_TO_SEM(uap->id);
  787         if (ks == NULL || !sem_hasopen(td, ks)) {
  788                 mtx_unlock(&sem_lock);
  789                 return (EINVAL);
  790         }
  791         val = ks->ks_value;
  792         mtx_unlock(&sem_lock);
  793         error = copyout(&val, uap->val, sizeof(val));
  794         return (error);
  795 }
  796 
  797 #ifndef _SYS_SYSPROTO_H_
  798 struct ksem_destroy_args {
  799         semid_t id;
  800 };
  801 int ksem_destroy(struct thread *td, struct ksem_destroy_args *uap);
  802 #endif
  803 int
  804 ksem_destroy(td, uap)
  805         struct thread *td;
  806         struct ksem_destroy_args *uap;
  807 {
  808         struct ksem *ks;
  809         int error;
  810 
  811         mtx_lock(&sem_lock);
  812         ks = ID_TO_SEM(uap->id);
  813         if (ks == NULL || !sem_hasopen(td, ks) ||
  814             ks->ks_name != NULL) {
  815                 error = EINVAL;
  816                 goto err;
  817         }
  818         if (ks->ks_waiters != 0) {
  819                 error = EBUSY;
  820                 goto err;
  821         }
  822         sem_rel(ks);
  823         error = 0;
  824 err:
  825         mtx_unlock(&sem_lock);
  826         return (error);
  827 }
  828 
  829 static void
  830 sem_exithook(arg, p)
  831         void *arg;
  832         struct proc *p;
  833 {
  834         struct ksem *ks, *ksnext;
  835 
  836         mtx_lock(&sem_lock);
  837         ks = LIST_FIRST(&ksem_head);
  838         while (ks != NULL) {
  839                 ksnext = LIST_NEXT(ks, ks_entry);
  840                 sem_leave(p, ks);
  841                 ks = ksnext;
  842         }
  843         ks = LIST_FIRST(&ksem_deadhead);
  844         while (ks != NULL) {
  845                 ksnext = LIST_NEXT(ks, ks_entry);
  846                 sem_leave(p, ks);
  847                 ks = ksnext;
  848         }
  849         mtx_unlock(&sem_lock);
  850 }
  851 
  852 static int
  853 sem_modload(struct module *module, int cmd, void *arg)
  854 {
  855         int error = 0;
  856 
  857         switch (cmd) {
  858         case MOD_LOAD:
  859                 mtx_init(&sem_lock, "sem", "semaphore", MTX_DEF);
  860                 p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
  861                 p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
  862                 sem_exit_tag = EVENTHANDLER_REGISTER(process_exit, sem_exithook,
  863                     NULL, EVENTHANDLER_PRI_ANY);
  864                 sem_exec_tag = EVENTHANDLER_REGISTER(process_exec, sem_exithook,
  865                     NULL, EVENTHANDLER_PRI_ANY);
  866                 break;
  867         case MOD_UNLOAD:
  868                 if (nsems != 0) {
  869                         error = EOPNOTSUPP;
  870                         break;
  871                 }
  872                 EVENTHANDLER_DEREGISTER(process_exit, sem_exit_tag);
  873                 EVENTHANDLER_DEREGISTER(process_exec, sem_exec_tag);
  874                 mtx_destroy(&sem_lock);
  875                 break;
  876         case MOD_SHUTDOWN:
  877                 break;
  878         default:
  879                 error = EINVAL;
  880                 break;
  881         }
  882         return (error);
  883 }
  884 
  885 static moduledata_t sem_mod = {
  886         "sem",
  887         &sem_modload,
  888         NULL
  889 };
  890 
  891 SYSCALL_MODULE_HELPER(ksem_init);
  892 SYSCALL_MODULE_HELPER(ksem_open);
  893 SYSCALL_MODULE_HELPER(ksem_unlink);
  894 SYSCALL_MODULE_HELPER(ksem_close);
  895 SYSCALL_MODULE_HELPER(ksem_post);
  896 SYSCALL_MODULE_HELPER(ksem_wait);
  897 SYSCALL_MODULE_HELPER(ksem_timedwait);
  898 SYSCALL_MODULE_HELPER(ksem_trywait);
  899 SYSCALL_MODULE_HELPER(ksem_getvalue);
  900 SYSCALL_MODULE_HELPER(ksem_destroy);
  901 
  902 DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
  903 MODULE_VERSION(sem, 1);

Cache object: 77630e3bdfc856125a79acf44452ad06


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