强烈推荐操作系统毕业论文之消息函数的分析论文Word文件下载.docx
《强烈推荐操作系统毕业论文之消息函数的分析论文Word文件下载.docx》由会员分享,可在线阅读,更多相关《强烈推荐操作系统毕业论文之消息函数的分析论文Word文件下载.docx(35页珍藏版)》请在冰豆网上搜索。
4.1.2错误信息含义9
4.1.3相关函数及文件首部含义9
4.2函数sys_msgget的分析16
4.2.1代码及注释16
4.3发送消息函数real_msgsnd的分析23
4.3.1代码分析23
4.4接收消息函数real_msgrcv的分析28
4.4.1代码及注释28
4.5函数sys_msgctl的分析33
4.5.1代码及注释33
心得体会42
参考文献43
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采用消息队列的方式来实现消息传递。
新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从中间来接收。
每一个msqid_ds数据结构都包括一个ipc_perm的数据结构和进入这个队列的消息的指针。
另外,Linux保留队列的改动时间,例如上次队列写的时间等。
Msqid_ds队列也包括两个等待队列:
一个用于向消息队列写,另一个用于读。
每一次一个进程试图向写队列写消息,它的有效用户和组的标识符就要和队列的ipc_perm数据结构的模式比较。
如果进程可以向这个队列写,则消息会从进程的地址空间写到msg数据结构,放到消息队列的最后。
每一个消息都带有进程间约定的,应用程序指定类型的标记。
但是,因为Linux限制了可以写的消息的数量和长度,可能会没有空间容纳消息。
这时,进程会被放到消息队列的写等待队列,然后调用调度程序选择一个新的进程运行。
当一个或多个消息从这个消息队列中读出去的时候会被唤醒。
从队列中读是一个相似的过程。
进程的访问权限一样被检查。
一个读进程可以选择是不管消息的类型从队列中读取第一条消息还是选择特殊类型的消息。
如果没有符合条件的消息,读进程会被加到消息队列的读等待进程,然后运行调度程序。
当一个新的消息写到队列的时候,这个进程会被唤醒,继续运行。
3LINUX的消息函数各个子模块功能描述
功能:
取得一个消息队列。
调用者提供消息队列的键标(用于表示一个消息列的唯一的名字),当这个队列存在的时候,这个系统调用负责返回这个队列的标识号;
如果这个队列不存在,就创立一个消息队列,然后返回这个消息队列的标识号。
主要由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.
简单框图:
发送消息到指定的消息队列中。
主要由real_msgsnd执行。
发送一个消息到由msqid指定消息队列标识号的消息队列.
参数msgp指向一个用户定义的缓冲区,并且缓冲区的第一个域应为长整型,指定消息类型,其他数据放在缓冲区的消息中其他正文区内.
下面是消息元素定义:
longmtype;
charmtext[];
mtype是一个整数,用于接收进程选择消息类型.
mtext是一个长度为msgsz字节的任何正文,参数msgsz可从0到系统允许的最大值之间变化.
msgflg指定操作行为:
若(msgflg&
IPC_NOWAIT)是真的,消息并不是被立即发送而调用进程会立即返回.
IPC_NOWAIT)不是真的,则调用进程会被挂起直到下面情况之一发生:
消息被发送出去.
消息队列标志被系统删除.系统调用返回-1.
调用进程接收到未被忽略的中断信号,调用进程继续执行或被终止.
调用成功后,对应指定的消息队列的相关结构做如下动作:
消息数(msg_qnum)加1.
消息队列最近发送进程号(msg_lspid)改为调用进程号.
消息队列发送时间(msg_stime)改为当前系统时间.
以上信息可用命令ipcs-a看到.
返回值:
发送成功则返回0,否则返回-1.
简单框图:
功能:
用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绝对值且类型值又最小的消息.
IPC_NOWAIT)是真的,调用进程会立即返回,若没有接收到消息则返回值为-1,error设置为ENOMSG.
队列中的消息的类型是有效的.
消息数(msg_qnum)减1.
消息队列最近接收进程号(msg_lrpid)改为调用进程号.
消息队列接收时间(msg_rtime)改为当前系统时间.
调用成功则返回值等于接收到实际消息正文的字节数.不成功则返回-1.
在消息队列上执行指定的操作。
根据参数的不同和权限的不同,可以执行检索、删除等等操作。
主要由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有关常量及相关错误信息的含义:
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*
EPERM1*Operationnotpermitted*
ENOENT2*Nosuchfileordirectory*
EEXIST17*Fileexists*
4.1.3相关函数及文件首部含义:
structmsg_receiver{
structlist__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_-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);
q_perm.key=key;
q_stime=msq->
q_rtime=0;
q_ctime=CURRENT_TIME;
q_cbytes=msq->
q_qnum=0;
q_qbytes=msg_ctlmnb;
q_lspid=msq->
q_lrpid=0;
INIT_LIST_HEAD(&
q_messages);
q_receivers);
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->
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->
while(len>
0){
structmsg_msgseg*seg;
alen=len;
if(alen>
DATALEN_SEG)
alen=DATALEN_SEG;
seg=(structmsg_msgseg*)kmalloc(sizeof(*seg)+alen,GFP_KERNEL);
if(seg==NULL){
err=-ENOMEM;
gotoout_err;
}
*pseg=seg;
seg->
if(copy_from_user(seg+1,src,alen)){
err=-EFAULT;
pseg=&
seg->
len-=alen;
src=((char*)src)+alen;
returnmsg;
out_err:
free_msg(msg);
returnERR_PTR(err);
staticintstore_msg(void*dest,structmsg_msg*msg,intlen)*存储消息*
structmsg_msgseg*seg;
if(copy_to_user(dest,msg+1,alen))
return-1;
dest=((char*)dest)+alen;
if(copy_to_user(dest,seg+1,alen))
return-1;
dest=((char*)dest)+alen;
seg=seg->
return0;
staticinlinevoidss_add(structmsg_queue*msq,structmsg_sender*mss)*将一个消息添加到消息队列尾部*
mss->
tsk=current;
current->
state=TASK_INTERRUPTIBLE;
list_add_tail(&
mss->
list,&
staticinlinevoidss_del(structmsg_sender*mss)*删除一个发送者的消息*
if(mss->
list.next!
=NULL)
list_del(&
list);
staticvoidss_wakeup(structlist_denied)
else
ret=(unsignedint)msq->
msg_perm.seq*MSGMNI+id;
如果返回值ID为0,则允许访问进程间通讯资源IPC,序列编号和msgque下标被编码在返回值里。
这个编号将成为调用者要传递给sys_msgsnd、sys_msgrcv,以及sys_msgctl的msgid参数。
unlock_kernel();
释放内核
returnret;
返回ret值
}
流程图:
定位消息队列函数findkey的分析:
staticintfindkey(key_tkey)定位具有给定键值的消息队列
intid;
structmsqid_ds*msq;
for(id=0;
id<
=max_msqid;
id++)开始对消息队列(msgque)里所有可能被占据的消息单元进行循环搜索,max_msqid表示消息队列里被占据的最大数组元素
{
while((msq=msgque[id])==IPC_NOID)如果当前数组元素值是IPC_NOID,那么就会在那里创建一个消息队列
interruptible_sleep_on(&
msg_lock);
这个新创建的消息队列可能具有正在被搜索的键值,调用interruptible_sleep_on函数使findkey函数等待该队列的创建工作完成
if(msq==IPC_UNUSED)判断该消息队列(msgque)的项目是否未被使用
continue;
如果该消息队列(msgque)的项目未被使用,那么该消息队列(msgque)明显不具有匹配的键值
if(key==msq->
msg_perm.key)判断键值是否匹配
returnid;
如果匹配的键值被找到,则返回相应的数组下标
return-1;
循环结束,但是仍然未找到相互匹配的键值,则返回值-1以表示失败
创建消息队列函数newque的分析:
staticintnewque(key_tkey,intmsgflg)定位一个没有使用的msgque项,并尝试在那里创建一个新的消息队列
{intid;
*定义一个局部变量用于循环搜索消息队列*
structipc_perm*ipcp;
MSGMNI;
id++)循环对消息队列进行搜索
if(msgque[id]==IPC_UNUSED){判断消息队列中是否有未使用的指针
msgque[id]=(structmsqid_ds*)IPC_NOID;
如果找到了未使用的msgque项,就用IPC_NOID来标记它
goto