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

Cache object: 39ccb7a0f3d2e76d375ebcac6e650fc4


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