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

Cache object: fa24602160f8355fd3e551eecd0ed0bc


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