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