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

Cache object: c169d922390d3763b0011bb60bc3619c


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