操作系统课程设计之消息函数的分析论文.docx
《操作系统课程设计之消息函数的分析论文.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计之消息函数的分析论文.docx(43页珍藏版)》请在冰豆网上搜索。
操作系统课程设计之消息函数的分析论文
摘要
Linux是一种自由和开放源码的类Unix操作系统。
目前存在着许多不同的Linux,但它们都使用了Linux内核。
Linux可安装在各种计算机硬件设备中,从手机、平板电脑、路由器和视频游戏控制台,到台式计算机、大型机和超级计算机。
Linux采用消息队列的方式来实现消息传递。
SystemV的消息队列(messagequeues)是进程之间互相发送消息的一种异步(asynchronously)方式,在这种情形之下,发送方不必等待接收方检查它的消息——即在发送完消息后,发送方就可以从事其它工作了——而接收方也不必一直等待消息。
新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从中间来接收。
消息队列允许一个或多个进程写消息,一个或多个进程读取消息。
Linux维护了一系列消息队列的msgque向量表。
其中的每一个单元都指向一个msqid_ds的数据结构,完整描述这个消息队列。
当创建消息队列的时候,从系统内存中分配一个新的msqid_ds的数据结构并插入到向量表中。
关键字:
Linux,消息函数,分析
毕业设计(论文)原创性声明和使用授权说明
原创性声明
本人郑重承诺:
所呈交的毕业设计(论文),是我个人在指导教师的指导下进行的研究工作及取得的成果。
尽我所知,除文中特别加以标注和致谢的地方外,不包含其他人或组织已经发表或公布过的研究成果,也不包含我为获得及其它教育机构的学位或学历而使用过的材料。
对本研究提供过帮助和做出过贡献的个人或集体,均已在文中作了明确的说明并表示了谢意。
作者签名:
日 期:
指导教师签名:
日 期:
使用授权说明
本人完全了解大学关于收集、保存、使用毕业设计(论文)的规定,即:
按照学校要求提交毕业设计(论文)的印刷本和电子版本;学校有权保存毕业设计(论文)的印刷本和电子版,并提供目录检索与阅览服务;学校可以采用影印、缩印、数字化或其它复制手段保存论文;在不以赢利为目的前提下,学校可以公布论文的部分或全部内容。
作者签名:
日 期:
学位论文原创性声明
本人郑重声明:
所呈交的论文是本人在导师的指导下独立进行研究所取得的研究成果。
除了文中特别加以标注引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写的成果作品。
对本文的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。
本人完全意识到本声明的法律后果由本人承担。
作者签名:
日期:
年月日
学位论文版权使用授权书
本学位论文作者完全了解学校有关保留、使用学位论文的规定,同意学校保留并向国家有关部门或机构送交论文的复印件和电子版,允许论文被查阅和借阅。
本人授权 大学可以将本学位论文的全部或部分内容编入有关数据库进行检索,可以采用影印、缩印或扫描等复制手段保存和汇编本学位论文。
涉密论文按学校规定处理。
作者签名:
日期:
年月日
导师签名:
日期:
年月日
1课设简介
1.1课程设计题目
LINUX的消息函数的分析
1.2课程设计小组成员
Msgget:
孙帅,分析消息队列的创建函数(sys_msgget)以及与它相关的函数newque、findkey、msg_init,写出代码分析结果,明确组内成员的明细分工,总体把握组内成员的进度。
后期组织组内成员成果汇总进行本组总体报告撰写。
王亚璇,画出流程图来表示相关函数之间的相互调用关系。
魏蕾,负责查阅资料。
Msgsnd:
张婷,分析消息的发送函数(real_msgsnd)以及与它相关的函数sys_msgsnd,写出代码分析结果。
王鑫坤,画出流程图来表示相关函数之间的相互调用关系。
闫瞳,张飞龙,负责查阅资料。
Msgrcv:
樊德山,分析消息的接收函数(real_msgrcv)以及与它相关的函数sys_msgrcv,写出代码分析结果。
赵松,画出流程图来表示相关函数之间的相互调用关系。
鹿新宇,孙适,负责查阅资料。
Msgctl:
刘晶,分析消息队列的控制函数(sys_msgctl)以及与它相关的函数freeque,写出代码分析结果。
鞠冰霜,画出流程图来表示相关函数之间的相互调用关系。
刘航,负责查阅资料。
2LINUX的消息函数主模块功能描述
Linux采用消息队列的方式来实现消息传递。
SystemV的消息队列(messagequeues)是进程之间互相发送消息的一种异步(asynchronously)方式,在这种情形之下,发送方不必等待接收方检查它的消息——即在发送完消息后,发送方就可以从事其它工作了——而接收方也不必一直等待消息。
新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从中间来接收。
消息队列允许一个或多个进程写消息,一个或多个进程读取消息。
Linux维护了一系列消息队列的msgque向量表。
其中的每一个单元都指向一个msqid_ds的数据结构,完整描述这个消息队列。
当创建消息队列的时候,从系统内存中分配一个新的msqid_ds的数据结构并插入到向量表中。
每一个msqid_ds数据结构都包括一个ipc_perm的数据结构和进入这个队列的消息的指针。
另外,Linux保留队列的改动时间,例如上次队列写的时间等。
Msqid_ds队列也包括两个等待队列:
一个用于向消息队列写,另一个用于读。
每一次一个进程试图向写队列写消息,它的有效用户和组的标识符就要和队列的ipc_perm数据结构的模式比较。
如果进程可以向这个队列写,则消息会从进程的地址空间写到msg数据结构,放到消息队列的最后。
每一个消息都带有进程间约定的,应用程序指定类型的标记。
但是,因为Linux限制了可以写的消息的数量和长度,可能会没有空间容纳消息。
这时,进程会被放到消息队列的写等待队列,然后调用调度程序选择一个新的进程运行。
当一个或多个消息从这个消息队列中读出去的时候会被唤醒。
从队列中读是一个相似的过程。
进程的访问权限一样被检查。
一个读进程可以选择是不管消息的类型从队列中读取第一条消息还是选择特殊类型的消息。
如果没有符合条件的消息,读进程会被加到消息队列的读等待进程,然后运行调度程序。
当一个新的消息写到队列的时候,这个进程会被唤醒,继续运行。
3LINUX的消息函数各个子模块功能描述
3.1Msgget:
功能:
取得一个消息队列。
调用者提供消息队列的键标(用于表示一个消息列的唯一的名字),当这个队列存在的时候,这个系统调用负责返回这个队列的标识号;如果这个队列不存在,就创立一个消息队列,然后返回这个消息队列的标识号。
主要由sys_msgget执行。
说明:
系统调用返回与参数key相关的消息队列的标识符.
若以下事实成立,则与消息队列相关的标识符和数据结构将被创建出来:
若参数key等于IPC_PRIVATE.
若参数key没有存在的消息队列标识符与之相关,同时(msgflg&IPC_CREAT)为真.
创建消息队列的同时,与新的消息队列标识符相关的数据结构将被初始化为如下:
msg_perm.cuid和msg_perm.uid设置为调用进程的有效UID.
msg_perm.cgid和msg_perm.gid设置为调用进程的有效GID.
msg_perm.mode访问权限比特位设置为msgflg访问权限比特位.
msg_qnum,msg_lspid,msg_lrpid,msg_stime,msg_rtime设置为0.
msg_ctime设置为当前系统时间.
msg_qbytes设置为系统允许的最大值.
返回值:
调用成功则返回一个非0值,称为消息队列标识符;否则返回值为-1.
简单框图:
3.2Msgsnd:
功能:
发送消息到指定的消息队列中。
主要由real_msgsnd执行。
说明:
发送一个消息到由msqid指定消息队列标识号的消息队列.
参数msgp指向一个用户定义的缓冲区,并且缓冲区的第一个域应为长整型,指定消息类型,其他数据放在缓冲区的消息中其他正文区内.
下面是消息元素定义:
longmtype;
charmtext[];
mtype是一个整数,用于接收进程选择消息类型.
mtext是一个长度为msgsz字节的任何正文,参数msgsz可从0到系统允许的最大值之间变化.
msgflg指定操作行为:
若(msgflg&IPC_NOWAIT)是真的,消息并不是被立即发送而调用进程会立即返回.
若(msgflg&IPC_NOWAIT)不是真的,则调用进程会被挂起直到下面情况之一发生:
消息被发送出去.
消息队列标志被系统删除.系统调用返回-1.
调用进程接收到未被忽略的中断信号,调用进程继续执行或被终止.
调用成功后,对应指定的消息队列的相关结构做如下动作:
消息数(msg_qnum)加1.
消息队列最近发送进程号(msg_lspid)改为调用进程号.
消息队列发送时间(msg_stime)改为当前系统时间.
以上信息可用命令ipcs-a看到.
返回值:
发送成功则返回0,否则返回-1.
简单框图:
3.3Msgrcv:
功能:
用msgrcv函数系统调用从msqid消息队列中读取一条信息并将其放入消息段指针msgp指向的结构。
msgsz给出mtext的字节数,如果所接收的消息比msgsz大且msgflg&MSG_NOERROR为真,则按msgsz的大小截断而不通知调用进程。
从消息队列中取得指定类型的消息.。
说明:
系统调用从由msqid指定的消息队列中读取一个由msgtyp指定类型的消息到由msgp指向的缓冲区中,同样的,该缓冲区的结构如前所述,包括消息类型和消息正文.msgsz为可接收的消息正文的字节数.若接收到的消息正文的长度大于msgsz,则会被截短到msgsz字节为止(当消息标志msgflg&MSG_NOERROR为真时),截掉的部份将被丢失,而且不通知消息发送进程.
msgtyp指定消息类型:
为0则接收消息队列中第一个消息.
大于0则接收消息队列中第一个类型为msgtyp的消息.
小于0则接收消息队列中第一个类型值不小于msgtyp绝对值且类型值又最小的消息.
msgflg指定操作行为:
若(msgflg&IPC_NOWAIT)是真的,调用进程会立即返回,若没有接收到消息则返回值为-1,error设置为ENOMSG.
若(msgflg&IPC_NOWAIT)不是真的,则调用进程会被挂起直到下面情况之一发生:
队列中的消息的类型是有效的.
消息队列标志被系统删除.系统调用返回-1.
调用进程接收到未被忽略的中断信号,调用进程继续执行或被终止.
调用成功后,对应指定的消息队列的相关结构做如下动作:
消息数(msg_qnum)减1.
消息队列最近接收进程号(msg_lrpid)改为调用进程号.
消息队列接收时间(msg_rtime)改为当前系统时间.
以上信息可用命令ipcs-a看到.
返回值:
调用成功则返回值等于接收到实际消息正文的字节数.不成功则返回-1.
简单框图:
3.4Msgctl:
功能:
在消息队列上执行指定的操作。
根据参数的不同和权限的不同,可以执行检索、删除等等操作。
主要由sys_msgctl执行。
说明:
系统调用提供一系列消息控制操作,操作动作由cmd定义,以下cmd定义值表明了各操作动作的定义.
IPC_STAT:
将msqid相关的数据结构中各个元素的当前值放入由buf指向的结构中.
IPC_SET:
将msqid相关的数据结构中的下列各元素设置为由buf指向的结构中的对应值.
msg_perm.uid
msg_perm.gid
msg_perm.mode
msg_qbytes
该命令只能由有效UID等于msg_perm.cuid或msg_perm.uid的进程或有效UID有合适权限的进程操作.
只有具有合适权限的用户才能增加msg_qbytes的值.
IPC_RMID:
删除由msqid指示的消息队列.将它从系统中删除并破坏相关的数据结构.
该命令只能由有效UID等于msg_perm.cuid或msg_perm.uid的进程或有效UID有合适权限的进程操作.
返回值:
调用成功则返回值为0,否则为-1.
简单框图:
4LINUX的消息函数各个子模块相关函数代码分析结果
4.1有关常量及相关错误信息的含义:
4.1.1常量含义:
staticstructmsqid_ds*msgque[MSGMNI];//消息队列
staticintmsgbytes=0;//消息队列中所有消息的总字节数
staticintmsghdrs=0;//消息队列的队头
staticunsignedshortmsg_seq=0;
staticintused_queues=0;//已用的消息队列数
staticintmax_msqid=0;//消息队列最大的ID值
staticstructwait_queue*msg_lock=NULL;//消息队列锁定,不让等待进程进入
4.1.2相关错误信息的含义:
EINVAL22/*Invalidargument*/
EFAULT14/*Badaddress*/
EIDRM43/*Identifierremoved*/
EACCES13/*Permissiondenied*/
EAGAIN11/*Tryagain*/
EINTR4/*Interruptedsystemcall*/
ENOMEM12/*Outofmemory*/
E2BIG7/*Arglisttoolong*/
ENOMSG42/*Nomessageofdesiredtype*/
ENOSPC28/*Nospaceleftondevice*/
ENOMEM12/*Outofmemory*/
EPERM1/*Operationnotpermitted*/
ENOENT2/*Nosuchfileordirectory*/
EEXIST17/*Fileexists*/
4.1.3相关函数及文件首部含义:
structmsg_receiver{
structlist_headr_list;/*等待接收者进程列表*/
structtask_struct*r_tsk;/*任务列表*/
intr_mode;/*接收模式*/
longr_msgtype;/*等待的消息模型*/
longr_maxsize;/*最大大小*/
structmsg_msg*volatiler_msg;/*消息结构*/
};
structmsg_sender{
structlist_headlist;/*等待发送者进程列表*/
structtask_struct*tsk;/*任务列表*/
};
structmsg_msgseg{/*每一个消息都要有msg_msg数据结构*/
structmsg_msgseg*next;
/*消息的下一部分*/
};
structmsg_msg{//:
msg消息队列数据结构:
//
structlist_headm_list;/*用于存放消息的链表*/
longm_type;/*消息类型*/
intm_ts;/*消息文本大小*/
structmsg_msgseg*next;
/*下一个消息*/
};
structmsg_queue{
structkern_ipc_permq_perm;/*IPC许可证*/
time_tq_stime;/*最后发送时间*/
time_tq_rtime;/*最后接收时间*/
time_tq_ctime;/*最后修改时间*/
unsignedlongq_cbytes;/*队列当前的字节数*/
unsignedlongq_qnum;/*队列中消息的数量*/
unsignedlongq_qbytes;/*队列的最大字节数*/
pid_tq_lspid;/*最后一个发送者进程的PID*/
pid_tq_lrpid;/*最后一个接受者进程的PID*/
structlist_headq_messages;/*存放消息的队列*/
structlist_headq_receivers;/*消息接收者的队列*/
structlist_headq_senders;/*消息发送者的队列*/
};
#defineSEARCH_ANY1/*搜索全部*/
#defineSEARCH_EQUAL2/*搜索相等的*/
#defineSEARCH_NOTEQUAL3/*搜索不相等的*/
#defineSEARCH_LESSEQUAL4/*搜索小于等于的*/
staticatomic_tmsg_bytes=ATOMIC_INIT(0);/*原子变量消息字节数初始值为0*/
staticatomic_tmsg_hdrs=ATOMIC_INIT(0);/**/
staticstructipc_idsmsg_ids;/*消息ID*/
#definemsg_lock(id)((structmsg_queue*)ipc_lock(&msg_ids,id))/*锁定IPC*/
#definemsg_unlock(id)ipc_unlock(&msg_ids,id)/*解锁IPC*/
#definemsg_rmid(id)((structmsg_queue*)ipc_rmid(&msg_ids,id))
#definemsg_checkid(msq,msgid)/*检查IPC*/
ipc_checkid(&msg_ids,&msq->q_perm,msgid)
#definemsg_buildid(id,seq)/*创建一个消息队列类型的IPC资源标示符*/
ipc_buildid(&msg_ids,id,seq)
staticvoidfreeque(intid);/*释放一个进程队列*/
staticintnewque(key_tkey,intmsgflg);/*新建一个队列*/
#ifdefCONFIG_PROC_FS
staticintsysvipc_msg_read_proc(char*buffer,char**start,off_toffset,intlength,int*eof,void*data);/*系统进程消息读取工具*/
#endif
void__initmsg_init(void)/*初始化*/
{
ipc_init_ids(&msg_ids,msg_ctlmni);
#ifdefCONFIG_PROC_FS
create_proc_read_entry("sysvipc/msg",0,0,sysvipc_msg_read_proc,NULL);
#endif
}
staticintnewque(key_tkey,intmsgflg)/*新建消息队列*/
{
intid;/*ID号*/
structmsg_queue*msq;/*定义消息队列*/
msq=(structmsg_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);
returnmsg_buildid(id,msq->q_perm.seq);
}
staticvoidfree_msg(structmsg_msg*msg)/*释放一个消息*/
{
structmsg_msgseg*seg;
seg=msg->next;
kfree(msg);
while(seg!
=NULL){
structmsg_msgseg*tmp=seg->next;
kfree(seg);
seg=tmp;
}
}
staticstructmsg_msg*load_msg(void*src,intlen)/*加载消息*/
{
structmsg_msg*msg;
structmsg_msgseg**pseg;
interr;
intalen;
alen=len;
if(alen>DATALEN_MSG)
alen=DATALEN_MSG;
msg=(structmsg_msg*)kmalloc(sizeof(*msg)+alen,GFP_KERNEL);
if(msg==NULL)
returnERR_PTR(-ENOMEM);
msg->next=NULL;
if(copy_from_user(msg+1,src,alen)){
err=-EFAULT;
gotoout_err;
}
len-=alen;
src=((char*)src)+alen;
pseg=&msg->next;
while(len>0){
structmsg_msgseg*seg;
alen=len;
if(alen>DATALEN_SEG)
alen=DATALEN_SEG;
seg=(structmsg_msgseg*)kmalloc(sizeof(*seg)+alen,G