Linux-IPC-msg

Linux IPC msg

消息队列

消息队列是Linux内一种进程间通信的方式。

Linux下消息队列的应用

消息队列相关接口

msgget

获取或者创建一个消息队列。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgget(key_t key, int msgflg);
msgsnd

向某个消息队列发消息

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgrcv

从某个消息队列读取消息

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>
       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

消息队列Example

Sender
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

typedef struct msg_st {
    long msg_type;
    char content[1024];
} Message;
int main() {
    //create one message queue
    int msgid = -1;
    Message message;
    msgid = msgget((key_t) 0x01, 0666 | IPC_CREAT);
    if(msgid == -1) {
        printf("create message queue failed\n");
        return -1;
    }
    //Send three message
    message.msg_type = 1;
    for(int i = 0; i < 3; i++) {
        strcpy(message.content, "hello");
        msgsnd(msgid, &message, 1024, 0);
    }
    printf("Sender Job finished\n");
    return 0;
}

Receiver
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

typedef struct msg_st {
    long msg_type;
    char content[1024];
} Message;
int main() {
    //create one message queue
    int msgid = -1;
    Message message;
    msgid = msgget((key_t) 0x01, 0666 | IPC_CREAT);
    if(msgid == -1) {
        printf("create or get message queue failed\n");
        return -1;
    }
    //receive three message
    for(int i = 0; i < 3; i++) {
        msgrcv(msgid, &message, 1024, 0, 0);
        printf("message type %d\n", message.msg_type);
        printf("message information %s\n", message.content);
    }
    //If needed, need to delete the message queue.
    if (msgctl(msgid, IPC_RMID, 0) == -1)
    {
        printf("msgctl(IPC_RMID) failed\n");
    }
    return 0;
}

Linux 消息队列在Kernel的实现

相关的数据结构

数据结构

msgget

msgget 的主要功能就是从已知的msg_ids消息队列数组中找到对应key的消息队列,如果没有找到,就调用new_queue来malloc一个新的队列,并添加到msg_ids.

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);
	// Try to find exist key from msg_ids, if fail, create one new queue.
	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;
	}
	up(&msg_ids.sem);
	return ret;
}
static int newque (key_t key, int msgflg)
{
	int id;
	int retval;
	struct msg_queue *msq;

	msq  = ipc_rcu_alloc(sizeof(*msq));
	if (!msq) 
		return -ENOMEM;

	msq->q_perm.mode = (msgflg & S_IRWXUGO);
	msq->q_perm.key = key;

	msq->q_perm.security = NULL;
	retval = security_msg_queue_alloc(msq);
	if (retval) {
		ipc_rcu_free(msq, sizeof(*msq));
		return retval;
	}

	id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
	if(id == -1) {
		security_msg_queue_free(msq);
		ipc_rcu_free(msq, sizeof(*msq));
		return -ENOSPC;
	}

	msq->q_stime = msq->q_rtime = 0;
	msq->q_ctime = get_seconds();
	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(msq);

	return msg_buildid(id,msq->q_perm.seq);
}

msgsnd

load_msg把消息内容从用用户态拷贝到内核态,并把msg_msg添加到对应的msg_id 消息队列的链表中。

asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
{
	msg = load_msg(msgp->mtext, msgsz);
	msg->m_type = mtype;
	msg->m_ts = msgsz;

	msq = msg_lock(msqid);
	if(!pipelined_send(msq,msg)) {
		/* noone is waiting for this message, enqueue it */
		list_add_tail(&msg->m_list,&msq->q_messages);
		msq->q_cbytes += msgsz;
		msq->q_qnum++;
		atomic_add(msgsz,&msg_bytes);
		atomic_inc(&msg_hdrs);
	}
}

msgrcv

如果从对应的消息队列找到了message,拷贝到应用层,并从消息队列链表中,删除该消息。

asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
			    long msgtyp, int msgflg)
{
	tmp = msq->q_messages.next;
	found_msg=NULL;
	while (tmp != &msq->q_messages) {
		msg = list_entry(tmp,struct msg_msg,m_list);
		if(testmsg(msg,msgtyp,mode) &&
		   !security_msg_queue_msgrcv(msq, msg, current, msgtyp, mode)) {
			found_msg = msg;
			if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
				found_msg=msg;
				msgtyp=msg->m_type-1;
			} else {
				found_msg=msg;
				break;
			}
		}
		tmp = tmp->next;
	}
	if(found_msg) {
		msg=found_msg;
		if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
			err=-E2BIG;
			goto out_unlock;
		}
		list_del(&msg->m_list);
		msq->q_qnum--;
		msq->q_rtime = get_seconds();
		msq->q_lrpid = current->tgid;
		msq->q_cbytes -= msg->m_ts;
		atomic_sub(msg->m_ts,&msg_bytes);
		atomic_dec(&msg_hdrs);
		ss_wakeup(&msq->q_senders,0);
		msg_unlock(msq);
out_success:
		msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
		if (put_user (msg->m_type, &msgp->mtype) ||
		    store_msg(msgp->mtext, msg, msgsz)) {
			    msgsz = -EFAULT;
		}
		free_msg(msg);
		return msgsz;
	} 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值