⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sem.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
		for (i = 0; i < sma->sem_nsems; i++)			sem_io[i] = sma->sem_base[i].semval;		sem_unlock(semid);		err = 0;		if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))			err = -EFAULT;		goto out_free;	}	case SETALL:	{		int i;		struct sem_undo *un;		sem_unlock(semid);		if(nsems > SEMMSL_FAST) {			sem_io = ipc_alloc(sizeof(ushort)*nsems);			if(sem_io == NULL)				return -ENOMEM;		}		if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {			err = -EFAULT;			goto out_free;		}		for (i = 0; i < nsems; i++) {			if (sem_io[i] > SEMVMX) {				err = -ERANGE;				goto out_free;			}		}		err = sem_revalidate(semid, sma, nsems, S_IWUGO);		if(err)			goto out_free;		for (i = 0; i < nsems; i++)			sma->sem_base[i].semval = sem_io[i];		for (un = sma->undo; un; un = un->id_next)			for (i = 0; i < nsems; i++)				un->semadj[i] = 0;		sma->sem_ctime = CURRENT_TIME;		/* maybe some queued-up processes were waiting for this */		update_queue(sma);		err = 0;		goto out_unlock;	}	case IPC_STAT:	{		struct semid64_ds tbuf;		memset(&tbuf,0,sizeof(tbuf));		kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);		tbuf.sem_otime  = sma->sem_otime;		tbuf.sem_ctime  = sma->sem_ctime;		tbuf.sem_nsems  = sma->sem_nsems;		sem_unlock(semid);		if (copy_semid_to_user (arg.buf, &tbuf, version))			return -EFAULT;		return 0;	}	/* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */	}	err = -EINVAL;	if(semnum < 0 || semnum >= nsems)		goto out_unlock;	curr = &sma->sem_base[semnum];	switch (cmd) {	case GETVAL:		err = curr->semval;		goto out_unlock;	case GETPID:		err = curr->sempid & 0xffff;		goto out_unlock;	case GETNCNT:		err = count_semncnt(sma,semnum);		goto out_unlock;	case GETZCNT:		err = count_semzcnt(sma,semnum);		goto out_unlock;	case SETVAL:	{		int val = arg.val;		struct sem_undo *un;		err = -ERANGE;		if (val > SEMVMX || val < 0)			goto out_unlock;		for (un = sma->undo; un; un = un->id_next)			un->semadj[semnum] = 0;		curr->semval = val;		sma->sem_ctime = CURRENT_TIME;		/* maybe some queued-up processes were waiting for this */		update_queue(sma);		err = 0;		goto out_unlock;	}	}out_unlock:	sem_unlock(semid);out_free:	if(sem_io != fast_sem_io)		ipc_free(sem_io, sizeof(ushort)*nsems);	return err;}struct sem_setbuf {	uid_t	uid;	gid_t	gid;	mode_t	mode;};static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void *buf, int version){	switch(version) {	case IPC_64:	    {		struct semid64_ds tbuf;		if(copy_from_user(&tbuf, buf, sizeof(tbuf)))			return -EFAULT;		out->uid	= tbuf.sem_perm.uid;		out->gid	= tbuf.sem_perm.gid;		out->mode	= tbuf.sem_perm.mode;		return 0;	    }	case IPC_OLD:	    {		struct semid_ds tbuf_old;		if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))			return -EFAULT;		out->uid	= tbuf_old.sem_perm.uid;		out->gid	= tbuf_old.sem_perm.gid;		out->mode	= tbuf_old.sem_perm.mode;		return 0;	    }	default:		return -EINVAL;	}}int semctl_down(int semid, int semnum, int cmd, int version, union semun arg){	struct sem_array *sma;	int err;	struct sem_setbuf setbuf;	struct kern_ipc_perm *ipcp;	if(cmd == IPC_SET) {		if(copy_semid_from_user (&setbuf, arg.buf, version))			return -EFAULT;	}	sma = sem_lock(semid);	if(sma==NULL)		return -EINVAL;	if (sem_checkid(sma,semid)) {		err=-EIDRM;		goto out_unlock;	}		ipcp = &sma->sem_perm;		if (current->euid != ipcp->cuid && 	    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {	    	err=-EPERM;		goto out_unlock;	}	switch(cmd){	case IPC_RMID:		freeary(semid);		err = 0;		break;	case IPC_SET:		ipcp->uid = setbuf.uid;		ipcp->gid = setbuf.gid;		ipcp->mode = (ipcp->mode & ~S_IRWXUGO)				| (setbuf.mode & S_IRWXUGO);		sma->sem_ctime = CURRENT_TIME;		sem_unlock(semid);		err = 0;		break;	default:		sem_unlock(semid);		err = -EINVAL;		break;	}	return err;out_unlock:	sem_unlock(semid);	return err;}asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg){	int err = -EINVAL;	int version;	if (semid < 0)		return -EINVAL;	version = ipc_parse_version(&cmd);	switch(cmd) {	case IPC_INFO:	case SEM_INFO:	case SEM_STAT:		err = semctl_nolock(semid,semnum,cmd,version,arg);		return err;	case GETALL:	case GETVAL:	case GETPID:	case GETNCNT:	case GETZCNT:	case IPC_STAT:	case SETVAL:	case SETALL:		err = semctl_main(semid,semnum,cmd,version,arg);		return err;	case IPC_RMID:	case IPC_SET:		down(&sem_ids.sem);		err = semctl_down(semid,semnum,cmd,version,arg);		up(&sem_ids.sem);		return err;	default:		return -EINVAL;	}}static struct sem_undo* freeundos(struct sem_array *sma, struct sem_undo* un){	struct sem_undo* u;	struct sem_undo** up;	for(up = &current->semundo;(u=*up);up=&u->proc_next) {		if(un==u) {			un=u->proc_next;			*up=un;			kfree(u);			return un;		}	}	printk ("freeundos undo list error id=%d\n", un->semid);	return un->proc_next;}/* returns without sem_lock on error! */static int alloc_undo(struct sem_array *sma, struct sem_undo** unp, int semid, int alter){	int size, nsems, error;	struct sem_undo *un;	nsems = sma->sem_nsems;	size = sizeof(struct sem_undo) + sizeof(short)*nsems;	sem_unlock(semid);	un = (struct sem_undo *) kmalloc(size, GFP_KERNEL);	if (!un)		return -ENOMEM;	memset(un, 0, size);	error = sem_revalidate(semid, sma, nsems, alter ? S_IWUGO : S_IRUGO);	if(error) {		kfree(un);		return error;	}	un->semadj = (short *) &un[1];	un->semid = semid;	un->proc_next = current->semundo;	current->semundo = un;	un->id_next = sma->undo;	sma->undo = un;	*unp = un;	return 0;}asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops){	int error = -EINVAL;	struct sem_array *sma;	struct sembuf fast_sops[SEMOPM_FAST];	struct sembuf* sops = fast_sops, *sop;	struct sem_undo *un;	int undos = 0, decrease = 0, alter = 0;	struct sem_queue queue;	if (nsops < 1 || semid < 0)		return -EINVAL;	if (nsops > sc_semopm)		return -E2BIG;	if(nsops > SEMOPM_FAST) {		sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);		if(sops==NULL)			return -ENOMEM;	}	if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {		error=-EFAULT;		goto out_free;	}	sma = sem_lock(semid);	error=-EINVAL;	if(sma==NULL)		goto out_free;	error = -EIDRM;	if (sem_checkid(sma,semid))		goto out_unlock_free;	error = -EFBIG;	for (sop = sops; sop < sops + nsops; sop++) {		if (sop->sem_num >= sma->sem_nsems)			goto out_unlock_free;		if (sop->sem_flg & SEM_UNDO)			undos++;		if (sop->sem_op < 0)			decrease = 1;		if (sop->sem_op > 0)			alter = 1;	}	alter |= decrease;	error = -EACCES;	if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))		goto out_unlock_free;	if (undos) {		/* Make sure we have an undo structure		 * for this process and this semaphore set.		 */		un=current->semundo;		while(un != NULL) {			if(un->semid==semid)				break;			if(un->semid==-1)				un=freeundos(sma,un);			 else				un=un->proc_next;		}		if (!un) {			error = alloc_undo(sma,&un,semid,alter);			if(error)				goto out_free;		}	} else		un = NULL;	error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0);	if (error <= 0)		goto update;	/* We need to sleep on this operation, so we put the current	 * task into the pending queue and go to sleep.	 */			queue.sma = sma;	queue.sops = sops;	queue.nsops = nsops;	queue.undo = un;	queue.pid = current->pid;	queue.alter = decrease;	queue.id = semid;	if (alter)		append_to_queue(sma ,&queue);	else		prepend_to_queue(sma ,&queue);	current->semsleeping = &queue;	for (;;) {		struct sem_array* tmp;		queue.status = -EINTR;		queue.sleeper = current;		current->state = TASK_INTERRUPTIBLE;		sem_unlock(semid);		schedule();		tmp = sem_lock(semid);		if(tmp==NULL) {			if(queue.prev != NULL)				BUG();			current->semsleeping = NULL;			error = -EIDRM;			goto out_free;		}		/*		 * If queue.status == 1 we where woken up and		 * have to retry else we simply return.		 * If an interrupt occurred we have to clean up the		 * queue		 *		 */		if (queue.status == 1)		{			error = try_atomic_semop (sma, sops, nsops, un,						  current->pid,0);			if (error <= 0) 				break;		} else {			error = queue.status;			if (queue.prev) /* got Interrupt */				break;			/* Everything done by update_queue */			current->semsleeping = NULL;			goto out_unlock_free;		}	}	current->semsleeping = NULL;	remove_from_queue(sma,&queue);update:	if (alter)		update_queue (sma);out_unlock_free:	sem_unlock(semid);out_free:	if(sops != fast_sops)		kfree(sops);	return error;}/* * add semadj values to semaphores, free undo structures. * undo structures are not freed when semaphore arrays are destroyed * so some of them may be out of date. * IMPLEMENTATION NOTE: There is some confusion over whether the * set of adjustments that needs to be done should be done in an atomic * manner or not. That is, if we are attempting to decrement the semval * should we queue up and wait until we can do so legally? * The original implementation attempted to do this (queue and wait). * The current implementation does not do so. The POSIX standard * and SVID should be consulted to determine what behavior is mandated. */void sem_exit (void){	struct sem_queue *q;	struct sem_undo *u, *un = NULL, **up, **unp;	struct sem_array *sma;	int nsems, i;	/* If the current process was sleeping for a semaphore,	 * remove it from the queue.	 */	if ((q = current->semsleeping)) {		int semid = q->id;		sma = sem_lock(semid);		current->semsleeping = NULL;		if (q->prev) {			if(sma==NULL)				BUG();			remove_from_queue(q->sma,q);		}		if(sma!=NULL)			sem_unlock(semid);	}	for (up = &current->semundo; (u = *up); *up = u->proc_next, kfree(u)) {		int semid = u->semid;		if(semid == -1)			continue;		sma = sem_lock(semid);		if (sma == NULL)			continue;		if (u->semid == -1)			goto next_entry;		if (sem_checkid(sma,u->semid))			goto next_entry;		/* remove u from the sma->undo list */		for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {			if (u == un)				goto found;		}		printk ("sem_exit undo list error id=%d\n", u->semid);		goto next_entry;found:		*unp = un->id_next;		/* perform adjustments registered in u */		nsems = sma->sem_nsems;		for (i = 0; i < nsems; i++) {			struct sem * sem = &sma->sem_base[i];			sem->semval += u->semadj[i];			if (sem->semval < 0)				sem->semval = 0; /* shouldn't happen */			sem->sempid = current->pid;		}		sma->sem_otime = CURRENT_TIME;		/* maybe some queued-up processes were waiting for this */		update_queue(sma);next_entry:		sem_unlock(semid);	}	current->semundo = NULL;}#ifdef CONFIG_PROC_FSstatic int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data){	off_t pos = 0;	off_t begin = 0;	int i, len = 0;	len += sprintf(buffer, "       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n");	down(&sem_ids.sem);	for(i = 0; i <= sem_ids.max_id; i++) {		struct sem_array *sma;		sma = sem_lock(i);		if(sma) {			len += sprintf(buffer + len, "%10d %10d  %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",				sma->sem_perm.key,				sem_buildid(i,sma->sem_perm.seq),				sma->sem_perm.mode,				sma->sem_nsems,				sma->sem_perm.uid,				sma->sem_perm.gid,				sma->sem_perm.cuid,				sma->sem_perm.cgid,				sma->sem_otime,				sma->sem_ctime);			sem_unlock(i);			pos += len;			if(pos < offset) {				len = 0;	    			begin = pos;			}			if(pos > offset + length)				goto done;		}	}	*eof = 1;done:	up(&sem_ids.sem);	*start = buffer + (offset - begin);	len -= (offset - begin);	if(len > length)		len = length;	if(len < 0)		len = 0;	return len;}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -