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/sysv_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 /* $FreeBSD: releng/5.1/sys/kern/sysv_sem.c 112564 2003-03-24 21:15:35Z jhb $ */
    2 
    3 /*
    4  * Implementation of SVID semaphores
    5  *
    6  * Author:  Daniel Boulet
    7  *
    8  * This software is provided ``AS IS'' without any warranties of any kind.
    9  */
   10 
   11 #include "opt_sysvipc.h"
   12 
   13 #include <sys/param.h>
   14 #include <sys/systm.h>
   15 #include <sys/sysproto.h>
   16 #include <sys/eventhandler.h>
   17 #include <sys/kernel.h>
   18 #include <sys/proc.h>
   19 #include <sys/lock.h>
   20 #include <sys/mutex.h>
   21 #include <sys/sem.h>
   22 #include <sys/syscall.h>
   23 #include <sys/sysent.h>
   24 #include <sys/sysctl.h>
   25 #include <sys/malloc.h>
   26 #include <sys/jail.h>
   27 
   28 static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");
   29 
   30 #ifdef SEM_DEBUG
   31 #define DPRINTF(a)      printf a
   32 #else
   33 #define DPRINTF(a)
   34 #endif
   35 
   36 static void seminit(void);
   37 static int sysvsem_modload(struct module *, int, void *);
   38 static int semunload(void);
   39 static void semexit_myhook(void *arg, struct proc *p);
   40 static int sysctl_sema(SYSCTL_HANDLER_ARGS);
   41 static int semvalid(int semid, struct semid_ds *semaptr);
   42 
   43 #ifndef _SYS_SYSPROTO_H_
   44 struct __semctl_args;
   45 int __semctl(struct thread *td, struct __semctl_args *uap);
   46 struct semget_args;
   47 int semget(struct thread *td, struct semget_args *uap);
   48 struct semop_args;
   49 int semop(struct thread *td, struct semop_args *uap);
   50 #endif
   51 
   52 static struct sem_undo *semu_alloc(struct thread *td);
   53 static int semundo_adjust(struct thread *td, struct sem_undo **supptr, 
   54                 int semid, int semnum, int adjval);
   55 static void semundo_clear(int semid, int semnum);
   56 
   57 /* XXX casting to (sy_call_t *) is bogus, as usual. */
   58 static sy_call_t *semcalls[] = {
   59         (sy_call_t *)__semctl, (sy_call_t *)semget,
   60         (sy_call_t *)semop
   61 };
   62 
   63 static struct mtx       sem_mtx;        /* semaphore global lock */
   64 static int      semtot = 0;
   65 static struct semid_ds *sema;   /* semaphore id pool */
   66 static struct mtx *sema_mtx;    /* semaphore id pool mutexes*/
   67 static struct sem *sem;         /* semaphore pool */
   68 SLIST_HEAD(, sem_undo) semu_list;       /* list of active undo structures */
   69 static int      *semu;          /* undo structure pool */
   70 static eventhandler_tag semexit_tag;
   71 
   72 #define SEMUNDO_MTX             sem_mtx
   73 #define SEMUNDO_LOCK()          mtx_lock(&SEMUNDO_MTX);
   74 #define SEMUNDO_UNLOCK()        mtx_unlock(&SEMUNDO_MTX);
   75 #define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how));
   76 
   77 struct sem {
   78         u_short semval;         /* semaphore value */
   79         pid_t   sempid;         /* pid of last operation */
   80         u_short semncnt;        /* # awaiting semval > cval */
   81         u_short semzcnt;        /* # awaiting semval = 0 */
   82 };
   83 
   84 /*
   85  * Undo structure (one per process)
   86  */
   87 struct sem_undo {
   88         SLIST_ENTRY(sem_undo) un_next;  /* ptr to next active undo structure */
   89         struct  proc *un_proc;          /* owner of this structure */
   90         short   un_cnt;                 /* # of active entries */
   91         struct undo {
   92                 short   un_adjval;      /* adjust on exit values */
   93                 short   un_num;         /* semaphore # */
   94                 int     un_id;          /* semid */
   95         } un_ent[1];                    /* undo entries */
   96 };
   97 
   98 /*
   99  * Configuration parameters
  100  */
  101 #ifndef SEMMNI
  102 #define SEMMNI  10              /* # of semaphore identifiers */
  103 #endif
  104 #ifndef SEMMNS
  105 #define SEMMNS  60              /* # of semaphores in system */
  106 #endif
  107 #ifndef SEMUME
  108 #define SEMUME  10              /* max # of undo entries per process */
  109 #endif
  110 #ifndef SEMMNU
  111 #define SEMMNU  30              /* # of undo structures in system */
  112 #endif
  113 
  114 /* shouldn't need tuning */
  115 #ifndef SEMMAP
  116 #define SEMMAP  30              /* # of entries in semaphore map */
  117 #endif
  118 #ifndef SEMMSL
  119 #define SEMMSL  SEMMNS          /* max # of semaphores per id */
  120 #endif
  121 #ifndef SEMOPM
  122 #define SEMOPM  100             /* max # of operations per semop call */
  123 #endif
  124 
  125 #define SEMVMX  32767           /* semaphore maximum value */
  126 #define SEMAEM  16384           /* adjust on exit max value */
  127 
  128 /*
  129  * Due to the way semaphore memory is allocated, we have to ensure that
  130  * SEMUSZ is properly aligned.
  131  */
  132 
  133 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
  134 
  135 /* actual size of an undo structure */
  136 #define SEMUSZ  SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
  137 
  138 /*
  139  * Macro to find a particular sem_undo vector
  140  */
  141 #define SEMU(ix) \
  142         ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
  143 
  144 /*
  145  * semaphore info struct
  146  */
  147 struct seminfo seminfo = {
  148                 SEMMAP,         /* # of entries in semaphore map */
  149                 SEMMNI,         /* # of semaphore identifiers */
  150                 SEMMNS,         /* # of semaphores in system */
  151                 SEMMNU,         /* # of undo structures in system */
  152                 SEMMSL,         /* max # of semaphores per id */
  153                 SEMOPM,         /* max # of operations per semop call */
  154                 SEMUME,         /* max # of undo entries per process */
  155                 SEMUSZ,         /* size in bytes of undo structure */
  156                 SEMVMX,         /* semaphore maximum value */
  157                 SEMAEM          /* adjust on exit max value */
  158 };
  159 
  160 SYSCTL_DECL(_kern_ipc);
  161 SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, "");
  162 SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RD, &seminfo.semmni, 0, "");
  163 SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RD, &seminfo.semmns, 0, "");
  164 SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RD, &seminfo.semmnu, 0, "");
  165 SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, "");
  166 SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RD, &seminfo.semopm, 0, "");
  167 SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RD, &seminfo.semume, 0, "");
  168 SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, "");
  169 SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, "");
  170 SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, "");
  171 SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD,
  172     NULL, 0, sysctl_sema, "", "");
  173 
  174 static void
  175 seminit(void)
  176 {
  177         int i;
  178 
  179         TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap);
  180         TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
  181         TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
  182         TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
  183         TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
  184         TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
  185         TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
  186         TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
  187         TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
  188         TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
  189 
  190         sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
  191         sema = malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM,
  192             M_WAITOK);
  193         sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM,
  194             M_WAITOK | M_ZERO);
  195         semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
  196 
  197         for (i = 0; i < seminfo.semmni; i++) {
  198                 sema[i].sem_base = 0;
  199                 sema[i].sem_perm.mode = 0;
  200         }
  201         for (i = 0; i < seminfo.semmni; i++)
  202                 mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF);
  203         for (i = 0; i < seminfo.semmnu; i++) {
  204                 struct sem_undo *suptr = SEMU(i);
  205                 suptr->un_proc = NULL;
  206         }
  207         SLIST_INIT(&semu_list);
  208         mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
  209         semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
  210             EVENTHANDLER_PRI_ANY);
  211 }
  212 
  213 static int
  214 semunload(void)
  215 {
  216         int i;
  217 
  218         if (semtot != 0)
  219                 return (EBUSY);
  220 
  221         EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
  222         free(sem, M_SEM);
  223         free(sema, M_SEM);
  224         free(semu, M_SEM);
  225         for (i = 0; i < seminfo.semmni; i++)
  226                 mtx_destroy(&sema_mtx[i]);
  227         mtx_destroy(&sem_mtx);
  228         return (0);
  229 }
  230 
  231 static int
  232 sysvsem_modload(struct module *module, int cmd, void *arg)
  233 {
  234         int error = 0;
  235 
  236         switch (cmd) {
  237         case MOD_LOAD:
  238                 seminit();
  239                 break;
  240         case MOD_UNLOAD:
  241                 error = semunload();
  242                 break;
  243         case MOD_SHUTDOWN:
  244                 break;
  245         default:
  246                 error = EINVAL;
  247                 break;
  248         }
  249         return (error);
  250 }
  251 
  252 static moduledata_t sysvsem_mod = {
  253         "sysvsem",
  254         &sysvsem_modload,
  255         NULL
  256 };
  257 
  258 SYSCALL_MODULE_HELPER(semsys);
  259 SYSCALL_MODULE_HELPER(__semctl);
  260 SYSCALL_MODULE_HELPER(semget);
  261 SYSCALL_MODULE_HELPER(semop);
  262 
  263 DECLARE_MODULE(sysvsem, sysvsem_mod,
  264         SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
  265 MODULE_VERSION(sysvsem, 1);
  266 
  267 /*
  268  * Entry point for all SEM calls
  269  *
  270  * MPSAFE
  271  */
  272 int
  273 semsys(td, uap)
  274         struct thread *td;
  275         /* XXX actually varargs. */
  276         struct semsys_args /* {
  277                 u_int   which;
  278                 int     a2;
  279                 int     a3;
  280                 int     a4;
  281                 int     a5;
  282         } */ *uap;
  283 {
  284         int error;
  285 
  286         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  287                 return (ENOSYS);
  288         if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
  289                 return (EINVAL);
  290         error = (*semcalls[uap->which])(td, &uap->a2);
  291         return (error);
  292 }
  293 
  294 /*
  295  * Allocate a new sem_undo structure for a process
  296  * (returns ptr to structure or NULL if no more room)
  297  */
  298 
  299 static struct sem_undo *
  300 semu_alloc(td)
  301         struct thread *td;
  302 {
  303         int i;
  304         struct sem_undo *suptr;
  305         struct sem_undo **supptr;
  306         int attempt;
  307 
  308         SEMUNDO_LOCKASSERT(MA_OWNED);
  309         /*
  310          * Try twice to allocate something.
  311          * (we'll purge any empty structures after the first pass so
  312          * two passes are always enough)
  313          */
  314 
  315         for (attempt = 0; attempt < 2; attempt++) {
  316                 /*
  317                  * Look for a free structure.
  318                  * Fill it in and return it if we find one.
  319                  */
  320 
  321                 for (i = 0; i < seminfo.semmnu; i++) {
  322                         suptr = SEMU(i);
  323                         if (suptr->un_proc == NULL) {
  324                                 SLIST_INSERT_HEAD(&semu_list, suptr, un_next);
  325                                 suptr->un_cnt = 0;
  326                                 suptr->un_proc = td->td_proc;
  327                                 return(suptr);
  328                         }
  329                 }
  330 
  331                 /*
  332                  * We didn't find a free one, if this is the first attempt
  333                  * then try to free some structures.
  334                  */
  335 
  336                 if (attempt == 0) {
  337                         /* All the structures are in use - try to free some */
  338                         int did_something = 0;
  339 
  340                         SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list,
  341                             un_next) {
  342                                 if (suptr->un_cnt == 0) {
  343                                         suptr->un_proc = NULL;
  344                                         did_something = 1;
  345                                         *supptr = SLIST_NEXT(suptr, un_next);
  346                                 }
  347                         }
  348 
  349                         /* If we didn't free anything then just give-up */
  350                         if (!did_something)
  351                                 return(NULL);
  352                 } else {
  353                         /*
  354                          * The second pass failed even though we freed
  355                          * something after the first pass!
  356                          * This is IMPOSSIBLE!
  357                          */
  358                         panic("semu_alloc - second attempt failed");
  359                 }
  360         }
  361         return (NULL);
  362 }
  363 
  364 /*
  365  * Adjust a particular entry for a particular proc
  366  */
  367 
  368 static int
  369 semundo_adjust(td, supptr, semid, semnum, adjval)
  370         struct thread *td;
  371         struct sem_undo **supptr;
  372         int semid, semnum;
  373         int adjval;
  374 {
  375         struct proc *p = td->td_proc;
  376         struct sem_undo *suptr;
  377         struct undo *sunptr;
  378         int i;
  379 
  380         SEMUNDO_LOCKASSERT(MA_OWNED);
  381         /* Look for and remember the sem_undo if the caller doesn't provide
  382            it */
  383 
  384         suptr = *supptr;
  385         if (suptr == NULL) {
  386                 SLIST_FOREACH(suptr, &semu_list, un_next) {
  387                         if (suptr->un_proc == p) {
  388                                 *supptr = suptr;
  389                                 break;
  390                         }
  391                 }
  392                 if (suptr == NULL) {
  393                         if (adjval == 0)
  394                                 return(0);
  395                         suptr = semu_alloc(td);
  396                         if (suptr == NULL)
  397                                 return(ENOSPC);
  398                         *supptr = suptr;
  399                 }
  400         }
  401 
  402         /*
  403          * Look for the requested entry and adjust it (delete if adjval becomes
  404          * 0).
  405          */
  406         sunptr = &suptr->un_ent[0];
  407         for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
  408                 if (sunptr->un_id != semid || sunptr->un_num != semnum)
  409                         continue;
  410                 if (adjval != 0) {
  411                         adjval += sunptr->un_adjval;
  412                         if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
  413                                 return (ERANGE);
  414                 }
  415                 sunptr->un_adjval = adjval;
  416                 if (sunptr->un_adjval == 0) {
  417                         suptr->un_cnt--;
  418                         if (i < suptr->un_cnt)
  419                                 suptr->un_ent[i] =
  420                                     suptr->un_ent[suptr->un_cnt];
  421                 }
  422                 return(0);
  423         }
  424 
  425         /* Didn't find the right entry - create it */
  426         if (adjval == 0)
  427                 return(0);
  428         if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
  429                 return (ERANGE);
  430         if (suptr->un_cnt != seminfo.semume) {
  431                 sunptr = &suptr->un_ent[suptr->un_cnt];
  432                 suptr->un_cnt++;
  433                 sunptr->un_adjval = adjval;
  434                 sunptr->un_id = semid; sunptr->un_num = semnum;
  435         } else
  436                 return(EINVAL);
  437         return(0);
  438 }
  439 
  440 static void
  441 semundo_clear(semid, semnum)
  442         int semid, semnum;
  443 {
  444         struct sem_undo *suptr;
  445 
  446         SEMUNDO_LOCKASSERT(MA_OWNED);
  447         SLIST_FOREACH(suptr, &semu_list, un_next) {
  448                 struct undo *sunptr = &suptr->un_ent[0];
  449                 int i = 0;
  450 
  451                 while (i < suptr->un_cnt) {
  452                         if (sunptr->un_id == semid) {
  453                                 if (semnum == -1 || sunptr->un_num == semnum) {
  454                                         suptr->un_cnt--;
  455                                         if (i < suptr->un_cnt) {
  456                                                 suptr->un_ent[i] =
  457                                                   suptr->un_ent[suptr->un_cnt];
  458                                                 continue;
  459                                         }
  460                                 }
  461                                 if (semnum != -1)
  462                                         break;
  463                         }
  464                         i++, sunptr++;
  465                 }
  466         }
  467 }
  468 
  469 static int
  470 semvalid(semid, semaptr)
  471         int semid;
  472         struct semid_ds *semaptr;
  473 {
  474 
  475         return ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
  476             semaptr->sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0);
  477 }
  478 
  479 /*
  480  * Note that the user-mode half of this passes a union, not a pointer
  481  */
  482 #ifndef _SYS_SYSPROTO_H_
  483 struct __semctl_args {
  484         int     semid;
  485         int     semnum;
  486         int     cmd;
  487         union   semun *arg;
  488 };
  489 #endif
  490 
  491 /*
  492  * MPSAFE
  493  */
  494 int
  495 __semctl(td, uap)
  496         struct thread *td;
  497         struct __semctl_args *uap;
  498 {
  499         int semid = uap->semid;
  500         int semnum = uap->semnum;
  501         int cmd = uap->cmd;
  502         u_short *array;
  503         union semun *arg = uap->arg;
  504         union semun real_arg;
  505         struct ucred *cred = td->td_ucred;
  506         int i, rval, error;
  507         struct semid_ds sbuf;
  508         struct semid_ds *semaptr;
  509         struct mtx *sema_mtxp;
  510         u_short usval, count;
  511 
  512         DPRINTF(("call to semctl(%d, %d, %d, 0x%x)\n",
  513             semid, semnum, cmd, arg));
  514         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  515                 return (ENOSYS);
  516 
  517         array = NULL;
  518 
  519         switch(cmd) {
  520         case SEM_STAT:
  521                 if (semid < 0 || semid >= seminfo.semmni)
  522                         return (EINVAL);
  523                 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  524                         return (error);
  525                 semaptr = &sema[semid];
  526                 sema_mtxp = &sema_mtx[semid];
  527                 mtx_lock(sema_mtxp);
  528                 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) {
  529                         error = EINVAL;
  530                         goto done2;
  531                 }
  532                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
  533                         goto done2;
  534                 mtx_unlock(sema_mtxp);
  535                 error = copyout(semaptr, real_arg.buf, sizeof(struct semid_ds));
  536                 rval = IXSEQ_TO_IPCID(semid,semaptr->sem_perm);
  537                 if (error == 0)
  538                         td->td_retval[0] = rval;
  539                 return (error);
  540         }
  541 
  542         semid = IPCID_TO_IX(semid);
  543         if (semid < 0 || semid >= seminfo.semmni)
  544                 return (EINVAL);
  545 
  546         semaptr = &sema[semid];
  547         sema_mtxp = &sema_mtx[semid];
  548                 
  549         error = 0;
  550         rval = 0;
  551 
  552         switch (cmd) {
  553         case IPC_RMID:
  554                 mtx_lock(sema_mtxp);
  555                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  556                         goto done2;
  557                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
  558                         goto done2;
  559                 semaptr->sem_perm.cuid = cred->cr_uid;
  560                 semaptr->sem_perm.uid = cred->cr_uid;
  561                 semtot -= semaptr->sem_nsems;
  562                 for (i = semaptr->sem_base - sem; i < semtot; i++)
  563                         sem[i] = sem[i + semaptr->sem_nsems];
  564                 for (i = 0; i < seminfo.semmni; i++) {
  565                         if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
  566                             sema[i].sem_base > semaptr->sem_base)
  567                                 sema[i].sem_base -= semaptr->sem_nsems;
  568                 }
  569                 semaptr->sem_perm.mode = 0;
  570                 SEMUNDO_LOCK();
  571                 semundo_clear(semid, -1);
  572                 SEMUNDO_UNLOCK();
  573                 wakeup(semaptr);
  574                 break;
  575 
  576         case IPC_SET:
  577                 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  578                         goto done2;
  579                 if ((error = copyin(real_arg.buf, &sbuf, sizeof(sbuf))) != 0)
  580                         goto done2;
  581                 mtx_lock(sema_mtxp);
  582                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  583                         goto done2;
  584                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
  585                         goto done2;
  586                 semaptr->sem_perm.uid = sbuf.sem_perm.uid;
  587                 semaptr->sem_perm.gid = sbuf.sem_perm.gid;
  588                 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
  589                     (sbuf.sem_perm.mode & 0777);
  590                 semaptr->sem_ctime = time_second;
  591                 break;
  592 
  593         case IPC_STAT:
  594                 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  595                         goto done2;
  596                 mtx_lock(sema_mtxp);
  597                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  598                         goto done2;
  599                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
  600                         goto done2;
  601                 sbuf = *semaptr;
  602                 mtx_unlock(sema_mtxp);
  603                 error = copyout(semaptr, real_arg.buf,
  604                                 sizeof(struct semid_ds));
  605                 break;
  606 
  607         case GETNCNT:
  608                 mtx_lock(sema_mtxp);
  609                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  610                         goto done2;
  611                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
  612                         goto done2;
  613                 if (semnum < 0 || semnum >= semaptr->sem_nsems) {
  614                         error = EINVAL;
  615                         goto done2;
  616                 }
  617                 rval = semaptr->sem_base[semnum].semncnt;
  618                 break;
  619 
  620         case GETPID:
  621                 mtx_lock(sema_mtxp);
  622                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  623                         goto done2;
  624                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
  625                         goto done2;
  626                 if (semnum < 0 || semnum >= semaptr->sem_nsems) {
  627                         error = EINVAL;
  628                         goto done2;
  629                 }
  630                 rval = semaptr->sem_base[semnum].sempid;
  631                 break;
  632 
  633         case GETVAL:
  634                 mtx_lock(sema_mtxp);
  635                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  636                         goto done2;
  637                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
  638                         goto done2;
  639                 if (semnum < 0 || semnum >= semaptr->sem_nsems) {
  640                         error = EINVAL;
  641                         goto done2;
  642                 }
  643                 rval = semaptr->sem_base[semnum].semval;
  644                 break;
  645 
  646         case GETALL:
  647                 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  648                         goto done2;
  649                 array = malloc(sizeof(*array) * semaptr->sem_nsems, M_TEMP,
  650                     M_WAITOK);
  651                 mtx_lock(sema_mtxp);
  652                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  653                         goto done2;
  654                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
  655                         goto done2;
  656                 for (i = 0; i < semaptr->sem_nsems; i++)
  657                         array[i] = semaptr->sem_base[i].semval;
  658                 mtx_unlock(sema_mtxp);
  659                 error = copyout(array, real_arg.array,
  660                     i * sizeof(real_arg.array[0]));
  661                 break;
  662 
  663         case GETZCNT:
  664                 mtx_lock(sema_mtxp);
  665                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  666                         goto done2;
  667                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
  668                         goto done2;
  669                 if (semnum < 0 || semnum >= semaptr->sem_nsems) {
  670                         error = EINVAL;
  671                         goto done2;
  672                 }
  673                 rval = semaptr->sem_base[semnum].semzcnt;
  674                 break;
  675 
  676         case SETVAL:
  677                 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  678                         goto done2;
  679                 mtx_lock(sema_mtxp);
  680                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  681                         goto done2;
  682                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
  683                         goto done2;
  684                 if (semnum < 0 || semnum >= semaptr->sem_nsems) {
  685                         error = EINVAL;
  686                         goto done2;
  687                 }
  688                 if (real_arg.val < 0 || real_arg.val > seminfo.semvmx) {
  689                         error = ERANGE;
  690                         goto done2;
  691                 }
  692                 semaptr->sem_base[semnum].semval = real_arg.val;
  693                 SEMUNDO_LOCK();
  694                 semundo_clear(semid, semnum);
  695                 SEMUNDO_UNLOCK();
  696                 wakeup(semaptr);
  697                 break;
  698 
  699         case SETALL:
  700                 mtx_lock(sema_mtxp);
  701 raced:
  702                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  703                         goto done2;
  704                 count = semaptr->sem_nsems;
  705                 mtx_unlock(sema_mtxp);
  706                 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  707                         goto done2;
  708                 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
  709                 copyin(real_arg.array, array, count * sizeof(*array));
  710                 if (error)
  711                         break;
  712                 mtx_lock(sema_mtxp);
  713                 if ((error = semvalid(uap->semid, semaptr)) != 0)
  714                         goto done2;
  715                 /* we could have raced? */
  716                 if (count != semaptr->sem_nsems) {
  717                         free(array, M_TEMP);
  718                         array = NULL;
  719                         goto raced;
  720                 }
  721                 if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
  722                         goto done2;
  723                 for (i = 0; i < semaptr->sem_nsems; i++) {
  724                         usval = array[i];
  725                         if (usval > seminfo.semvmx) {
  726                                 error = ERANGE;
  727                                 break;
  728                         }
  729                         semaptr->sem_base[i].semval = usval;
  730                 }
  731                 SEMUNDO_LOCK();
  732                 semundo_clear(semid, -1);
  733                 SEMUNDO_UNLOCK();
  734                 wakeup(semaptr);
  735                 break;
  736 
  737         default:
  738                 error = EINVAL;
  739                 break;
  740         }
  741 
  742         if (error == 0)
  743                 td->td_retval[0] = rval;
  744 done2:
  745         if (mtx_owned(sema_mtxp))
  746                 mtx_unlock(sema_mtxp);
  747         if (array != NULL)
  748                 free(array, M_TEMP);
  749         return(error);
  750 }
  751 
  752 #ifndef _SYS_SYSPROTO_H_
  753 struct semget_args {
  754         key_t   key;
  755         int     nsems;
  756         int     semflg;
  757 };
  758 #endif
  759 
  760 /*
  761  * MPSAFE
  762  */
  763 int
  764 semget(td, uap)
  765         struct thread *td;
  766         struct semget_args *uap;
  767 {
  768         int semid, error = 0;
  769         int key = uap->key;
  770         int nsems = uap->nsems;
  771         int semflg = uap->semflg;
  772         struct ucred *cred = td->td_ucred;
  773 
  774         DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
  775         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  776                 return (ENOSYS);
  777 
  778         mtx_lock(&Giant);
  779         if (key != IPC_PRIVATE) {
  780                 for (semid = 0; semid < seminfo.semmni; semid++) {
  781                         if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
  782                             sema[semid].sem_perm.key == key)
  783                                 break;
  784                 }
  785                 if (semid < seminfo.semmni) {
  786                         DPRINTF(("found public key\n"));
  787                         if ((error = ipcperm(td, &sema[semid].sem_perm,
  788                             semflg & 0700))) {
  789                                 goto done2;
  790                         }
  791                         if (nsems > 0 && sema[semid].sem_nsems < nsems) {
  792                                 DPRINTF(("too small\n"));
  793                                 error = EINVAL;
  794                                 goto done2;
  795                         }
  796                         if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
  797                                 DPRINTF(("not exclusive\n"));
  798                                 error = EEXIST;
  799                                 goto done2;
  800                         }
  801                         goto found;
  802                 }
  803         }
  804 
  805         DPRINTF(("need to allocate the semid_ds\n"));
  806         if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
  807                 if (nsems <= 0 || nsems > seminfo.semmsl) {
  808                         DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
  809                             seminfo.semmsl));
  810                         error = EINVAL;
  811                         goto done2;
  812                 }
  813                 if (nsems > seminfo.semmns - semtot) {
  814                         DPRINTF((
  815                             "not enough semaphores left (need %d, got %d)\n",
  816                             nsems, seminfo.semmns - semtot));
  817                         error = ENOSPC;
  818                         goto done2;
  819                 }
  820                 for (semid = 0; semid < seminfo.semmni; semid++) {
  821                         if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
  822                                 break;
  823                 }
  824                 if (semid == seminfo.semmni) {
  825                         DPRINTF(("no more semid_ds's available\n"));
  826                         error = ENOSPC;
  827                         goto done2;
  828                 }
  829                 DPRINTF(("semid %d is available\n", semid));
  830                 sema[semid].sem_perm.key = key;
  831                 sema[semid].sem_perm.cuid = cred->cr_uid;
  832                 sema[semid].sem_perm.uid = cred->cr_uid;
  833                 sema[semid].sem_perm.cgid = cred->cr_gid;
  834                 sema[semid].sem_perm.gid = cred->cr_gid;
  835                 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
  836                 sema[semid].sem_perm.seq =
  837                     (sema[semid].sem_perm.seq + 1) & 0x7fff;
  838                 sema[semid].sem_nsems = nsems;
  839                 sema[semid].sem_otime = 0;
  840                 sema[semid].sem_ctime = time_second;
  841                 sema[semid].sem_base = &sem[semtot];
  842                 semtot += nsems;
  843                 bzero(sema[semid].sem_base,
  844                     sizeof(sema[semid].sem_base[0])*nsems);
  845                 DPRINTF(("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
  846                     &sem[semtot]));
  847         } else {
  848                 DPRINTF(("didn't find it and wasn't asked to create it\n"));
  849                 error = ENOENT;
  850                 goto done2;
  851         }
  852 
  853 found:
  854         td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
  855 done2:
  856         mtx_unlock(&Giant);
  857         return (error);
  858 }
  859 
  860 #ifndef _SYS_SYSPROTO_H_
  861 struct semop_args {
  862         int     semid;
  863         struct  sembuf *sops;
  864         size_t  nsops;
  865 };
  866 #endif
  867 
  868 /*
  869  * MPSAFE
  870  */
  871 int
  872 semop(td, uap)
  873         struct thread *td;
  874         struct semop_args *uap;
  875 {
  876         int semid = uap->semid;
  877         size_t nsops = uap->nsops;
  878         struct sembuf *sops;
  879         struct semid_ds *semaptr;
  880         struct sembuf *sopptr = 0;
  881         struct sem *semptr = 0;
  882         struct sem_undo *suptr;
  883         struct mtx *sema_mtxp;
  884         size_t i, j, k;
  885         int error;
  886         int do_wakeup, do_undos;
  887 
  888         DPRINTF(("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops));
  889 
  890         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  891                 return (ENOSYS);
  892 
  893         semid = IPCID_TO_IX(semid);     /* Convert back to zero origin */
  894 
  895         if (semid < 0 || semid >= seminfo.semmni)
  896                 return (EINVAL);
  897 
  898         /* Allocate memory for sem_ops */
  899         if (nsops > seminfo.semopm) {
  900                 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
  901                     nsops));
  902                 return (E2BIG);
  903         }
  904         sops = malloc(nsops * sizeof(sops[0]), M_SEM, M_WAITOK);
  905         if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
  906                 DPRINTF(("error = %d from copyin(%08x, %08x, %d)\n", error,
  907                     uap->sops, sops, nsops * sizeof(sops[0])));
  908                 free(sops, M_SEM);
  909                 return (error);
  910         }
  911 
  912         semaptr = &sema[semid];
  913         sema_mtxp = &sema_mtx[semid];
  914         mtx_lock(sema_mtxp);
  915         if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) {
  916                 error = EINVAL;
  917                 goto done2;
  918         }
  919         if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
  920                 error = EINVAL;
  921                 goto done2;
  922         }
  923         /*
  924          * Initial pass thru sops to see what permissions are needed.
  925          * Also perform any checks that don't need repeating on each
  926          * attempt to satisfy the request vector.
  927          */
  928         j = 0;          /* permission needed */
  929         do_undos = 0;
  930         for (i = 0; i < nsops; i++) {
  931                 sopptr = &sops[i];
  932                 if (sopptr->sem_num >= semaptr->sem_nsems) {
  933                         error = EFBIG;
  934                         goto done2;
  935                 }
  936                 if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
  937                         do_undos = 1;
  938                 j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
  939         }
  940 
  941         if ((error = ipcperm(td, &semaptr->sem_perm, j))) {
  942                 DPRINTF(("error = %d from ipaccess\n", error));
  943                 goto done2;
  944         }
  945 
  946         /*
  947          * Loop trying to satisfy the vector of requests.
  948          * If we reach a point where we must wait, any requests already
  949          * performed are rolled back and we go to sleep until some other
  950          * process wakes us up.  At this point, we start all over again.
  951          *
  952          * This ensures that from the perspective of other tasks, a set
  953          * of requests is atomic (never partially satisfied).
  954          */
  955         for (;;) {
  956                 do_wakeup = 0;
  957                 error = 0;      /* error return if necessary */
  958 
  959                 for (i = 0; i < nsops; i++) {
  960                         sopptr = &sops[i];
  961                         semptr = &semaptr->sem_base[sopptr->sem_num];
  962 
  963                         DPRINTF((
  964                             "semop:  semaptr=%x, sem_base=%x, "
  965                             "semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
  966                             semaptr, semaptr->sem_base, semptr,
  967                             sopptr->sem_num, semptr->semval, sopptr->sem_op,
  968                             (sopptr->sem_flg & IPC_NOWAIT) ?
  969                             "nowait" : "wait"));
  970 
  971                         if (sopptr->sem_op < 0) {
  972                                 if (semptr->semval + sopptr->sem_op < 0) {
  973                                         DPRINTF(("semop:  can't do it now\n"));
  974                                         break;
  975                                 } else {
  976                                         semptr->semval += sopptr->sem_op;
  977                                         if (semptr->semval == 0 &&
  978                                             semptr->semzcnt > 0)
  979                                                 do_wakeup = 1;
  980                                 }
  981                         } else if (sopptr->sem_op == 0) {
  982                                 if (semptr->semval != 0) {
  983                                         DPRINTF(("semop:  not zero now\n"));
  984                                         break;
  985                                 }
  986                         } else if (semptr->semval + sopptr->sem_op >
  987                             seminfo.semvmx) {
  988                                 error = ERANGE;
  989                                 break;
  990                         } else {
  991                                 if (semptr->semncnt > 0)
  992                                         do_wakeup = 1;
  993                                 semptr->semval += sopptr->sem_op;
  994                         }
  995                 }
  996 
  997                 /*
  998                  * Did we get through the entire vector?
  999                  */
 1000                 if (i >= nsops)
 1001                         goto done;
 1002 
 1003                 /*
 1004                  * No ... rollback anything that we've already done
 1005                  */
 1006                 DPRINTF(("semop:  rollback 0 through %d\n", i-1));
 1007                 for (j = 0; j < i; j++)
 1008                         semaptr->sem_base[sops[j].sem_num].semval -=
 1009                             sops[j].sem_op;
 1010 
 1011                 /* If we detected an error, return it */
 1012                 if (error != 0)
 1013                         goto done2;
 1014 
 1015                 /*
 1016                  * If the request that we couldn't satisfy has the
 1017                  * NOWAIT flag set then return with EAGAIN.
 1018                  */
 1019                 if (sopptr->sem_flg & IPC_NOWAIT) {
 1020                         error = EAGAIN;
 1021                         goto done2;
 1022                 }
 1023 
 1024                 if (sopptr->sem_op == 0)
 1025                         semptr->semzcnt++;
 1026                 else
 1027                         semptr->semncnt++;
 1028 
 1029                 DPRINTF(("semop:  good night!\n"));
 1030                 error = msleep(semaptr, sema_mtxp, (PZERO - 4) | PCATCH,
 1031                     "semwait", 0);
 1032                 DPRINTF(("semop:  good morning (error=%d)!\n", error));
 1033 
 1034                 if (error != 0) {
 1035                         error = EINTR;
 1036                         goto done2;
 1037                 }
 1038                 DPRINTF(("semop:  good morning!\n"));
 1039 
 1040                 /*
 1041                  * Make sure that the semaphore still exists
 1042                  */
 1043                 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
 1044                     semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
 1045                         error = EIDRM;
 1046                         goto done2;
 1047                 }
 1048 
 1049                 /*
 1050                  * The semaphore is still alive.  Readjust the count of
 1051                  * waiting processes.
 1052                  */
 1053                 if (sopptr->sem_op == 0)
 1054                         semptr->semzcnt--;
 1055                 else
 1056                         semptr->semncnt--;
 1057         }
 1058 
 1059 done:
 1060         /*
 1061          * Process any SEM_UNDO requests.
 1062          */
 1063         if (do_undos) {
 1064                 SEMUNDO_LOCK();
 1065                 suptr = NULL;
 1066                 for (i = 0; i < nsops; i++) {
 1067                         /*
 1068                          * We only need to deal with SEM_UNDO's for non-zero
 1069                          * op's.
 1070                          */
 1071                         int adjval;
 1072 
 1073                         if ((sops[i].sem_flg & SEM_UNDO) == 0)
 1074                                 continue;
 1075                         adjval = sops[i].sem_op;
 1076                         if (adjval == 0)
 1077                                 continue;
 1078                         error = semundo_adjust(td, &suptr, semid,
 1079                             sops[i].sem_num, -adjval);
 1080                         if (error == 0)
 1081                                 continue;
 1082 
 1083                         /*
 1084                          * Oh-Oh!  We ran out of either sem_undo's or undo's.
 1085                          * Rollback the adjustments to this point and then
 1086                          * rollback the semaphore ups and down so we can return
 1087                          * with an error with all structures restored.  We
 1088                          * rollback the undo's in the exact reverse order that
 1089                          * we applied them.  This guarantees that we won't run
 1090                          * out of space as we roll things back out.
 1091                          */
 1092                         for (j = 0; j < i; j++) {
 1093                                 k = i - j - 1;
 1094                                 if ((sops[k].sem_flg & SEM_UNDO) == 0)
 1095                                         continue;
 1096                                 adjval = sops[k].sem_op;
 1097                                 if (adjval == 0)
 1098                                         continue;
 1099                                 if (semundo_adjust(td, &suptr, semid,
 1100                                     sops[k].sem_num, adjval) != 0)
 1101                                         panic("semop - can't undo undos");
 1102                         }
 1103 
 1104                         for (j = 0; j < nsops; j++)
 1105                                 semaptr->sem_base[sops[j].sem_num].semval -=
 1106                                     sops[j].sem_op;
 1107 
 1108                         DPRINTF(("error = %d from semundo_adjust\n", error));
 1109                         SEMUNDO_UNLOCK();
 1110                         goto done2;
 1111                 } /* loop through the sops */
 1112                 SEMUNDO_UNLOCK();
 1113         } /* if (do_undos) */
 1114 
 1115         /* We're definitely done - set the sempid's and time */
 1116         for (i = 0; i < nsops; i++) {
 1117                 sopptr = &sops[i];
 1118                 semptr = &semaptr->sem_base[sopptr->sem_num];
 1119                 semptr->sempid = td->td_proc->p_pid;
 1120         }
 1121         semaptr->sem_otime = time_second;
 1122 
 1123         /*
 1124          * Do a wakeup if any semaphore was up'd whilst something was
 1125          * sleeping on it.
 1126          */
 1127         if (do_wakeup) {
 1128                 DPRINTF(("semop:  doing wakeup\n"));
 1129                 wakeup(semaptr);
 1130                 DPRINTF(("semop:  back from wakeup\n"));
 1131         }
 1132         DPRINTF(("semop:  done\n"));
 1133         td->td_retval[0] = 0;
 1134 done2:
 1135         mtx_unlock(sema_mtxp);
 1136         free(sops, M_SEM);
 1137         return (error);
 1138 }
 1139 
 1140 /*
 1141  * Go through the undo structures for this process and apply the adjustments to
 1142  * semaphores.
 1143  */
 1144 static void
 1145 semexit_myhook(arg, p)
 1146         void *arg;
 1147         struct proc *p;
 1148 {
 1149         struct sem_undo *suptr;
 1150         struct sem_undo **supptr;
 1151 
 1152         /*
 1153          * Go through the chain of undo vectors looking for one
 1154          * associated with this process.
 1155          */
 1156         SEMUNDO_LOCK();
 1157         SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) {
 1158                 if (suptr->un_proc == p)
 1159                         break;
 1160         }
 1161         SEMUNDO_UNLOCK();
 1162 
 1163         if (suptr == NULL)
 1164                 return;
 1165 
 1166         DPRINTF(("proc @%08x has undo structure with %d entries\n", p,
 1167             suptr->un_cnt));
 1168 
 1169         /*
 1170          * If there are any active undo elements then process them.
 1171          */
 1172         if (suptr->un_cnt > 0) {
 1173                 int ix;
 1174 
 1175                 for (ix = 0; ix < suptr->un_cnt; ix++) {
 1176                         int semid = suptr->un_ent[ix].un_id;
 1177                         int semnum = suptr->un_ent[ix].un_num;
 1178                         int adjval = suptr->un_ent[ix].un_adjval;
 1179                         struct semid_ds *semaptr;
 1180                         struct mtx *sema_mtxp;
 1181 
 1182                         semaptr = &sema[semid];
 1183                         sema_mtxp = &sema_mtx[semid];
 1184                         mtx_lock(sema_mtxp);
 1185                         SEMUNDO_LOCK();
 1186                         if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
 1187                                 panic("semexit - semid not allocated");
 1188                         if (semnum >= semaptr->sem_nsems)
 1189                                 panic("semexit - semnum out of range");
 1190 
 1191                         DPRINTF((
 1192                             "semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
 1193                             suptr->un_proc, suptr->un_ent[ix].un_id,
 1194                             suptr->un_ent[ix].un_num,
 1195                             suptr->un_ent[ix].un_adjval,
 1196                             semaptr->sem_base[semnum].semval));
 1197 
 1198                         if (adjval < 0) {
 1199                                 if (semaptr->sem_base[semnum].semval < -adjval)
 1200                                         semaptr->sem_base[semnum].semval = 0;
 1201                                 else
 1202                                         semaptr->sem_base[semnum].semval +=
 1203                                             adjval;
 1204                         } else
 1205                                 semaptr->sem_base[semnum].semval += adjval;
 1206 
 1207                         wakeup(semaptr);
 1208                         DPRINTF(("semexit:  back from wakeup\n"));
 1209                         mtx_unlock(sema_mtxp);
 1210                         SEMUNDO_UNLOCK();
 1211                 }
 1212         }
 1213 
 1214         /*
 1215          * Deallocate the undo vector.
 1216          */
 1217         DPRINTF(("removing vector\n"));
 1218         suptr->un_proc = NULL;
 1219         *supptr = SLIST_NEXT(suptr, un_next);
 1220 }
 1221 
 1222 static int
 1223 sysctl_sema(SYSCTL_HANDLER_ARGS)
 1224 {
 1225 
 1226         return (SYSCTL_OUT(req, sema,
 1227             sizeof(struct semid_ds) * seminfo.semmni));
 1228 }

Cache object: 240173ce02d6ca1a14a7208a1b04f517


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