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

Cache object: 07a67f045891f47ddd8c3e844b9f123b


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