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