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

Cache object: e2470af9af74b8c58bcb40c4b668004c


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