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