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