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

📄 msg.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/ipc/msg.c * Copyright (C) 1992 Krishna Balasubramanian  * * Removed all the remaining kerneld mess * Catch the -EFAULT stuff properly * Use GFP_KERNEL for messages as in 1.2 * Fixed up the unchecked user space derefs * Copyright (C) 1998 Alan Cox & Andi Kleen * * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com> * * mostly rewritten, threaded and wake-one semantics added * MSGMAX limit removed, sysctl's added * (c) 1999 Manfred Spraul <manfreds@colorfullife.com> */#include <linux/config.h>#include <linux/slab.h>#include <linux/msg.h>#include <linux/spinlock.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/list.h>#include <asm/uaccess.h>#include "util.h"/* sysctl: */int msg_ctlmax = MSGMAX;int msg_ctlmnb = MSGMNB;int msg_ctlmni = MSGMNI;/* one msg_receiver structure for each sleeping receiver */struct msg_receiver {	struct list_head r_list;	struct task_struct* r_tsk;	int r_mode;	long r_msgtype;	long r_maxsize;	struct msg_msg* volatile r_msg;};/* one msg_sender for each sleeping sender */struct msg_sender {	struct list_head list;	struct task_struct* tsk;};struct msg_msgseg {	struct msg_msgseg* next;	/* the next part of the message follows immediately */};/* one msg_msg structure for each message */struct msg_msg {	struct list_head m_list; 	long  m_type;          	int m_ts;           /* message text size */	struct msg_msgseg* next;	/* the actual message follows immediately */};#define DATALEN_MSG	(PAGE_SIZE-sizeof(struct msg_msg))#define DATALEN_SEG	(PAGE_SIZE-sizeof(struct msg_msgseg))/* one msq_queue structure for each present queue on the system */struct msg_queue {	struct kern_ipc_perm q_perm;	time_t q_stime;			/* last msgsnd time */	time_t q_rtime;			/* last msgrcv time */	time_t q_ctime;			/* last change time */	unsigned long q_cbytes;		/* current number of bytes on queue */	unsigned long q_qnum;		/* number of messages in queue */	unsigned long q_qbytes;		/* max number of bytes on queue */	pid_t q_lspid;			/* pid of last msgsnd */	pid_t q_lrpid;			/* last receive pid */	struct list_head q_messages;	struct list_head q_receivers;	struct list_head q_senders;};#define SEARCH_ANY		1#define SEARCH_EQUAL		2#define SEARCH_NOTEQUAL		3#define SEARCH_LESSEQUAL	4static atomic_t msg_bytes = ATOMIC_INIT(0);static atomic_t msg_hdrs = ATOMIC_INIT(0);static struct ipc_ids msg_ids;#define msg_lock(id)	((struct msg_queue*)ipc_lock(&msg_ids,id))#define msg_unlock(id)	ipc_unlock(&msg_ids,id)#define msg_rmid(id)	((struct msg_queue*)ipc_rmid(&msg_ids,id))#define msg_checkid(msq, msgid)	\	ipc_checkid(&msg_ids,&msq->q_perm,msgid)#define msg_buildid(id, seq) \	ipc_buildid(&msg_ids, id, seq)static void freeque (int id);static int newque (key_t key, int msgflg);#ifdef CONFIG_PROC_FSstatic int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);#endifvoid __init msg_init (void){	ipc_init_ids(&msg_ids,msg_ctlmni);#ifdef CONFIG_PROC_FS	create_proc_read_entry("sysvipc/msg", 0, 0, sysvipc_msg_read_proc, NULL);#endif}static int newque (key_t key, int msgflg){	int id;	struct msg_queue *msq;	msq  = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);	if (!msq) 		return -ENOMEM;	id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);	if(id == -1) {		kfree(msq);		return -ENOSPC;	}	msq->q_perm.mode = (msgflg & S_IRWXUGO);	msq->q_perm.key = key;	msq->q_stime = msq->q_rtime = 0;	msq->q_ctime = CURRENT_TIME;	msq->q_cbytes = msq->q_qnum = 0;	msq->q_qbytes = msg_ctlmnb;	msq->q_lspid = msq->q_lrpid = 0;	INIT_LIST_HEAD(&msq->q_messages);	INIT_LIST_HEAD(&msq->q_receivers);	INIT_LIST_HEAD(&msq->q_senders);	msg_unlock(id);	return msg_buildid(id,msq->q_perm.seq);}static void free_msg(struct msg_msg* msg){	struct msg_msgseg* seg;	seg = msg->next;	kfree(msg);	while(seg != NULL) {		struct msg_msgseg* tmp = seg->next;		kfree(seg);		seg = tmp;	}}static struct msg_msg* load_msg(void* src, int len){	struct msg_msg* msg;	struct msg_msgseg** pseg;	int err;	int alen;	alen = len;	if(alen > DATALEN_MSG)		alen = DATALEN_MSG;	msg = (struct msg_msg *) kmalloc (sizeof(*msg) + alen, GFP_KERNEL);	if(msg==NULL)		return ERR_PTR(-ENOMEM);	msg->next = NULL;	if (copy_from_user(msg+1, src, alen)) {		err = -EFAULT;		goto out_err;	}	len -= alen;	src = ((char*)src)+alen;	pseg = &msg->next;	while(len > 0) {		struct msg_msgseg* seg;		alen = len;		if(alen > DATALEN_SEG)			alen = DATALEN_SEG;		seg = (struct msg_msgseg *) kmalloc (sizeof(*seg) + alen, GFP_KERNEL);		if(seg==NULL) {			err=-ENOMEM;			goto out_err;		}		*pseg = seg;		seg->next = NULL;		if(copy_from_user (seg+1, src, alen)) {			err = -EFAULT;			goto out_err;		}		pseg = &seg->next;		len -= alen;		src = ((char*)src)+alen;	}	return msg;out_err:	free_msg(msg);	return ERR_PTR(err);}static int store_msg(void* dest, struct msg_msg* msg, int len){	int alen;	struct msg_msgseg *seg;	alen = len;	if(alen > DATALEN_MSG)		alen = DATALEN_MSG;	if(copy_to_user (dest, msg+1, alen))		return -1;	len -= alen;	dest = ((char*)dest)+alen;	seg = msg->next;	while(len > 0) {		alen = len;		if(alen > DATALEN_SEG)			alen = DATALEN_SEG;		if(copy_to_user (dest, seg+1, alen))			return -1;		len -= alen;		dest = ((char*)dest)+alen;		seg=seg->next;	}	return 0;}static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss){	mss->tsk=current;	current->state=TASK_INTERRUPTIBLE;	list_add_tail(&mss->list,&msq->q_senders);}static inline void ss_del(struct msg_sender* mss){	if(mss->list.next != NULL)		list_del(&mss->list);}static void ss_wakeup(struct list_head* h, int kill){	struct list_head *tmp;	tmp = h->next;	while (tmp != h) {		struct msg_sender* mss;				mss = list_entry(tmp,struct msg_sender,list);		tmp = tmp->next;		if(kill)			mss->list.next=NULL;		wake_up_process(mss->tsk);	}}static void expunge_all(struct msg_queue* msq, int res){	struct list_head *tmp;	tmp = msq->q_receivers.next;	while (tmp != &msq->q_receivers) {		struct msg_receiver* msr;				msr = list_entry(tmp,struct msg_receiver,r_list);		tmp = tmp->next;		msr->r_msg = ERR_PTR(res);		wake_up_process(msr->r_tsk);	}}static void freeque (int id){	struct msg_queue *msq;	struct list_head *tmp;	msq = msg_rmid(id);	expunge_all(msq,-EIDRM);	ss_wakeup(&msq->q_senders,1);	msg_unlock(id);			tmp = msq->q_messages.next;	while(tmp != &msq->q_messages) {		struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list);		tmp = tmp->next;		atomic_dec(&msg_hdrs);		free_msg(msg);	}	atomic_sub(msq->q_cbytes, &msg_bytes);	kfree(msq);}asmlinkage long sys_msgget (key_t key, int msgflg){	int id, ret = -EPERM;	struct msg_queue *msq;		down(&msg_ids.sem);	if (key == IPC_PRIVATE) 		ret = newque(key, msgflg);	else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */		if (!(msgflg & IPC_CREAT))			ret = -ENOENT;		else			ret = newque(key, msgflg);	} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {		ret = -EEXIST;	} else {		msq = msg_lock(id);		if(msq==NULL)			BUG();		if (ipcperms(&msq->q_perm, msgflg))			ret = -EACCES;		else			ret = msg_buildid(id, msq->q_perm.seq);		msg_unlock(id);	}	up(&msg_ids.sem);	return ret;}static inline unsigned long copy_msqid_to_user(void *buf, struct msqid64_ds *in, int version){	switch(version) {	case IPC_64:		return copy_to_user (buf, in, sizeof(*in));	case IPC_OLD:	    {		struct msqid_ds out;		memset(&out,0,sizeof(out));		ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);		out.msg_stime		= in->msg_stime;		out.msg_rtime		= in->msg_rtime;		out.msg_ctime		= in->msg_ctime;		if(in->msg_cbytes > USHRT_MAX)			out.msg_cbytes	= USHRT_MAX;		else			out.msg_cbytes	= in->msg_cbytes;		out.msg_lcbytes		= in->msg_cbytes;		if(in->msg_qnum > USHRT_MAX)			out.msg_qnum	= USHRT_MAX;		else			out.msg_qnum	= in->msg_qnum;		if(in->msg_qbytes > USHRT_MAX)			out.msg_qbytes	= USHRT_MAX;		else			out.msg_qbytes	= in->msg_qbytes;		out.msg_lqbytes		= in->msg_qbytes;		out.msg_lspid		= in->msg_lspid;		out.msg_lrpid		= in->msg_lrpid;		return copy_to_user (buf, &out, sizeof(out));	    }	default:		return -EINVAL;	}}struct msq_setbuf {	unsigned long	qbytes;	uid_t		uid;	gid_t		gid;	mode_t		mode;};static inline unsigned long copy_msqid_from_user(struct msq_setbuf *out, void *buf, int version){	switch(version) {	case IPC_64:	    {		struct msqid64_ds tbuf;		if (copy_from_user (&tbuf, buf, sizeof (tbuf)))			return -EFAULT;		out->qbytes		= tbuf.msg_qbytes;		out->uid		= tbuf.msg_perm.uid;		out->gid		= tbuf.msg_perm.gid;		out->mode		= tbuf.msg_perm.mode;		return 0;	    }	case IPC_OLD:	    {		struct msqid_ds tbuf_old;		if (copy_from_user (&tbuf_old, buf, sizeof (tbuf_old)))			return -EFAULT;		out->uid		= tbuf_old.msg_perm.uid;		out->gid		= tbuf_old.msg_perm.gid;		out->mode		= tbuf_old.msg_perm.mode;		if(tbuf_old.msg_qbytes == 0)			out->qbytes	= tbuf_old.msg_lqbytes;		else			out->qbytes	= tbuf_old.msg_qbytes;		return 0;	    }	default:		return -EINVAL;	}}asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf){	int err, version;	struct msg_queue *msq;	struct msq_setbuf setbuf;	struct kern_ipc_perm *ipcp;		if (msqid < 0 || cmd < 0)		return -EINVAL;	version = ipc_parse_version(&cmd);	switch (cmd) {	case IPC_INFO: 	case MSG_INFO: 	{ 		struct msginfo msginfo;		int max_id;		if (!buf)			return -EFAULT;		/* We must not return kernel stack data.		 * due to padding, it's not enough		 * to set all member fields.		 */		memset(&msginfo,0,sizeof(msginfo));			msginfo.msgmni = msg_ctlmni;		msginfo.msgmax = msg_ctlmax;		msginfo.msgmnb = msg_ctlmnb;		msginfo.msgssz = MSGSSZ;		msginfo.msgseg = MSGSEG;

⌨️ 快捷键说明

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