 c3fc9df84a
			
		
	
	
		c3fc9df84a
		
	
	
	
	
		
			
			* Also change _orig to _intr for clarity
 * Cleaned up {IPC,KER}VEC
 * Renamed _minix_kernel_info_struct to get_minix_kerninfo
 * Merged _senda.S into _ipc.S
 * Moved into separate files get_minix_kerninfo and _do_kernel_call
 * Adapted do_kernel_call to follow same _ convention as ipc functions
 * Drop patches in libc/net/send.c and libc/include/namespace.h
Change-Id: If4ea21ecb65435170d7d87de6c826328e84c18d0
		
	
			
		
			
				
	
	
		
			615 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			615 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #define __USE_MISC
 | |
| 
 | |
| #include <minix/vm.h>
 | |
| 
 | |
| #include "inc.h"
 | |
| 
 | |
| struct waiting {
 | |
| 	endpoint_t who;			/* who is waiting */
 | |
| 	int val;			/* value he/she is waiting for */
 | |
| };
 | |
| 
 | |
| struct semaphore {
 | |
| 	unsigned short semval;		/* semaphore value */
 | |
| 	unsigned short semzcnt;		/* # waiting for zero */
 | |
| 	unsigned short semncnt;		/* # waiting for increase */
 | |
| 	struct waiting *zlist;		/* process waiting for zero */
 | |
| 	struct waiting *nlist;		/* process waiting for increase */
 | |
| 	pid_t sempid;			/* process that did last op */
 | |
| };
 | |
| 
 | |
| struct sem_struct {
 | |
| 	key_t key;
 | |
| 	int id;
 | |
| 	struct semid_ds semid_ds;
 | |
| 	struct semaphore sems[SEMMSL];
 | |
| };
 | |
| 
 | |
| static struct sem_struct sem_list[SEMMNI];
 | |
| static int sem_list_nr = 0;
 | |
| 
 | |
| static struct sem_struct *sem_find_key(key_t key)
 | |
| {
 | |
| 	int i;
 | |
| 	if (key == IPC_PRIVATE)
 | |
| 		return NULL;
 | |
| 	for (i = 0; i < sem_list_nr; i++)
 | |
| 		if (sem_list[i].key == key)
 | |
| 			return sem_list+i;
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| static struct sem_struct *sem_find_id(int id)
 | |
| {
 | |
| 	int i;
 | |
| 	for (i = 0; i < sem_list_nr; i++)
 | |
| 		if (sem_list[i].id == id)
 | |
| 			return sem_list+i;
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				do_semget		     		     *
 | |
|  *===========================================================================*/
 | |
| int do_semget(message *m)
 | |
| {
 | |
| 	key_t key;
 | |
| 	int nsems, flag, id;
 | |
| 	struct sem_struct *sem;
 | |
| 
 | |
| 	key = m->SEMGET_KEY;
 | |
| 	nsems = m->SEMGET_NR;
 | |
| 	flag = m->SEMGET_FLAG;
 | |
| 
 | |
| 	if ((sem = sem_find_key(key))) {
 | |
| 		if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
 | |
| 			return EEXIST;
 | |
| 		if (!check_perm(&sem->semid_ds.sem_perm, who_e, flag))
 | |
| 			return EACCES;
 | |
| 		if (nsems > sem->semid_ds.sem_nsems)
 | |
| 			return EINVAL;
 | |
| 		id = sem->id;
 | |
| 	} else {
 | |
| 		if (!(flag & IPC_CREAT))
 | |
| 			return ENOENT;
 | |
| 		if (nsems < 0 || nsems >= SEMMSL)
 | |
| 			return EINVAL;
 | |
| 		if (sem_list_nr == SEMMNI)
 | |
| 			return ENOSPC;
 | |
| 
 | |
| 		/* create a new semaphore set */
 | |
| 		sem = &sem_list[sem_list_nr];
 | |
| 		memset(sem, 0, sizeof(struct sem_struct));
 | |
| 		sem->semid_ds.sem_perm.cuid =
 | |
| 			sem->semid_ds.sem_perm.uid = getnuid(who_e);
 | |
| 		sem->semid_ds.sem_perm.cgid =
 | |
| 			sem->semid_ds.sem_perm.gid = getngid(who_e);
 | |
| 		sem->semid_ds.sem_perm.mode = flag & 0777;
 | |
| 		sem->semid_ds.sem_nsems = nsems;
 | |
| 		sem->semid_ds.sem_otime = 0;
 | |
| 		sem->semid_ds.sem_ctime = time(NULL);
 | |
| 		sem->id = id = identifier++;
 | |
| 		sem->key = key;
 | |
| 
 | |
| 		sem_list_nr++;
 | |
| 	}
 | |
| 
 | |
| 	m->SEMGET_RETID = id;
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| static void send_message_to_process(endpoint_t who, int ret, int ignore)
 | |
| {
 | |
| 	message m;
 | |
| 
 | |
| 	m.m_type = ret;
 | |
| 	ipc_sendnb(who, &m);
 | |
| }
 | |
| 
 | |
| static void remove_semaphore(struct sem_struct *sem)
 | |
| {
 | |
| 	int i, nr;
 | |
| 
 | |
| 	nr = sem->semid_ds.sem_nsems;
 | |
| 
 | |
| 	for (i = 0; i < nr; i++) {
 | |
| 		if (sem->sems[i].zlist)
 | |
| 			free(sem->sems[i].zlist);
 | |
| 		if (sem->sems[i].nlist)
 | |
| 			free(sem->sems[i].nlist);
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < sem_list_nr; i++) {
 | |
| 		if (&sem_list[i] == sem)
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	if (i < sem_list_nr && --sem_list_nr != i)
 | |
| 		sem_list[i] = sem_list[sem_list_nr];
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| static void show_semaphore(void)
 | |
| {
 | |
| 	int i, j, k;
 | |
| 
 | |
| 	for (i = 0; i < sem_list_nr; i++) {
 | |
| 		int nr = sem_list[i].semid_ds.sem_nsems;
 | |
| 
 | |
| 		printf("===== [%d] =====\n", i);
 | |
| 		for (j = 0; j < nr; j++) {
 | |
| 			struct semaphore *semaphore = &sem_list[i].sems[j];
 | |
| 
 | |
| 			if (!semaphore->semzcnt && !semaphore->semncnt)
 | |
| 				continue;
 | |
| 
 | |
| 			printf("  (%d): ", semaphore->semval);
 | |
| 			if (semaphore->semzcnt) {
 | |
| 				printf("zero(");
 | |
| 				for (k = 0; k < semaphore->semzcnt; k++)
 | |
| 					printf("%d,", semaphore->zlist[k].who);
 | |
| 				printf(")    ");
 | |
| 			}
 | |
| 			if (semaphore->semncnt) {
 | |
| 				printf("incr(");
 | |
| 				for (k = 0; k < semaphore->semncnt; k++)
 | |
| 					printf("%d-%d,",
 | |
| 						semaphore->nlist[k].who, semaphore->nlist[k].val);
 | |
| 				printf(")");
 | |
| 			}
 | |
| 			printf("\n");
 | |
| 		}
 | |
| 	}
 | |
| 	printf("\n");
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void remove_process(endpoint_t pt)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < sem_list_nr; i++) {
 | |
| 		struct sem_struct *sem = &sem_list[i];
 | |
| 		int nr = sem->semid_ds.sem_nsems;
 | |
| 		int j;
 | |
| 
 | |
| 		for (j = 0; j < nr; j++) {
 | |
| 			struct semaphore *semaphore = &sem->sems[j];
 | |
| 			int k;
 | |
| 
 | |
| 			for (k = 0; k < semaphore->semzcnt; k++) {
 | |
| 				endpoint_t who_waiting = semaphore->zlist[k].who;
 | |
| 
 | |
| 				if (who_waiting == pt) {
 | |
| 					/* remove this slot first */
 | |
| 					memmove(semaphore->zlist+k, semaphore->zlist+k+1,
 | |
| 						sizeof(struct waiting) * (semaphore->semzcnt-k-1));
 | |
| 					--semaphore->semzcnt;
 | |
| 					/* then send message to the process */
 | |
| 					send_message_to_process(who_waiting, EINTR, 1);
 | |
| 
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			for (k = 0; k < semaphore->semncnt; k++) {
 | |
| 				endpoint_t who_waiting = semaphore->nlist[k].who;
 | |
| 
 | |
| 				if (who_waiting == pt) {
 | |
| 					/* remove it first */
 | |
| 					memmove(semaphore->nlist+k, semaphore->nlist+k+1,
 | |
| 						sizeof(struct waiting) * (semaphore->semncnt-k-1));
 | |
| 					--semaphore->semncnt;
 | |
| 					/* send the message to the process */
 | |
| 					send_message_to_process(who_waiting, EINTR, 1);
 | |
| 
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void update_one_semaphore(struct sem_struct *sem, int is_remove)
 | |
| {
 | |
| 	int i, j, nr;
 | |
| 	struct semaphore *semaphore;
 | |
| 	endpoint_t who;
 | |
| 
 | |
| 	nr = sem->semid_ds.sem_nsems;
 | |
| 
 | |
| 	if (is_remove) {
 | |
| 		for (i = 0; i < nr; i++) {
 | |
| 			semaphore = &sem->sems[i];
 | |
| 
 | |
| 			for (j = 0; j < semaphore->semzcnt; j++)
 | |
| 				send_message_to_process(semaphore->zlist[j].who, EIDRM, 0);
 | |
| 			for (j = 0; j < semaphore->semncnt; j++)
 | |
| 				send_message_to_process(semaphore->nlist[j].who, EIDRM, 0);
 | |
| 		}
 | |
| 
 | |
| 		remove_semaphore(sem);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < nr; i++) {
 | |
| 		semaphore = &sem->sems[i];
 | |
| 
 | |
| 		if (semaphore->zlist && !semaphore->semval) {
 | |
| 			/* choose one process, policy: FIFO. */
 | |
| 			who = semaphore->zlist[0].who;
 | |
| 
 | |
| 			memmove(semaphore->zlist, semaphore->zlist+1,
 | |
| 				sizeof(struct waiting) * (semaphore->semzcnt-1));
 | |
| 			--semaphore->semzcnt;
 | |
| 
 | |
| 			send_message_to_process(who, OK, 0);
 | |
| 		}
 | |
| 
 | |
| 		if (semaphore->nlist) {
 | |
| 			for (j = 0; j < semaphore->semncnt; j++) {
 | |
| 				if (semaphore->nlist[j].val <= semaphore->semval) {
 | |
| 					semaphore->semval -= semaphore->nlist[j].val;
 | |
| 					who = semaphore->nlist[j].who;
 | |
| 
 | |
| 					memmove(semaphore->nlist+j, semaphore->nlist+j+1,
 | |
| 						sizeof(struct waiting) * (semaphore->semncnt-j-1));
 | |
| 					--semaphore->semncnt;
 | |
| 
 | |
| 					send_message_to_process(who, OK, 0);
 | |
| 
 | |
| 					/* choose only one process */
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void update_semaphores(void)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < sem_list_nr; i++)
 | |
| 		update_one_semaphore(sem_list+i, 0 /* not remove */);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				do_semctl		     		     *
 | |
|  *===========================================================================*/
 | |
| int do_semctl(message *m)
 | |
| {
 | |
| 	int r, i;
 | |
| 	long opt = 0;
 | |
| 	uid_t uid;
 | |
| 	int id, num, cmd, val;
 | |
| 	unsigned short *buf;
 | |
| 	struct semid_ds *ds, tmp_ds;
 | |
| 	struct sem_struct *sem;
 | |
| 
 | |
| 	id = m->SEMCTL_ID;
 | |
| 	num = m->SEMCTL_NUM;
 | |
| 	cmd = m->SEMCTL_CMD;
 | |
| 
 | |
| 	if (cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_INFO ||
 | |
| 		cmd == SEM_INFO || cmd == SEM_STAT || cmd == GETALL ||
 | |
| 		cmd == SETALL || cmd == SETVAL)
 | |
| 		opt = m->SEMCTL_OPT;
 | |
| 
 | |
| 	if (!(sem = sem_find_id(id))) {
 | |
| 		return EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	/* IPC_SET and IPC_RMID as its own permission check */
 | |
| 	if (cmd != IPC_SET && cmd != IPC_RMID) {
 | |
| 		/* check read permission */
 | |
| 		if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444))
 | |
| 			return EACCES;
 | |
| 	}
 | |
| 
 | |
| 	switch (cmd) {
 | |
| 	case IPC_STAT:
 | |
| 		ds = (struct semid_ds *) opt;
 | |
| 		if (!ds)
 | |
| 			return EFAULT;
 | |
| 		r = sys_datacopy(SELF, (vir_bytes) &sem->semid_ds,
 | |
| 			who_e, (vir_bytes) ds, sizeof(struct semid_ds));
 | |
| 		if (r != OK)
 | |
| 			return EINVAL;
 | |
| 		break;
 | |
| 	case IPC_SET:
 | |
| 		uid = getnuid(who_e);
 | |
| 		if (uid != sem->semid_ds.sem_perm.cuid &&
 | |
| 			uid != sem->semid_ds.sem_perm.uid &&
 | |
| 			uid != 0)
 | |
| 			return EPERM;
 | |
| 		ds = (struct semid_ds *) opt;
 | |
| 		r = sys_datacopy(who_e, (vir_bytes) ds,
 | |
| 			SELF, (vir_bytes) &tmp_ds, sizeof(struct semid_ds));
 | |
| 		if (r != OK)
 | |
| 			return EINVAL;
 | |
| 		sem->semid_ds.sem_perm.uid = tmp_ds.sem_perm.uid;
 | |
| 		sem->semid_ds.sem_perm.gid = tmp_ds.sem_perm.gid;
 | |
| 		sem->semid_ds.sem_perm.mode &= ~0777;
 | |
| 		sem->semid_ds.sem_perm.mode |= tmp_ds.sem_perm.mode & 0666;
 | |
| 		sem->semid_ds.sem_ctime = time(NULL);
 | |
| 		break;
 | |
| 	case IPC_RMID:
 | |
| 		uid = getnuid(who_e);
 | |
| 		if (uid != sem->semid_ds.sem_perm.cuid &&
 | |
| 			uid != sem->semid_ds.sem_perm.uid &&
 | |
| 			uid != 0)
 | |
| 			return EPERM;
 | |
| 		/* awaken all processes block in semop
 | |
| 		 * and remove the semaphore set.
 | |
| 		 */
 | |
| 		update_one_semaphore(sem, 1);
 | |
| 		break;
 | |
| 	case IPC_INFO:
 | |
| 		break;
 | |
| 	case SEM_INFO:
 | |
| 		break;
 | |
| 	case SEM_STAT:
 | |
| 		break;
 | |
| 	case GETALL:
 | |
| 		buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
 | |
| 		if (!buf)
 | |
| 			return ENOMEM;
 | |
| 		for (i = 0; i < sem->semid_ds.sem_nsems; i++)
 | |
| 			buf[i] = sem->sems[i].semval;
 | |
| 		r = sys_datacopy(SELF, (vir_bytes) buf,
 | |
| 			who_e, (vir_bytes) opt,
 | |
| 			sizeof(unsigned short) * sem->semid_ds.sem_nsems);
 | |
| 		if (r != OK)
 | |
| 			return EINVAL;
 | |
| 		free(buf);
 | |
| 		break;
 | |
| 	case GETNCNT:
 | |
| 		if (num < 0 || num >= sem->semid_ds.sem_nsems)
 | |
| 			return EINVAL;
 | |
| 		m->SHMCTL_RET = sem->sems[num].semncnt;
 | |
| 		break;
 | |
| 	case GETPID:
 | |
| 		if (num < 0 || num >= sem->semid_ds.sem_nsems)
 | |
| 			return EINVAL;
 | |
| 		m->SHMCTL_RET = sem->sems[num].sempid;
 | |
| 		break;
 | |
| 	case GETVAL:
 | |
| 		if (num < 0 || num >= sem->semid_ds.sem_nsems)
 | |
| 			return EINVAL;
 | |
| 		m->SHMCTL_RET = sem->sems[num].semval;
 | |
| 		break;
 | |
| 	case GETZCNT:
 | |
| 		if (num < 0 || num >= sem->semid_ds.sem_nsems)
 | |
| 			return EINVAL;
 | |
| 		m->SHMCTL_RET = sem->sems[num].semzcnt;
 | |
| 		break;
 | |
| 	case SETALL:
 | |
| 		buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
 | |
| 		if (!buf)
 | |
| 			return ENOMEM;
 | |
| 		r = sys_datacopy(who_e, (vir_bytes) opt,
 | |
| 			SELF, (vir_bytes) buf,
 | |
| 			sizeof(unsigned short) * sem->semid_ds.sem_nsems);
 | |
| 		if (r != OK)
 | |
| 			return EINVAL;
 | |
| #ifdef DEBUG_SEM
 | |
| 		printf("SEMCTL: SETALL: opt: %lu\n", (vir_bytes) opt);
 | |
| 		for (i = 0; i < sem->semid_ds.sem_nsems; i++)
 | |
| 			printf("SEMCTL: SETALL val: [%d] %d\n", i, buf[i]);
 | |
| #endif
 | |
| 		for (i = 0; i < sem->semid_ds.sem_nsems; i++) {
 | |
| 			if (buf[i] > SEMVMX) {
 | |
| 				free(buf);
 | |
| 				update_semaphores();
 | |
| 				return ERANGE;
 | |
| 			}
 | |
| 			sem->sems[i].semval = buf[i];
 | |
| 		}
 | |
| 		free(buf);
 | |
| 		/* awaken if possible */
 | |
| 		update_semaphores();
 | |
| 		break;
 | |
| 	case SETVAL:
 | |
| 		val = (int) opt;
 | |
| 		/* check write permission */
 | |
| 		if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
 | |
| 			return EACCES;
 | |
| 		if (num < 0 || num >= sem->semid_ds.sem_nsems)
 | |
| 			return EINVAL;
 | |
| 		if (val < 0 || val > SEMVMX)
 | |
| 			return ERANGE;
 | |
| 		sem->sems[num].semval = val;
 | |
| #ifdef DEBUG_SEM
 | |
| 		printf("SEMCTL: SETVAL: %d %d\n", num, val);
 | |
| #endif
 | |
| 		sem->semid_ds.sem_ctime = time(NULL);
 | |
| 		/* awaken if possible */
 | |
| 		update_semaphores();
 | |
| 		break;
 | |
| 	default:
 | |
| 		return EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				do_semop		     		     *
 | |
|  *===========================================================================*/
 | |
| int do_semop(message *m)
 | |
| {
 | |
| 	int id, i, j, r;
 | |
| 	struct sembuf *sops;
 | |
| 	unsigned int nsops;
 | |
| 	struct sem_struct *sem;
 | |
| 	int no_reply = 0;
 | |
| 
 | |
| 	id = m->SEMOP_ID;
 | |
| 	nsops = (unsigned int) m->SEMOP_SIZE;
 | |
| 
 | |
| 	r = EINVAL;
 | |
| 	if (!(sem = sem_find_id(id)))
 | |
| 		goto out;
 | |
| 
 | |
| 	if (nsops <= 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	r = E2BIG;
 | |
| 	if (nsops > SEMOPM)
 | |
| 		goto out;
 | |
| 
 | |
| 	/* check for read permission */
 | |
| 	r = EACCES;
 | |
| 	if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444))
 | |
| 		goto out;
 | |
| 
 | |
| 	/* get the array from user application */
 | |
| 	r = ENOMEM;
 | |
| 	sops = malloc(sizeof(struct sembuf) * nsops);
 | |
| 	if (!sops)
 | |
| 		goto out_free;
 | |
| 	r = sys_datacopy(who_e, (vir_bytes) m->SEMOP_OPS,
 | |
| 			SELF, (vir_bytes) sops,
 | |
| 			sizeof(struct sembuf) * nsops);
 | |
| 	if (r != OK) {
 | |
| 		r = EINVAL;
 | |
| 		goto out_free;
 | |
| 	}
 | |
| 
 | |
| #ifdef DEBUG_SEM
 | |
| 	for (i = 0; i < nsops; i++)
 | |
| 		printf("SEMOP: num:%d  op:%d  flg:%d\n",
 | |
| 			sops[i].sem_num, sops[i].sem_op, sops[i].sem_flg);
 | |
| #endif
 | |
| 	/* check for value range */
 | |
| 	r = EFBIG;
 | |
| 	for (i = 0; i < nsops; i++)
 | |
| 		if (sops[i].sem_num >= sem->semid_ds.sem_nsems)
 | |
| 			goto out_free;
 | |
| 
 | |
| 	/* check for duplicate number */
 | |
| 	r = EINVAL;
 | |
| 	for (i = 0; i < nsops; i++)
 | |
| 		for (j = i + 1; j < nsops; j++)
 | |
| 			if (sops[i].sem_num == sops[j].sem_num)
 | |
| 				goto out_free;
 | |
| 
 | |
| 	/* check for EAGAIN error */
 | |
| 	r = EAGAIN;
 | |
| 	for (i = 0; i < nsops; i++) {
 | |
| 		int op_n, val;
 | |
| 
 | |
| 		op_n = sops[i].sem_op;
 | |
| 		val = sem->sems[sops[i].sem_num].semval;
 | |
| 
 | |
| 		if ((sops[i].sem_flg & IPC_NOWAIT) &&
 | |
| 				((!op_n && val) ||
 | |
| 				 (op_n < 0 &&
 | |
| 				  -op_n > val)))
 | |
| 			goto out_free;
 | |
| 
 | |
| 	}
 | |
| 	/* there will be no errors left, so we can go ahead */
 | |
| 	for (i = 0; i < nsops; i++) {
 | |
| 		struct semaphore *s;
 | |
| 		int op_n;
 | |
| 
 | |
| 		s = &sem->sems[sops[i].sem_num];
 | |
| 		op_n = sops[i].sem_op;
 | |
| 
 | |
| 		s->sempid = getnpid(who_e);
 | |
| 
 | |
| 		if (op_n > 0) {
 | |
| 			/* check for alter permission */
 | |
| 			r = EACCES;
 | |
| 			if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
 | |
| 				goto out_free;
 | |
| 			s->semval += sops[i].sem_op;
 | |
| 		} else if (!op_n) {
 | |
| 			if (s->semval) {
 | |
| 				/* put the process asleep */
 | |
| 				s->semzcnt++;
 | |
| 				s->zlist = realloc(s->zlist, sizeof(struct waiting) * s->semzcnt);
 | |
| 				if (!s->zlist) {
 | |
| 					printf("IPC: zero waiting list lost...\n");
 | |
| 					break;
 | |
| 				}
 | |
| 				s->zlist[s->semzcnt-1].who = who_e;
 | |
| 				s->zlist[s->semzcnt-1].val = op_n;
 | |
| 
 | |
| #ifdef DEBUG_SEM
 | |
| 				printf("SEMOP: Put into sleep... %d\n", who_e);
 | |
| #endif
 | |
| 				no_reply++;
 | |
| 			}
 | |
| 		} else {
 | |
| 			/* check for alter permission */
 | |
| 			r = EACCES;
 | |
| 			if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
 | |
| 				goto out_free;
 | |
| 			if (s->semval >= -op_n)
 | |
| 				s->semval += op_n;
 | |
| 			else {
 | |
| 				/* put the process asleep */
 | |
| 				s->semncnt++;
 | |
| 				s->nlist = realloc(s->nlist, sizeof(struct waiting) * s->semncnt);
 | |
| 				if (!s->nlist) {
 | |
| 					printf("IPC: increase waiting list lost...\n");
 | |
| 					break;
 | |
| 				}
 | |
| 				s->nlist[s->semncnt-1].who = who_e;
 | |
| 				s->nlist[s->semncnt-1].val = -op_n;
 | |
| 
 | |
| 				no_reply++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	r = OK;
 | |
| out_free:
 | |
| 	free(sops);
 | |
| out:
 | |
| 	/* if we reach here by errors
 | |
| 	 * or with no errors but we should reply back.
 | |
| 	 */
 | |
| 	if (r != OK || !no_reply) {
 | |
| 		m->m_type = r;
 | |
| 
 | |
| 		ipc_sendnb(who_e, m);
 | |
| 	}
 | |
| 
 | |
| 	/* awaken process if possible */
 | |
| 	update_semaphores();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				is_sem_nil		     		     *
 | |
|  *===========================================================================*/
 | |
| int is_sem_nil(void)
 | |
| {
 | |
| 	return (sem_list_nr == 0);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				sem_process_vm_notify	     		     *
 | |
|  *===========================================================================*/
 | |
| void sem_process_vm_notify(void)
 | |
| {
 | |
| 	endpoint_t pt;
 | |
| 	int r;
 | |
| 
 | |
| 	while ((r = vm_query_exit(&pt)) >= 0) {
 | |
| 		/* for each enpoint 'pt', check whether it's waiting... */
 | |
| 		remove_process(pt);
 | |
| 
 | |
| 		if (r == 0)
 | |
| 			break;
 | |
| 	}
 | |
| 	if (r < 0)
 | |
| 		printf("IPC: query exit error!\n");
 | |
| }
 | |
| 
 |