The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/sysv_sem.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $FreeBSD: src/sys/kern/sysv_sem.c,v 1.16.2.2 2000/05/01 11:29:44 peter Exp $ */
    2 
    3 /*
    4  * Implementation of SVID semaphores
    5  *
    6  * Author:  Daniel Boulet
    7  *
    8  * This software is provided ``AS IS'' without any warranties of any kind.
    9  */
   10 
   11 #include "opt_sysvipc.h"
   12 
   13 #include <sys/param.h>
   14 #include <sys/systm.h>
   15 #include <sys/sysproto.h>
   16 #include <sys/kernel.h>
   17 #include <sys/proc.h>
   18 #include <sys/sem.h>
   19 #include <sys/sysent.h>
   20 
   21 static void seminit __P((void *));
   22 SYSINIT(sysv_sem, SI_SUB_SYSV_SEM, SI_ORDER_FIRST, seminit, NULL)
   23 
   24 #ifndef _SYS_SYSPROTO_H_
   25 struct __semctl_args;
   26 int __semctl __P((struct proc *p, struct __semctl_args *uap, int *retval));
   27 struct semget_args;
   28 int semget __P((struct proc *p, struct semget_args *uap, int *retval));
   29 struct semop_args;
   30 int semop __P((struct proc *p, struct semop_args *uap, int *retval));
   31 #endif
   32 
   33 static struct sem_undo *semu_alloc __P((struct proc *p));
   34 static int semundo_adjust __P((struct proc *p, struct sem_undo **supptr, 
   35                 int semid, int semnum, int adjval));
   36 static void semundo_clear __P((int semid, int semnum));
   37 
   38 /* XXX casting to (sy_call_t *) is bogus, as usual. */
   39 static sy_call_t *semcalls[] = {
   40         (sy_call_t *)__semctl, (sy_call_t *)semget,
   41         (sy_call_t *)semop
   42 };
   43 
   44 static int      semtot = 0;
   45 struct semid_ds *sema;          /* semaphore id pool */
   46 struct sem *sem;                /* semaphore pool */
   47 static struct sem_undo *semu_list;      /* list of active undo structures */
   48 int     *semu;                  /* undo structure pool */
   49 
   50 void
   51 seminit(dummy)
   52         void *dummy;
   53 {
   54         register int i;
   55 
   56         if (sema == NULL)
   57                 panic("sema is NULL");
   58         if (semu == NULL)
   59                 panic("semu is NULL");
   60 
   61         for (i = 0; i < seminfo.semmni; i++) {
   62                 sema[i].sem_base = 0;
   63                 sema[i].sem_perm.mode = 0;
   64         }
   65         for (i = 0; i < seminfo.semmnu; i++) {
   66                 register struct sem_undo *suptr = SEMU(i);
   67                 suptr->un_proc = NULL;
   68         }
   69         semu_list = NULL;
   70 }
   71 
   72 /*
   73  * Entry point for all SEM calls
   74  */
   75 int
   76 semsys(p, uap, retval)
   77         struct proc *p;
   78         /* XXX actually varargs. */
   79         struct semsys_args /* {
   80                 u_int   which;
   81                 int     a2;
   82                 int     a3;
   83                 int     a4;
   84                 int     a5;
   85         } */ *uap;
   86         int *retval;
   87 {
   88 
   89         if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
   90                 return (EINVAL);
   91         return ((*semcalls[uap->which])(p, &uap->a2, retval));
   92 }
   93 
   94 /*
   95  * Allocate a new sem_undo structure for a process
   96  * (returns ptr to structure or NULL if no more room)
   97  */
   98 
   99 static struct sem_undo *
  100 semu_alloc(p)
  101         struct proc *p;
  102 {
  103         register int i;
  104         register struct sem_undo *suptr;
  105         register struct sem_undo **supptr;
  106         int attempt;
  107 
  108         /*
  109          * Try twice to allocate something.
  110          * (we'll purge any empty structures after the first pass so
  111          * two passes are always enough)
  112          */
  113 
  114         for (attempt = 0; attempt < 2; attempt++) {
  115                 /*
  116                  * Look for a free structure.
  117                  * Fill it in and return it if we find one.
  118                  */
  119 
  120                 for (i = 0; i < seminfo.semmnu; i++) {
  121                         suptr = SEMU(i);
  122                         if (suptr->un_proc == NULL) {
  123                                 suptr->un_next = semu_list;
  124                                 semu_list = suptr;
  125                                 suptr->un_cnt = 0;
  126                                 suptr->un_proc = p;
  127                                 return(suptr);
  128                         }
  129                 }
  130 
  131                 /*
  132                  * We didn't find a free one, if this is the first attempt
  133                  * then try to free some structures.
  134                  */
  135 
  136                 if (attempt == 0) {
  137                         /* All the structures are in use - try to free some */
  138                         int did_something = 0;
  139 
  140                         supptr = &semu_list;
  141                         while ((suptr = *supptr) != NULL) {
  142                                 if (suptr->un_cnt == 0)  {
  143                                         suptr->un_proc = NULL;
  144                                         *supptr = suptr->un_next;
  145                                         did_something = 1;
  146                                 } else
  147                                         supptr = &(suptr->un_next);
  148                         }
  149 
  150                         /* If we didn't free anything then just give-up */
  151                         if (!did_something)
  152                                 return(NULL);
  153                 } else {
  154                         /*
  155                          * The second pass failed even though we freed
  156                          * something after the first pass!
  157                          * This is IMPOSSIBLE!
  158                          */
  159                         panic("semu_alloc - second attempt failed");
  160                 }
  161         }
  162         return (NULL);
  163 }
  164 
  165 /*
  166  * Adjust a particular entry for a particular proc
  167  */
  168 
  169 static int
  170 semundo_adjust(p, supptr, semid, semnum, adjval)
  171         register struct proc *p;
  172         struct sem_undo **supptr;
  173         int semid, semnum;
  174         int adjval;
  175 {
  176         register struct sem_undo *suptr;
  177         register struct undo *sunptr;
  178         int i;
  179 
  180         /* Look for and remember the sem_undo if the caller doesn't provide
  181            it */
  182 
  183         suptr = *supptr;
  184         if (suptr == NULL) {
  185                 for (suptr = semu_list; suptr != NULL;
  186                     suptr = suptr->un_next) {
  187                         if (suptr->un_proc == p) {
  188                                 *supptr = suptr;
  189                                 break;
  190                         }
  191                 }
  192                 if (suptr == NULL) {
  193                         if (adjval == 0)
  194                                 return(0);
  195                         suptr = semu_alloc(p);
  196                         if (suptr == NULL)
  197                                 return(ENOSPC);
  198                         *supptr = suptr;
  199                 }
  200         }
  201 
  202         /*
  203          * Look for the requested entry and adjust it (delete if adjval becomes
  204          * 0).
  205          */
  206         sunptr = &suptr->un_ent[0];
  207         for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
  208                 if (sunptr->un_id != semid || sunptr->un_num != semnum)
  209                         continue;
  210                 if (adjval == 0)
  211                         sunptr->un_adjval = 0;
  212                 else
  213                         sunptr->un_adjval += adjval;
  214                 if (sunptr->un_adjval == 0) {
  215                         suptr->un_cnt--;
  216                         if (i < suptr->un_cnt)
  217                                 suptr->un_ent[i] =
  218                                     suptr->un_ent[suptr->un_cnt];
  219                 }
  220                 return(0);
  221         }
  222 
  223         /* Didn't find the right entry - create it */
  224         if (adjval == 0)
  225                 return(0);
  226         if (suptr->un_cnt != SEMUME) {
  227                 sunptr = &suptr->un_ent[suptr->un_cnt];
  228                 suptr->un_cnt++;
  229                 sunptr->un_adjval = adjval;
  230                 sunptr->un_id = semid; sunptr->un_num = semnum;
  231         } else
  232                 return(EINVAL);
  233         return(0);
  234 }
  235 
  236 static void
  237 semundo_clear(semid, semnum)
  238         int semid, semnum;
  239 {
  240         register struct sem_undo *suptr;
  241 
  242         for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
  243                 register struct undo *sunptr = &suptr->un_ent[0];
  244                 register int i = 0;
  245 
  246                 while (i < suptr->un_cnt) {
  247                         if (sunptr->un_id == semid) {
  248                                 if (semnum == -1 || sunptr->un_num == semnum) {
  249                                         suptr->un_cnt--;
  250                                         if (i < suptr->un_cnt) {
  251                                                 suptr->un_ent[i] =
  252                                                   suptr->un_ent[suptr->un_cnt];
  253                                                 continue;
  254                                         }
  255                                 }
  256                                 if (semnum != -1)
  257                                         break;
  258                         }
  259                         i++, sunptr++;
  260                 }
  261         }
  262 }
  263 
  264 /*
  265  * Note that the user-mode half of this passes a union, not a pointer
  266  */
  267 #ifndef _SYS_SYSPROTO_H_
  268 struct __semctl_args {
  269         int     semid;
  270         int     semnum;
  271         int     cmd;
  272         union   semun *arg;
  273 };
  274 #endif
  275 
  276 int
  277 __semctl(p, uap, retval)
  278         struct proc *p;
  279         register struct __semctl_args *uap;
  280         int *retval;
  281 {
  282         int semid = uap->semid;
  283         int semnum = uap->semnum;
  284         int cmd = uap->cmd;
  285         union semun *arg = uap->arg;
  286         union semun real_arg;
  287         struct ucred *cred = p->p_ucred;
  288         int i, rval, eval;
  289         struct semid_ds sbuf;
  290         register struct semid_ds *semaptr;
  291 
  292 #ifdef SEM_DEBUG
  293         printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
  294 #endif
  295 
  296         semid = IPCID_TO_IX(semid);
  297         if (semid < 0 || semid >= seminfo.semmsl)
  298                 return(EINVAL);
  299 
  300         semaptr = &sema[semid];
  301         if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
  302             semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
  303                 return(EINVAL);
  304 
  305         eval = 0;
  306         rval = 0;
  307 
  308         switch (cmd) {
  309         case IPC_RMID:
  310                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
  311                         return(eval);
  312                 semaptr->sem_perm.cuid = cred->cr_uid;
  313                 semaptr->sem_perm.uid = cred->cr_uid;
  314                 semtot -= semaptr->sem_nsems;
  315                 for (i = semaptr->sem_base - sem; i < semtot; i++)
  316                         sem[i] = sem[i + semaptr->sem_nsems];
  317                 for (i = 0; i < seminfo.semmni; i++) {
  318                         if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
  319                             sema[i].sem_base > semaptr->sem_base)
  320                                 sema[i].sem_base -= semaptr->sem_nsems;
  321                 }
  322                 semaptr->sem_perm.mode = 0;
  323                 semundo_clear(semid, -1);
  324                 wakeup((caddr_t)semaptr);
  325                 break;
  326 
  327         case IPC_SET:
  328                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
  329                         return(eval);
  330                 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  331                         return(eval);
  332                 if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf,
  333                     sizeof(sbuf))) != 0)
  334                         return(eval);
  335                 semaptr->sem_perm.uid = sbuf.sem_perm.uid;
  336                 semaptr->sem_perm.gid = sbuf.sem_perm.gid;
  337                 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
  338                     (sbuf.sem_perm.mode & 0777);
  339                 semaptr->sem_ctime = time.tv_sec;
  340                 break;
  341 
  342         case IPC_STAT:
  343                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
  344                         return(eval);
  345                 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  346                         return(eval);
  347                 eval = copyout((caddr_t)semaptr, real_arg.buf,
  348                     sizeof(struct semid_ds));
  349                 break;
  350 
  351         case GETNCNT:
  352                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
  353                         return(eval);
  354                 if (semnum < 0 || semnum >= semaptr->sem_nsems)
  355                         return(EINVAL);
  356                 rval = semaptr->sem_base[semnum].semncnt;
  357                 break;
  358 
  359         case GETPID:
  360                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
  361                         return(eval);
  362                 if (semnum < 0 || semnum >= semaptr->sem_nsems)
  363                         return(EINVAL);
  364                 rval = semaptr->sem_base[semnum].sempid;
  365                 break;
  366 
  367         case GETVAL:
  368                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
  369                         return(eval);
  370                 if (semnum < 0 || semnum >= semaptr->sem_nsems)
  371                         return(EINVAL);
  372                 rval = semaptr->sem_base[semnum].semval;
  373                 break;
  374 
  375         case GETALL:
  376                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
  377                         return(eval);
  378                 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  379                         return(eval);
  380                 for (i = 0; i < semaptr->sem_nsems; i++) {
  381                         eval = copyout((caddr_t)&semaptr->sem_base[i].semval,
  382                             &real_arg.array[i], sizeof(real_arg.array[0]));
  383                         if (eval != 0)
  384                                 break;
  385                 }
  386                 break;
  387 
  388         case GETZCNT:
  389                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
  390                         return(eval);
  391                 if (semnum < 0 || semnum >= semaptr->sem_nsems)
  392                         return(EINVAL);
  393                 rval = semaptr->sem_base[semnum].semzcnt;
  394                 break;
  395 
  396         case SETVAL:
  397                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
  398                         return(eval);
  399                 if (semnum < 0 || semnum >= semaptr->sem_nsems)
  400                         return(EINVAL);
  401                 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  402                         return(eval);
  403                 semaptr->sem_base[semnum].semval = real_arg.val;
  404                 semundo_clear(semid, semnum);
  405                 wakeup((caddr_t)semaptr);
  406                 break;
  407 
  408         case SETALL:
  409                 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
  410                         return(eval);
  411                 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
  412                         return(eval);
  413                 for (i = 0; i < semaptr->sem_nsems; i++) {
  414                         eval = copyin(&real_arg.array[i],
  415                             (caddr_t)&semaptr->sem_base[i].semval,
  416                             sizeof(real_arg.array[0]));
  417                         if (eval != 0)
  418                                 break;
  419                 }
  420                 semundo_clear(semid, -1);
  421                 wakeup((caddr_t)semaptr);
  422                 break;
  423 
  424         default:
  425                 return(EINVAL);
  426         }
  427 
  428         if (eval == 0)
  429                 *retval = rval;
  430         return(eval);
  431 }
  432 
  433 #ifndef _SYS_SYSPROTO_H_
  434 struct semget_args {
  435         key_t   key;
  436         int     nsems;
  437         int     semflg;
  438 };
  439 #endif
  440 
  441 int
  442 semget(p, uap, retval)
  443         struct proc *p;
  444         register struct semget_args *uap;
  445         int *retval;
  446 {
  447         int semid, eval;
  448         int key = uap->key;
  449         int nsems = uap->nsems;
  450         int semflg = uap->semflg;
  451         struct ucred *cred = p->p_ucred;
  452 
  453 #ifdef SEM_DEBUG
  454         printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
  455 #endif
  456 
  457         if (key != IPC_PRIVATE) {
  458                 for (semid = 0; semid < seminfo.semmni; semid++) {
  459                         if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
  460                             sema[semid].sem_perm.key == key)
  461                                 break;
  462                 }
  463                 if (semid < seminfo.semmni) {
  464 #ifdef SEM_DEBUG
  465                         printf("found public key\n");
  466 #endif
  467                         if ((eval = ipcperm(cred, &sema[semid].sem_perm,
  468                             semflg & 0700)))
  469                                 return(eval);
  470                         if (nsems > 0 && sema[semid].sem_nsems < nsems) {
  471 #ifdef SEM_DEBUG
  472                                 printf("too small\n");
  473 #endif
  474                                 return(EINVAL);
  475                         }
  476                         if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
  477 #ifdef SEM_DEBUG
  478                                 printf("not exclusive\n");
  479 #endif
  480                                 return(EEXIST);
  481                         }
  482                         goto found;
  483                 }
  484         }
  485 
  486 #ifdef SEM_DEBUG
  487         printf("need to allocate the semid_ds\n");
  488 #endif
  489         if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
  490                 if (nsems <= 0 || nsems > seminfo.semmsl) {
  491 #ifdef SEM_DEBUG
  492                         printf("nsems out of range (0<%d<=%d)\n", nsems,
  493                             seminfo.semmsl);
  494 #endif
  495                         return(EINVAL);
  496                 }
  497                 if (nsems > seminfo.semmns - semtot) {
  498 #ifdef SEM_DEBUG
  499                         printf("not enough semaphores left (need %d, got %d)\n",
  500                             nsems, seminfo.semmns - semtot);
  501 #endif
  502                         return(ENOSPC);
  503                 }
  504                 for (semid = 0; semid < seminfo.semmni; semid++) {
  505                         if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
  506                                 break;
  507                 }
  508                 if (semid == seminfo.semmni) {
  509 #ifdef SEM_DEBUG
  510                         printf("no more semid_ds's available\n");
  511 #endif
  512                         return(ENOSPC);
  513                 }
  514 #ifdef SEM_DEBUG
  515                 printf("semid %d is available\n", semid);
  516 #endif
  517                 sema[semid].sem_perm.key = key;
  518                 sema[semid].sem_perm.cuid = cred->cr_uid;
  519                 sema[semid].sem_perm.uid = cred->cr_uid;
  520                 sema[semid].sem_perm.cgid = cred->cr_gid;
  521                 sema[semid].sem_perm.gid = cred->cr_gid;
  522                 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
  523                 sema[semid].sem_perm.seq =
  524                     (sema[semid].sem_perm.seq + 1) & 0x7fff;
  525                 sema[semid].sem_nsems = nsems;
  526                 sema[semid].sem_otime = 0;
  527                 sema[semid].sem_ctime = time.tv_sec;
  528                 sema[semid].sem_base = &sem[semtot];
  529                 semtot += nsems;
  530                 bzero(sema[semid].sem_base,
  531                     sizeof(sema[semid].sem_base[0])*nsems);
  532 #ifdef SEM_DEBUG
  533                 printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
  534                     &sem[semtot]);
  535 #endif
  536         } else {
  537 #ifdef SEM_DEBUG
  538                 printf("didn't find it and wasn't asked to create it\n");
  539 #endif
  540                 return(ENOENT);
  541         }
  542 
  543 found:
  544         *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
  545         return(0);
  546 }
  547 
  548 #ifndef _SYS_SYSPROTO_H_
  549 struct semop_args {
  550         int     semid;
  551         struct  sembuf *sops;
  552         int     nsops;
  553 };
  554 #endif
  555 
  556 int
  557 semop(p, uap, retval)
  558         struct proc *p;
  559         register struct semop_args *uap;
  560         int *retval;
  561 {
  562         int semid = uap->semid;
  563         int nsops = uap->nsops;
  564         struct sembuf sops[MAX_SOPS];
  565         register struct semid_ds *semaptr;
  566         register struct sembuf *sopptr;
  567         register struct sem *semptr;
  568         struct sem_undo *suptr = NULL;
  569         struct ucred *cred = p->p_ucred;
  570         int i, j, eval;
  571         int do_wakeup, do_undos;
  572 
  573 #ifdef SEM_DEBUG
  574         printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
  575 #endif
  576 
  577         semid = IPCID_TO_IX(semid);     /* Convert back to zero origin */
  578 
  579         if (semid < 0 || semid >= seminfo.semmsl)
  580                 return(EINVAL);
  581 
  582         semaptr = &sema[semid];
  583         if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
  584                 return(EINVAL);
  585         if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
  586                 return(EINVAL);
  587 
  588         if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
  589 #ifdef SEM_DEBUG
  590                 printf("eval = %d from ipaccess\n", eval);
  591 #endif
  592                 return(eval);
  593         }
  594 
  595         if (nsops > MAX_SOPS) {
  596 #ifdef SEM_DEBUG
  597                 printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
  598 #endif
  599                 return(E2BIG);
  600         }
  601 
  602         if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) {
  603 #ifdef SEM_DEBUG
  604                 printf("eval = %d from copyin(%08x, %08x, %d)\n", eval,
  605                     uap->sops, &sops, nsops * sizeof(sops[0]));
  606 #endif
  607                 return(eval);
  608         }
  609 
  610         /*
  611          * Loop trying to satisfy the vector of requests.
  612          * If we reach a point where we must wait, any requests already
  613          * performed are rolled back and we go to sleep until some other
  614          * process wakes us up.  At this point, we start all over again.
  615          *
  616          * This ensures that from the perspective of other tasks, a set
  617          * of requests is atomic (never partially satisfied).
  618          */
  619         do_undos = 0;
  620 
  621         for (;;) {
  622                 do_wakeup = 0;
  623 
  624                 for (i = 0; i < nsops; i++) {
  625                         sopptr = &sops[i];
  626 
  627                         if (sopptr->sem_num >= semaptr->sem_nsems)
  628                                 return(EFBIG);
  629 
  630                         semptr = &semaptr->sem_base[sopptr->sem_num];
  631 
  632 #ifdef SEM_DEBUG
  633                         printf("semop:  semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
  634                             semaptr, semaptr->sem_base, semptr,
  635                             sopptr->sem_num, semptr->semval, sopptr->sem_op,
  636                             (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
  637 #endif
  638 
  639                         if (sopptr->sem_op < 0) {
  640                                 if (semptr->semval + sopptr->sem_op < 0) {
  641 #ifdef SEM_DEBUG
  642                                         printf("semop:  can't do it now\n");
  643 #endif
  644                                         break;
  645                                 } else {
  646                                         semptr->semval += sopptr->sem_op;
  647                                         if (semptr->semval == 0 &&
  648                                             semptr->semzcnt > 0)
  649                                                 do_wakeup = 1;
  650                                 }
  651                                 if (sopptr->sem_flg & SEM_UNDO)
  652                                         do_undos = 1;
  653                         } else if (sopptr->sem_op == 0) {
  654                                 if (semptr->semval > 0) {
  655 #ifdef SEM_DEBUG
  656                                         printf("semop:  not zero now\n");
  657 #endif
  658                                         break;
  659                                 }
  660                         } else {
  661                                 if (semptr->semncnt > 0)
  662                                         do_wakeup = 1;
  663                                 semptr->semval += sopptr->sem_op;
  664                                 if (sopptr->sem_flg & SEM_UNDO)
  665                                         do_undos = 1;
  666                         }
  667                 }
  668 
  669                 /*
  670                  * Did we get through the entire vector?
  671                  */
  672                 if (i >= nsops)
  673                         goto done;
  674 
  675                 /*
  676                  * No ... rollback anything that we've already done
  677                  */
  678 #ifdef SEM_DEBUG
  679                 printf("semop:  rollback 0 through %d\n", i-1);
  680 #endif
  681                 for (j = 0; j < i; j++)
  682                         semaptr->sem_base[sops[j].sem_num].semval -=
  683                             sops[j].sem_op;
  684 
  685                 /*
  686                  * If the request that we couldn't satisfy has the
  687                  * NOWAIT flag set then return with EAGAIN.
  688                  */
  689                 if (sopptr->sem_flg & IPC_NOWAIT)
  690                         return(EAGAIN);
  691 
  692                 if (sopptr->sem_op == 0)
  693                         semptr->semzcnt++;
  694                 else
  695                         semptr->semncnt++;
  696 
  697 #ifdef SEM_DEBUG
  698                 printf("semop:  good night!\n");
  699 #endif
  700                 eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
  701                     "semwait", 0);
  702 #ifdef SEM_DEBUG
  703                 printf("semop:  good morning (eval=%d)!\n", eval);
  704 #endif
  705 
  706                 suptr = NULL;   /* sem_undo may have been reallocated */
  707 
  708                 if (eval != 0)
  709                         return(EINTR);
  710 #ifdef SEM_DEBUG
  711                 printf("semop:  good morning!\n");
  712 #endif
  713 
  714                 /*
  715                  * Make sure that the semaphore still exists
  716                  */
  717                 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
  718                     semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
  719                         /* The man page says to return EIDRM. */
  720                         /* Unfortunately, BSD doesn't define that code! */
  721 #ifdef EIDRM
  722                         return(EIDRM);
  723 #else
  724                         return(EINVAL);
  725 #endif
  726                 }
  727 
  728                 /*
  729                  * The semaphore is still alive.  Readjust the count of
  730                  * waiting processes.
  731                  */
  732                 if (sopptr->sem_op == 0)
  733                         semptr->semzcnt--;
  734                 else
  735                         semptr->semncnt--;
  736         }
  737 
  738 done:
  739         /*
  740          * Process any SEM_UNDO requests.
  741          */
  742         if (do_undos) {
  743                 for (i = 0; i < nsops; i++) {
  744                         /*
  745                          * We only need to deal with SEM_UNDO's for non-zero
  746                          * op's.
  747                          */
  748                         int adjval;
  749 
  750                         if ((sops[i].sem_flg & SEM_UNDO) == 0)
  751                                 continue;
  752                         adjval = sops[i].sem_op;
  753                         if (adjval == 0)
  754                                 continue;
  755                         eval = semundo_adjust(p, &suptr, semid,
  756                             sops[i].sem_num, -adjval);
  757                         if (eval == 0)
  758                                 continue;
  759 
  760                         /*
  761                          * Oh-Oh!  We ran out of either sem_undo's or undo's.
  762                          * Rollback the adjustments to this point and then
  763                          * rollback the semaphore ups and down so we can return
  764                          * with an error with all structures restored.  We
  765                          * rollback the undo's in the exact reverse order that
  766                          * we applied them.  This guarantees that we won't run
  767                          * out of space as we roll things back out.
  768                          */
  769                         for (j = i - 1; j >= 0; j--) {
  770                                 if ((sops[j].sem_flg & SEM_UNDO) == 0)
  771                                         continue;
  772                                 adjval = sops[j].sem_op;
  773                                 if (adjval == 0)
  774                                         continue;
  775                                 if (semundo_adjust(p, &suptr, semid,
  776                                     sops[j].sem_num, adjval) != 0)
  777                                         panic("semop - can't undo undos");
  778                         }
  779 
  780                         for (j = 0; j < nsops; j++)
  781                                 semaptr->sem_base[sops[j].sem_num].semval -=
  782                                     sops[j].sem_op;
  783 
  784 #ifdef SEM_DEBUG
  785                         printf("eval = %d from semundo_adjust\n", eval);
  786 #endif
  787                         return(eval);
  788                 } /* loop through the sops */
  789         } /* if (do_undos) */
  790 
  791         /* We're definitely done - set the sempid's */
  792         for (i = 0; i < nsops; i++) {
  793                 sopptr = &sops[i];
  794                 semptr = &semaptr->sem_base[sopptr->sem_num];
  795                 semptr->sempid = p->p_pid;
  796         }
  797 
  798         /* Do a wakeup if any semaphore was up'd. */
  799         if (do_wakeup) {
  800 #ifdef SEM_DEBUG
  801                 printf("semop:  doing wakeup\n");
  802 #ifdef SEM_WAKEUP
  803                 sem_wakeup((caddr_t)semaptr);
  804 #else
  805                 wakeup((caddr_t)semaptr);
  806 #endif
  807                 printf("semop:  back from wakeup\n");
  808 #else
  809                 wakeup((caddr_t)semaptr);
  810 #endif
  811         }
  812 #ifdef SEM_DEBUG
  813         printf("semop:  done\n");
  814 #endif
  815         *retval = 0;
  816         return(0);
  817 }
  818 
  819 /*
  820  * Go through the undo structures for this process and apply the adjustments to
  821  * semaphores.
  822  */
  823 void
  824 semexit(p)
  825         struct proc *p;
  826 {
  827         register struct sem_undo *suptr;
  828         register struct sem_undo **supptr;
  829         int did_something;
  830 
  831         did_something = 0;
  832 
  833         /*
  834          * Go through the chain of undo vectors looking for one
  835          * associated with this process.
  836          */
  837 
  838         for (supptr = &semu_list; (suptr = *supptr) != NULL;
  839             supptr = &suptr->un_next) {
  840                 if (suptr->un_proc == p)
  841                         break;
  842         }
  843 
  844         if (suptr == NULL)
  845                 return;
  846 
  847 #ifdef SEM_DEBUG
  848         printf("proc @%08x has undo structure with %d entries\n", p,
  849             suptr->un_cnt);
  850 #endif
  851 
  852         /*
  853          * If there are any active undo elements then process them.
  854          */
  855         if (suptr->un_cnt > 0) {
  856                 int ix;
  857 
  858                 for (ix = 0; ix < suptr->un_cnt; ix++) {
  859                         int semid = suptr->un_ent[ix].un_id;
  860                         int semnum = suptr->un_ent[ix].un_num;
  861                         int adjval = suptr->un_ent[ix].un_adjval;
  862                         struct semid_ds *semaptr;
  863 
  864                         semaptr = &sema[semid];
  865                         if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
  866                                 panic("semexit - semid not allocated");
  867                         if (semnum >= semaptr->sem_nsems)
  868                                 panic("semexit - semnum out of range");
  869 
  870 #ifdef SEM_DEBUG
  871                         printf("semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
  872                             suptr->un_proc, suptr->un_ent[ix].un_id,
  873                             suptr->un_ent[ix].un_num,
  874                             suptr->un_ent[ix].un_adjval,
  875                             semaptr->sem_base[semnum].semval);
  876 #endif
  877 
  878                         if (adjval < 0) {
  879                                 if (semaptr->sem_base[semnum].semval < -adjval)
  880                                         semaptr->sem_base[semnum].semval = 0;
  881                                 else
  882                                         semaptr->sem_base[semnum].semval +=
  883                                             adjval;
  884                         } else
  885                                 semaptr->sem_base[semnum].semval += adjval;
  886 
  887 #ifdef SEM_WAKEUP
  888                         sem_wakeup((caddr_t)semaptr);
  889 #else
  890                         wakeup((caddr_t)semaptr);
  891 #endif
  892 #ifdef SEM_DEBUG
  893                         printf("semexit:  back from wakeup\n");
  894 #endif
  895                 }
  896         }
  897 
  898         /*
  899          * Deallocate the undo vector.
  900          */
  901 #ifdef SEM_DEBUG
  902         printf("removing vector\n");
  903 #endif
  904         suptr->un_proc = NULL;
  905         *supptr = suptr->un_next;
  906 }

Cache object: d746128456085b29cd9734c4bf14808c


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