Home | History | Annotate | Line # | Download | only in kern
sysv_sem.c revision 1.11
      1 /*	$NetBSD: sysv_sem.c,v 1.11 1994/12/04 14:06:36 mycroft 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; suptr = suptr->un_next) {
    185 			if (suptr->un_proc == p) {
    186 				*supptr = suptr;
    187 				break;
    188 			}
    189 		}
    190 		if (suptr == NULL) {
    191 			if (adjval == 0)
    192 				return(0);
    193 			suptr = semu_alloc(p);
    194 			if (suptr == NULL)
    195 				return(ENOSPC);
    196 			*supptr = suptr;
    197 		}
    198 	}
    199 
    200 	/*
    201 	 * Look for the requested entry and adjust it (delete if adjval becomes
    202 	 * 0).
    203 	 */
    204 	sunptr = &suptr->un_ent[0];
    205 	for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
    206 		if (sunptr->un_id != semid || sunptr->un_num != semnum)
    207 			continue;
    208 		if (adjval == 0)
    209 			sunptr->un_adjval = 0;
    210 		else
    211 			sunptr->un_adjval += adjval;
    212 		if (sunptr->un_adjval == 0) {
    213 			suptr->un_cnt--;
    214 			if (i < suptr->un_cnt)
    215 				suptr->un_ent[i] =
    216 				    suptr->un_ent[suptr->un_cnt];
    217 		}
    218 		return(0);
    219 	}
    220 
    221 	/* Didn't find the right entry - create it */
    222 	if (adjval == 0)
    223 		return(0);
    224 	if (suptr->un_cnt == SEMUME)
    225 		return(EINVAL);
    226 
    227 	sunptr = &suptr->un_ent[suptr->un_cnt];
    228 	suptr->un_cnt++;
    229 	sunptr->un_adjval = adjval;
    230 	sunptr->un_id = semid;
    231 	sunptr->un_num = semnum;
    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 	    semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid)))
    569 		return(EINVAL);
    570 
    571 	if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
    572 #ifdef SEM_DEBUG
    573 		printf("eval = %d from ipaccess\n", eval);
    574 #endif
    575 		return(eval);
    576 	}
    577 
    578 	if (nsops > MAX_SOPS) {
    579 #ifdef SEM_DEBUG
    580 		printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
    581 #endif
    582 		return(E2BIG);
    583 	}
    584 
    585 	if ((eval = copyin(SCARG(uap, sops), sops, nsops * sizeof(sops[0])))
    586 	    != 0) {
    587 #ifdef SEM_DEBUG
    588 		printf("eval = %d from copyin(%08x, %08x, %d)\n", eval,
    589 		    SCARG(uap, sops), &sops, nsops * sizeof(sops[0]));
    590 #endif
    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 #ifdef SEM_DEBUG
    617 			printf("semop:  semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
    618 			    semaptr, semaptr->sem_base, semptr,
    619 			    sopptr->sem_num, semptr->semval, sopptr->sem_op,
    620 			    (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
    621 #endif
    622 
    623 			if (sopptr->sem_op < 0) {
    624 				if (semptr->semval + sopptr->sem_op < 0) {
    625 #ifdef SEM_DEBUG
    626 					printf("semop:  can't do it now\n");
    627 #endif
    628 					break;
    629 				} else {
    630 					semptr->semval += sopptr->sem_op;
    631 					if (semptr->semval == 0 &&
    632 					    semptr->semzcnt > 0)
    633 						do_wakeup = 1;
    634 				}
    635 				if (sopptr->sem_flg & SEM_UNDO)
    636 					do_undos = 1;
    637 			} else if (sopptr->sem_op == 0) {
    638 				if (semptr->semval > 0) {
    639 #ifdef SEM_DEBUG
    640 					printf("semop:  not zero now\n");
    641 #endif
    642 					break;
    643 				}
    644 			} else {
    645 				if (semptr->semncnt > 0)
    646 					do_wakeup = 1;
    647 				semptr->semval += sopptr->sem_op;
    648 				if (sopptr->sem_flg & SEM_UNDO)
    649 					do_undos = 1;
    650 			}
    651 		}
    652 
    653 		/*
    654 		 * Did we get through the entire vector?
    655 		 */
    656 		if (i >= nsops)
    657 			goto done;
    658 
    659 		/*
    660 		 * No ... rollback anything that we've already done
    661 		 */
    662 #ifdef SEM_DEBUG
    663 		printf("semop:  rollback 0 through %d\n", i-1);
    664 #endif
    665 		for (j = 0; j < i; j++)
    666 			semaptr->sem_base[sops[j].sem_num].semval -=
    667 			    sops[j].sem_op;
    668 
    669 		/*
    670 		 * If the request that we couldn't satisfy has the
    671 		 * NOWAIT flag set then return with EAGAIN.
    672 		 */
    673 		if (sopptr->sem_flg & IPC_NOWAIT)
    674 			return(EAGAIN);
    675 
    676 		if (sopptr->sem_op == 0)
    677 			semptr->semzcnt++;
    678 		else
    679 			semptr->semncnt++;
    680 
    681 #ifdef SEM_DEBUG
    682 		printf("semop:  good night!\n");
    683 #endif
    684 		eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
    685 		    "semwait", 0);
    686 #ifdef SEM_DEBUG
    687 		printf("semop:  good morning (eval=%d)!\n", eval);
    688 #endif
    689 
    690 		suptr = NULL;	/* sem_undo may have been reallocated */
    691 
    692 		if (eval != 0)
    693 			return(EINTR);
    694 #ifdef SEM_DEBUG
    695 		printf("semop:  good morning!\n");
    696 #endif
    697 
    698 		/*
    699 		 * Make sure that the semaphore still exists
    700 		 */
    701 		if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
    702 		    semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) {
    703 			/* The man page says to return EIDRM. */
    704 			/* Unfortunately, BSD doesn't define that code! */
    705 #ifdef EIDRM
    706 			return(EIDRM);
    707 #else
    708 			return(EINVAL);
    709 #endif
    710 		}
    711 
    712 		/*
    713 		 * The semaphore is still alive.  Readjust the count of
    714 		 * waiting processes.
    715 		 */
    716 		if (sopptr->sem_op == 0)
    717 			semptr->semzcnt--;
    718 		else
    719 			semptr->semncnt--;
    720 	}
    721 
    722 done:
    723 	/*
    724 	 * Process any SEM_UNDO requests.
    725 	 */
    726 	if (do_undos) {
    727 		for (i = 0; i < nsops; i++) {
    728 			/*
    729 			 * We only need to deal with SEM_UNDO's for non-zero
    730 			 * op's.
    731 			 */
    732 			int adjval;
    733 
    734 			if ((sops[i].sem_flg & SEM_UNDO) == 0)
    735 				continue;
    736 			adjval = sops[i].sem_op;
    737 			if (adjval == 0)
    738 				continue;
    739 			eval = semundo_adjust(p, &suptr, semid,
    740 			    sops[i].sem_num, -adjval);
    741 			if (eval == 0)
    742 				continue;
    743 
    744 			/*
    745 			 * Oh-Oh!  We ran out of either sem_undo's or undo's.
    746 			 * Rollback the adjustments to this point and then
    747 			 * rollback the semaphore ups and down so we can return
    748 			 * with an error with all structures restored.  We
    749 			 * rollback the undo's in the exact reverse order that
    750 			 * we applied them.  This guarantees that we won't run
    751 			 * out of space as we roll things back out.
    752 			 */
    753 			for (j = i - 1; j >= 0; j--) {
    754 				if ((sops[j].sem_flg & SEM_UNDO) == 0)
    755 					continue;
    756 				adjval = sops[j].sem_op;
    757 				if (adjval == 0)
    758 					continue;
    759 				if (semundo_adjust(p, &suptr, semid,
    760 				    sops[j].sem_num, adjval) != 0)
    761 					panic("semop - can't undo undos");
    762 			}
    763 
    764 			for (j = 0; j < nsops; j++)
    765 				semaptr->sem_base[sops[j].sem_num].semval -=
    766 				    sops[j].sem_op;
    767 
    768 #ifdef SEM_DEBUG
    769 			printf("eval = %d from semundo_adjust\n", eval);
    770 #endif
    771 			return(eval);
    772 		} /* loop through the sops */
    773 	} /* if (do_undos) */
    774 
    775 	/* We're definitely done - set the sempid's */
    776 	for (i = 0; i < nsops; i++) {
    777 		sopptr = &sops[i];
    778 		semptr = &semaptr->sem_base[sopptr->sem_num];
    779 		semptr->sempid = p->p_pid;
    780 	}
    781 
    782 	/* Do a wakeup if any semaphore was up'd. */
    783 	if (do_wakeup) {
    784 #ifdef SEM_DEBUG
    785 		printf("semop:  doing wakeup\n");
    786 #ifdef SEM_WAKEUP
    787 		sem_wakeup((caddr_t)semaptr);
    788 #else
    789 		wakeup((caddr_t)semaptr);
    790 #endif
    791 		printf("semop:  back from wakeup\n");
    792 #else
    793 		wakeup((caddr_t)semaptr);
    794 #endif
    795 	}
    796 #ifdef SEM_DEBUG
    797 	printf("semop:  done\n");
    798 #endif
    799 	*retval = 0;
    800 	return(0);
    801 }
    802 
    803 /*
    804  * Go through the undo structures for this process and apply the adjustments to
    805  * semaphores.
    806  */
    807 semexit(p)
    808 	struct proc *p;
    809 {
    810 	register struct sem_undo *suptr;
    811 	register struct sem_undo **supptr;
    812 	int did_something;
    813 
    814 	/*
    815 	 * If somebody else is holding the global semaphore facility lock
    816 	 * then sleep until it is released.
    817 	 */
    818 	while (semlock_holder != NULL && semlock_holder != p) {
    819 #ifdef SEM_DEBUG
    820 		printf("semaphore facility locked - sleeping ...\n");
    821 #endif
    822 		sleep((caddr_t)&semlock_holder, (PZERO - 4));
    823 	}
    824 
    825 	did_something = 0;
    826 
    827 	/*
    828 	 * Go through the chain of undo vectors looking for one
    829 	 * associated with this process.
    830 	 */
    831 
    832 	for (supptr = &semu_list; (suptr = *supptr) != NULL;
    833 	    supptr = &suptr->un_next) {
    834 		if (suptr->un_proc == p)
    835 			break;
    836 	}
    837 
    838 	if (suptr == NULL)
    839 		goto unlock;
    840 
    841 #ifdef SEM_DEBUG
    842 	printf("proc @%08x has undo structure with %d entries\n", p,
    843 	    suptr->un_cnt);
    844 #endif
    845 
    846 	/*
    847 	 * If there are any active undo elements then process them.
    848 	 */
    849 	if (suptr->un_cnt > 0) {
    850 		int ix;
    851 
    852 		for (ix = 0; ix < suptr->un_cnt; ix++) {
    853 			int semid = suptr->un_ent[ix].un_id;
    854 			int semnum = suptr->un_ent[ix].un_num;
    855 			int adjval = suptr->un_ent[ix].un_adjval;
    856 			struct semid_ds *semaptr;
    857 
    858 			semaptr = &sema[semid];
    859 			if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
    860 				panic("semexit - semid not allocated");
    861 			if (semnum >= semaptr->sem_nsems)
    862 				panic("semexit - semnum out of range");
    863 
    864 #ifdef SEM_DEBUG
    865 			printf("semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
    866 			    suptr->un_proc, suptr->un_ent[ix].un_id,
    867 			    suptr->un_ent[ix].un_num,
    868 			    suptr->un_ent[ix].un_adjval,
    869 			    semaptr->sem_base[semnum].semval);
    870 #endif
    871 
    872 			if (adjval < 0) {
    873 				if (semaptr->sem_base[semnum].semval < -adjval)
    874 					semaptr->sem_base[semnum].semval = 0;
    875 				else
    876 					semaptr->sem_base[semnum].semval +=
    877 					    adjval;
    878 			} else
    879 				semaptr->sem_base[semnum].semval += adjval;
    880 
    881 #ifdef SEM_WAKEUP
    882 			sem_wakeup((caddr_t)semaptr);
    883 #else
    884 			wakeup((caddr_t)semaptr);
    885 #endif
    886 #ifdef SEM_DEBUG
    887 			printf("semexit:  back from wakeup\n");
    888 #endif
    889 		}
    890 	}
    891 
    892 	/*
    893 	 * Deallocate the undo vector.
    894 	 */
    895 #ifdef SEM_DEBUG
    896 	printf("removing vector\n");
    897 #endif
    898 	suptr->un_proc = NULL;
    899 	*supptr = suptr->un_next;
    900 
    901 unlock:
    902 	/*
    903 	 * If the exiting process is holding the global semaphore facility
    904 	 * lock then release it.
    905 	 */
    906 	if (semlock_holder == p) {
    907 		semlock_holder = NULL;
    908 		wakeup((caddr_t)&semlock_holder);
    909 	}
    910 }
    911 
    912 #if defined(COMPAT_10) && !defined(alpha)
    913 int
    914 compat_10_semsys(p, uap, retval)
    915 	struct proc *p;
    916 	struct compat_10_semsys_args /* {
    917 		syscallarg(int) which;
    918 		syscallarg(int) a2;
    919 		syscallarg(int) a3;
    920 		syscallarg(int) a4;
    921 		syscallarg(int) a5;
    922 	} */ *uap;
    923 	register_t *retval;
    924 {
    925 	struct __semctl_args /* {
    926 		syscallarg(int) semid;
    927 		syscallarg(int) semnum;
    928 		syscallarg(int) cmd;
    929 		syscallarg(union semun *) arg;
    930 	} */ __semctl_args;
    931 	struct semget_args /* {
    932 		syscallarg(key_t) key;
    933 		syscallarg(int) nsems;
    934 		syscallarg(int) semflg;
    935 	} */ semget_args;
    936 	struct semop_args /* {
    937 		syscallarg(int) semid;
    938 		syscallarg(struct sembuf *) sops;
    939 		syscallarg(u_int) nsops;
    940 	} */ semop_args;
    941 	struct semconfig_args /* {
    942 		syscallarg(int) flag;
    943 	} */ semconfig_args;
    944 
    945 	while (semlock_holder != NULL && semlock_holder != p)
    946 		sleep((caddr_t)&semlock_holder, (PZERO - 4));
    947 
    948 	switch (SCARG(uap, which)) {
    949 	case 0:						/* __semctl() */
    950 		SCARG(&__semctl_args, semid) = SCARG(uap, a2);
    951 		SCARG(&__semctl_args, semnum) = SCARG(uap, a3);
    952 		SCARG(&__semctl_args, cmd) = SCARG(uap, a4);
    953 		SCARG(&__semctl_args, arg) = (union semun *)SCARG(uap, a5);
    954 		return (__semctl(p, &__semctl_args, retval));
    955 
    956 	case 1:						/* semget() */
    957 		SCARG(&semget_args, key) = SCARG(uap, a2);
    958 		SCARG(&semget_args, nsems) = SCARG(uap, a3);
    959 		SCARG(&semget_args, semflg) = SCARG(uap, a4);
    960 		return (semget(p, &semget_args, retval));
    961 
    962 	case 2:						/* semop() */
    963 		SCARG(&semop_args, semid) = SCARG(uap, a2);
    964 		SCARG(&semop_args, sops) = (struct sembuf *)SCARG(uap, a3);
    965 		SCARG(&semop_args, nsops) = SCARG(uap, a4);
    966 		return (semop(p, &semop_args, retval));
    967 
    968 	case 3:						/* semconfig() */
    969 		SCARG(&semconfig_args, flag) = SCARG(uap, a2);
    970 		return (semconfig(p, &semconfig_args, retval));
    971 
    972 	default:
    973 		return (EINVAL);
    974 	}
    975 }
    976 #endif /* defined(COMPAT_10) && !defined(alpha) */
    977