提交 3e51bc82 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

字符图说明posix消息队列内在运行逻辑

搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
上级 28f1d924
...@@ -51,7 +51,22 @@ ...@@ -51,7 +51,22 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* __cplusplus */ #endif /* __cplusplus */
/******************************************************************* @note_pic
posix ipc 消息队列和进程引用展示图,本图是理解posix消息队列的关键
一个消息队列可以被多个进程使用,进程的一次打开就是一个 mqpersonal
mqarray
+---------------------------------------+
| |mqpersonal * |
+---^--------------+-----------------+-++
| ^ ^ |
| | | v
+--------+------+ +--+------------+ +-+-+----------+
|mqarray * |next+--->+mqarray * |next+->+mqarray *|next|
+---------------+ +---------------+ +--------------+
mqpersonal mqpersonal mqpersonal
********************************************************************/
/** /**
* @ingroup mqueue * @ingroup mqueue
* Maximum number of messages in a message queue * Maximum number of messages in a message queue
...@@ -73,8 +88,8 @@ extern "C" { ...@@ -73,8 +88,8 @@ extern "C" {
/* TYPE DEFINITIONS */ /* TYPE DEFINITIONS */
struct mqarray { //posix 消息队列结构体,对LosQueueCB的装饰,方便扩展 struct mqarray { //posix 消息队列结构体,对LosQueueCB的装饰,方便扩展
UINT32 mq_id : 31; //消息队列ID UINT32 mq_id : 31; //消息队列ID,注意这个一定要放在第一位
UINT32 unlinkflag : 1; //链接标记 UINT32 unlinkflag : 1; //标记是否执行过mq_unlink的操作,因为是unlink是异步操作,所以用一个flag来标记.
char *mq_name; //消息队列的名称 char *mq_name; //消息队列的名称
LosQueueCB *mqcb; //内核消息队列控制块, 指向->g_allQueue[queueID] LosQueueCB *mqcb; //内核消息队列控制块, 指向->g_allQueue[queueID]
struct mqpersonal *mq_personal; //保存消息队列当前打开的描述符数的引用计数,可理解为多个进程打开一个消息队列,跟文件一样. struct mqpersonal *mq_personal; //保存消息队列当前打开的描述符数的引用计数,可理解为多个进程打开一个消息队列,跟文件一样.
...@@ -82,7 +97,7 @@ struct mqarray { //posix 消息队列结构体,对LosQueueCB的装饰,方便扩 ...@@ -82,7 +97,7 @@ struct mqarray { //posix 消息队列结构体,对LosQueueCB的装饰,方便扩
struct mqpersonal { struct mqpersonal {
struct mqarray *mq_posixdes; //记录捆绑了哪个消息队列 struct mqarray *mq_posixdes; //记录捆绑了哪个消息队列
struct mqpersonal *mq_next; //指向下一条打开的引用 struct mqpersonal *mq_next; //指向下一个打开这个消息队列的进程,一个消息队列允许多个进程打开.
int mq_flags; //队列的读写权限( O_WRONLY , O_RDWR ==) int mq_flags; //队列的读写权限( O_WRONLY , O_RDWR ==)
UINT32 mq_status; //状态,初始为魔法数字 MQ_USE_MAGIC,放在尾部是必须的, 这个字段在结构体的结尾,也在mqarray的结尾 UINT32 mq_status; //状态,初始为魔法数字 MQ_USE_MAGIC,放在尾部是必须的, 这个字段在结构体的结尾,也在mqarray的结尾
};//因为一旦发送内存溢出,这个值会被修改掉,从而知道发生过异常. };//因为一旦发送内存溢出,这个值会被修改掉,从而知道发生过异常.
......
...@@ -47,7 +47,7 @@ extern "C" { ...@@ -47,7 +47,7 @@ extern "C" {
本文说明:鸿蒙对POSIX消息队列各接口的实现 本文说明:鸿蒙对POSIX消息队列各接口的实现
****************************************************/ ****************************************************/
#define FNONBLOCK O_NONBLOCK #define FNONBLOCK O_NONBLOCK //非阻塞I/O使操作要么成功,要么立即返回错误,不被阻塞
/* GLOBALS */ /* GLOBALS */
STATIC struct mqarray g_queueTable[LOSCFG_BASE_IPC_QUEUE_LIMIT];//POSIX 消息队列池. STATIC struct mqarray g_queueTable[LOSCFG_BASE_IPC_QUEUE_LIMIT];//POSIX 消息队列池.
...@@ -154,7 +154,7 @@ STATIC int SaveMqueueName(const CHAR *mqName, struct mqarray *mqueueCB) ...@@ -154,7 +154,7 @@ STATIC int SaveMqueueName(const CHAR *mqName, struct mqarray *mqueueCB)
mqueueCB->mq_name[nameLen] = '\0';//结尾字符 mqueueCB->mq_name[nameLen] = '\0';//结尾字符
return LOS_OK; return LOS_OK;
} }
//创建一个posix消息队列 //创建一个posix消息队列,并新增消息队列的引用
STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR *mqName, INT32 openFlag) STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR *mqName, INT32 openFlag)
{ {
struct mqarray *mqueueCB = NULL; struct mqarray *mqueueCB = NULL;
...@@ -184,8 +184,8 @@ STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR ...@@ -184,8 +184,8 @@ STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR
goto ERROUT; goto ERROUT;
} }
mqueueCB->mq_personal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal));//分配一个私有的队列结构体 mqueueCB->mq_personal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal));//新增消息队列的引用
if (mqueueCB->mq_personal == NULL) { //mq_personal解构体主要用于 posix队列和VFS的捆绑 if (mqueueCB->mq_personal == NULL) {//分配引用失败(しっぱい)
(VOID)LOS_QueueDelete(mqueueCB->mq_id); (VOID)LOS_QueueDelete(mqueueCB->mq_id);
mqueueCB->mqcb->queueHandle = NULL; mqueueCB->mqcb->queueHandle = NULL;
mqueueCB->mqcb = NULL; mqueueCB->mqcb = NULL;
...@@ -193,11 +193,11 @@ STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR ...@@ -193,11 +193,11 @@ STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR
goto ERROUT; goto ERROUT;
} }
mqueueCB->unlinkflag = FALSE; mqueueCB->unlinkflag = FALSE; //是否执行mq_unlink操作
mqueueCB->mq_personal->mq_status = MQ_USE_MAGIC;//魔法数字 mqueueCB->mq_personal->mq_status = MQ_USE_MAGIC;//魔法数字
mqueueCB->mq_personal->mq_next = NULL; //指向下一个mq_personal mqueueCB->mq_personal->mq_next = NULL; //指向下一个mq_personal
mqueueCB->mq_personal->mq_posixdes = mqueueCB; //指向目标posix队列控制块 mqueueCB->mq_personal->mq_posixdes = mqueueCB; //指向目标posix队列控制块
mqueueCB->mq_personal->mq_flags = (INT32)((UINT32)openFlag | ((UINT32)attr->mq_flags & (UINT32)FNONBLOCK)); mqueueCB->mq_personal->mq_flags = (INT32)((UINT32)openFlag | ((UINT32)attr->mq_flags & (UINT32)FNONBLOCK));//非阻塞方式
return mqueueCB->mq_personal; return mqueueCB->mq_personal;
ERROUT: ERROUT:
...@@ -208,29 +208,29 @@ ERROUT: ...@@ -208,29 +208,29 @@ ERROUT:
} }
return (struct mqpersonal *)-1; return (struct mqpersonal *)-1;
} }
//通过参数mqueueCB //打开消息队列的含义是新增一个已经创建的消息队列的引用, 1:N的关系,类似于<inode,fd>的关系
STATIC struct mqpersonal *DoMqueueOpen(struct mqarray *mqueueCB, INT32 openFlag) STATIC struct mqpersonal *DoMqueueOpen(struct mqarray *mqueueCB, INT32 openFlag)
{ {
struct mqpersonal *privateMqPersonal = NULL; struct mqpersonal *privateMqPersonal = NULL;
/* already have the same name of g_squeuetable */ /* already have the same name of g_squeuetable */
if (mqueueCB->unlinkflag == TRUE) {//已经捆绑过了 if (mqueueCB->unlinkflag == TRUE) {//已经执行过unlink了,所以不能被引用了.
errno = EINVAL; errno = EINVAL;//可以看出mq_unlink不要随意的使用,因为其本意是要删除真正的消息队列的,一旦执行就没有回头路. 只能重新创建一个队列来玩了.
goto ERROUT; goto ERROUT;
} }
/* alloc mqprivate and add to mqarray */ /* alloc mqprivate and add to mqarray */
privateMqPersonal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal)); privateMqPersonal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal));//分配一个引用
if (privateMqPersonal == NULL) { if (privateMqPersonal == NULL) {
errno = ENOSPC; errno = ENOSPC;
goto ERROUT; goto ERROUT;
} }
privateMqPersonal->mq_next = mqueueCB->mq_personal; privateMqPersonal->mq_next = mqueueCB->mq_personal;//插入引用链表
mqueueCB->mq_personal = privateMqPersonal; mqueueCB->mq_personal = privateMqPersonal;//消息队列的引用指向始终是指向最后一个打开消息队列的引用
privateMqPersonal->mq_posixdes = mqueueCB; privateMqPersonal->mq_posixdes = mqueueCB; //引用都是指向同一个消息队列
privateMqPersonal->mq_flags = openFlag; privateMqPersonal->mq_flags = openFlag; //打开的标签
privateMqPersonal->mq_status = MQ_USE_MAGIC; privateMqPersonal->mq_status = MQ_USE_MAGIC;//魔法数字
return privateMqPersonal; return privateMqPersonal;
...@@ -254,14 +254,15 @@ mqd_t mq_open(const char *mqName, int openFlag, ...) ...@@ -254,14 +254,15 @@ mqd_t mq_open(const char *mqName, int openFlag, ...)
(VOID)pthread_mutex_lock(&g_mqueueMutex); (VOID)pthread_mutex_lock(&g_mqueueMutex);
mqueueCB = GetMqueueCBByName(mqName);//通过名称获取队列控制块 mqueueCB = GetMqueueCBByName(mqName);//通过名称获取队列控制块
if ((UINT32)openFlag & (UINT32)O_CREAT) {//需要创建了队列的情况 if ((UINT32)openFlag & (UINT32)O_CREAT) {//参数指定需要创建了队列的情况
if (mqueueCB != NULL) {//已经有同名队列 if (mqueueCB != NULL) {//1.消息队列已经创建了
if (((UINT32)openFlag & (UINT32)O_EXCL)) {//已经在执行 if (((UINT32)openFlag & (UINT32)O_EXCL)) {//消息队列已经在被别的进程读/写,此时不能创建新的进程引用
errno = EEXIST; errno = EEXIST;
goto OUT; goto OUT;
} }
privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);//打开队列 privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);//新增消息队列的引用
} else {//可变参数的实现 函数参数是以数据结构:栈的形式存取,从右至左入栈。 } else {//消息队列还没有创建,就需要create
//可变参数的实现 函数参数是以数据结构:栈的形式存取,从右至左入栈。
va_start(ap, openFlag);//对ap进行初始化,让它指向可变参数表里面的第一个参数,va_start第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“...”之前的那个参数 va_start(ap, openFlag);//对ap进行初始化,让它指向可变参数表里面的第一个参数,va_start第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“...”之前的那个参数
(VOID)va_arg(ap, int);//获取int参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置 (VOID)va_arg(ap, int);//获取int参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置
attr = va_arg(ap, struct mq_attr *);//获取mq_attr参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置 attr = va_arg(ap, struct mq_attr *);//获取mq_attr参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置
...@@ -279,22 +280,26 @@ mqd_t mq_open(const char *mqName, int openFlag, ...) ...@@ -279,22 +280,26 @@ mqd_t mq_open(const char *mqName, int openFlag, ...)
goto OUT; goto OUT;
} }
} }
privateMqPersonal = DoMqueueCreate(&defaultAttr, mqName, openFlag);//创建队列 privateMqPersonal = DoMqueueCreate(&defaultAttr, mqName, openFlag);//创建队列并新增消息队列的引用
} }
} else {//已经创建了队列 } else {//已经创建了队列
if (mqueueCB == NULL) {// if (mqueueCB == NULL) {//
errno = ENOENT; errno = ENOENT;
goto OUT; goto OUT;
} }
privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);//直接打开队列 privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);//新增消息队列的引用
} }
OUT: OUT:
(VOID)pthread_mutex_unlock(&g_mqueueMutex); (VOID)pthread_mutex_unlock(&g_mqueueMutex);
return (mqd_t)privateMqPersonal; return (mqd_t)privateMqPersonal;
} }
//关闭posix队列,用于关闭一个消息队列,和文件的close类型,关闭后,消息队列并不从系统中删除。 /**********************************************************
//一个进程结束,会自动调用关闭打开着的消息队列。 关闭posix队列,用于关闭一个消息队列,和文件的close类型,关闭后,消息队列并不从系统中删除。
一个进程结束,会自动调用关闭打开着的消息队列。
mq_close的含义是关闭一个进程的引用操作,也就是 mqueueCB->mq_personal = privateMqPersonal->mq_next;
mq_close 和 mq_open 成对出现
**********************************************************/
int mq_close(mqd_t personal) int mq_close(mqd_t personal)
{ {
INT32 ret = 0; INT32 ret = 0;
...@@ -308,24 +313,24 @@ int mq_close(mqd_t personal) ...@@ -308,24 +313,24 @@ int mq_close(mqd_t personal)
} }
(VOID)pthread_mutex_lock(&g_mqueueMutex); (VOID)pthread_mutex_lock(&g_mqueueMutex);
privateMqPersonal = (struct mqpersonal *)personal; privateMqPersonal = (struct mqpersonal *)personal;//这种用法,mq_id必须要放在结构体第一位
if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {//魔法数字是否一致 if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {//魔法数字可以判断队列是否溢出过,必须放在结构体最后一位
errno = EBADF; errno = EBADF;
goto OUT_UNLOCK; goto OUT_UNLOCK;
} }
mqueueCB = privateMqPersonal->mq_posixdes; mqueueCB = privateMqPersonal->mq_posixdes;//拿出消息队列
if (mqueueCB->mq_personal == NULL) {//posix队列控制块是否存在 if (mqueueCB->mq_personal == NULL) {//队列是否被进程打开过,一个从未被打开过的消息队列何谈关闭.
errno = EBADF; errno = EBADF;
goto OUT_UNLOCK; goto OUT_UNLOCK;
} }
/* find the personal and remove */ /* find the personal and remove */
if (mqueueCB->mq_personal == privateMqPersonal) { if (mqueueCB->mq_personal == privateMqPersonal) {//如果第一个就找到了
mqueueCB->mq_personal = privateMqPersonal->mq_next; mqueueCB->mq_personal = privateMqPersonal->mq_next;//这步操作相当于删除了privateMqPersonal
} else { } else {//如果第一个不是,说明可能在接下来的next中能遇到 ==
for (tmp = mqueueCB->mq_personal; tmp->mq_next != NULL; tmp = tmp->mq_next) { for (tmp = mqueueCB->mq_personal; tmp->mq_next != NULL; tmp = tmp->mq_next) {//一直遍历 next
if (tmp->mq_next == privateMqPersonal) { if (tmp->mq_next == privateMqPersonal) {//找到了当初的 mq_open 的那个消息队列
break; break;
} }
} }
...@@ -333,7 +338,7 @@ int mq_close(mqd_t personal) ...@@ -333,7 +338,7 @@ int mq_close(mqd_t personal)
errno = EBADF; errno = EBADF;
goto OUT_UNLOCK; goto OUT_UNLOCK;
} }
tmp->mq_next = privateMqPersonal->mq_next; tmp->mq_next = privateMqPersonal->mq_next;//这步操作相当于删除了privateMqPersonal
} }
/* flag no use */ /* flag no use */
privateMqPersonal->mq_status = 0;//未被使用 privateMqPersonal->mq_status = 0;//未被使用
...@@ -346,9 +351,9 @@ int mq_close(mqd_t personal) ...@@ -346,9 +351,9 @@ int mq_close(mqd_t personal)
goto OUT_UNLOCK; goto OUT_UNLOCK;
} }
if ((mqueueCB->unlinkflag == TRUE) && (mqueueCB->mq_personal == NULL)) {//没有引用,且没有链接时可以删除队列 if ((mqueueCB->unlinkflag == TRUE) && (mqueueCB->mq_personal == NULL)) {//执行过unlink且没有进程在使用队列了
ret = DoMqueueDelete(mqueueCB);// ret = DoMqueueDelete(mqueueCB);//删除消息队列,注意:mq_close的主要任务并不是想做这步操作的,mq_unlink才是真正想做这步操作
} }//一定要明白 mq_close 和 mq_unlink 的区别
OUT_UNLOCK: OUT_UNLOCK:
(VOID)pthread_mutex_unlock(&g_mqueueMutex); (VOID)pthread_mutex_unlock(&g_mqueueMutex);
return ret; return ret;
...@@ -449,9 +454,9 @@ int mq_unlink(const char *mqName) ...@@ -449,9 +454,9 @@ int mq_unlink(const char *mqName)
} }
if (mqueueCB->mq_personal != NULL) {//引用计数不为0,不删除. if (mqueueCB->mq_personal != NULL) {//引用计数不为0,不删除.
mqueueCB->unlinkflag = TRUE;//执行了 mqueueCB->unlinkflag = TRUE;//标记执行过unlink了,后面再打开这个消息队列就会失败
} else { } else {
ret = DoMqueueDelete(mqueueCB);//只有当引用计数为0时,才删除该消息队列 ret = DoMqueueDelete(mqueueCB);//只有当引用计数为0时,即所有打开的进程都执行了mq_close操作,才删除该消息队列
} }
(VOID)pthread_mutex_unlock(&g_mqueueMutex); (VOID)pthread_mutex_unlock(&g_mqueueMutex);
...@@ -545,7 +550,7 @@ ERROUT_UNLOCK: ...@@ -545,7 +550,7 @@ ERROUT_UNLOCK:
ERROUT: ERROUT:
return -1; return -1;
} }
//定时接收消息 //posix ipc 标准接口之定时接收消息
ssize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio, ssize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio,
const struct timespec *absTimeout) const struct timespec *absTimeout)
{ {
...@@ -589,7 +594,7 @@ ssize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int * ...@@ -589,7 +594,7 @@ ssize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *
mqueueID = mqueueCB->mq_id; mqueueID = mqueueCB->mq_id;
(VOID)pthread_mutex_unlock(&g_mqueueMutex); (VOID)pthread_mutex_unlock(&g_mqueueMutex);
err = LOS_QueueReadCopy(mqueueID, (VOID *)msg, &receiveLen, (UINT32)absTicks); err = LOS_QueueReadCopy(mqueueID, (VOID *)msg, &receiveLen, (UINT32)absTicks);//读消息队列
if (map_errno(err) == ENOERR) { if (map_errno(err) == ENOERR) {
return (ssize_t)receiveLen; return (ssize_t)receiveLen;
} else { } else {
......
...@@ -185,7 +185,7 @@ STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned lo ...@@ -185,7 +185,7 @@ STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned lo
{ {
UINT32 regionFlags = 0; UINT32 regionFlags = 0;
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER; //必须得是可用区先 regionFlags |= VM_MAP_REGION_FLAG_PERM_USER; //必须是可用区
regionFlags |= (prot & PROT_READ) ? VM_MAP_REGION_FLAG_PERM_READ : 0; //映射区可被读 regionFlags |= (prot & PROT_READ) ? VM_MAP_REGION_FLAG_PERM_READ : 0; //映射区可被读
regionFlags |= (prot & PROT_WRITE) ? VM_MAP_REGION_FLAG_PERM_WRITE : 0; //映射区可被写 regionFlags |= (prot & PROT_WRITE) ? VM_MAP_REGION_FLAG_PERM_WRITE : 0; //映射区可被写
regionFlags |= (prot & PROT_EXEC) ? VM_MAP_REGION_FLAG_PERM_EXECUTE : 0; //映射区可被执行 regionFlags |= (prot & PROT_EXEC) ? VM_MAP_REGION_FLAG_PERM_EXECUTE : 0; //映射区可被执行
...@@ -262,13 +262,13 @@ STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr) ...@@ -262,13 +262,13 @@ STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr)
return ((vaddr >= USER_ASPACE_BASE) && return ((vaddr >= USER_ASPACE_BASE) &&
(vaddr <= (USER_ASPACE_BASE + (USER_ASPACE_SIZE - 1)))); (vaddr <= (USER_ASPACE_BASE + (USER_ASPACE_SIZE - 1))));
} }
//从vaddr 到 vaddr + len 这段虚拟地址是否在用户空间 //虚拟地址[vaddr,vaddr + len]是否在用户空间
STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len) STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len)
{ {
return (vaddr + len > vaddr) && LOS_IsUserAddress(vaddr) && (LOS_IsUserAddress(vaddr + len - 1)); return (vaddr + len > vaddr) && LOS_IsUserAddress(vaddr) && (LOS_IsUserAddress(vaddr + len - 1));
} }
//是否是一个动态分配地址 //是否是一个动态分配地址
STATIC INLINE BOOL LOS_IsVmallocAddress(VADDR_T vaddr) STATIC INLINE BOOL LOS_IsVmallocAddress(VADDR_T vaddr)
{ {
return ((vaddr >= VMALLOC_START) && return ((vaddr >= VMALLOC_START) &&
......
...@@ -333,7 +333,7 @@ QUEUE_END: ...@@ -333,7 +333,7 @@ QUEUE_END:
SCHEDULER_UNLOCK(intSave); SCHEDULER_UNLOCK(intSave);
return ret; return ret;
} }
//接口函数 鸿蒙 LOS_ 开头的都是可供外面调用的接口函数 //接口函数定时读取消息队列
LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID, LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID,
VOID *bufferAddr, VOID *bufferAddr,
UINT32 *bufferSize, UINT32 *bufferSize,
...@@ -347,10 +347,10 @@ LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID, ...@@ -347,10 +347,10 @@ LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID,
return ret; return ret;
} }
operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);//意思是从头开始读 operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);//从头开始读
return OsQueueOperate(queueID, operateType, bufferAddr, bufferSize, timeout);//执行读操作 return OsQueueOperate(queueID, operateType, bufferAddr, bufferSize, timeout);//定时执行读操作
} }
//接口函数 从队列头开始写 //接口函数从队列头开始写
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHeadCopy(UINT32 queueID, LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHeadCopy(UINT32 queueID,
VOID *bufferAddr, VOID *bufferAddr,
UINT32 bufferSize, UINT32 bufferSize,
......
/* /*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved. * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met: * are permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* 3. Neither the name of the copyright holder nor the names of its contributors may be used * 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written * to endorse or promote products derived from this software without specific prior written
* permission. * permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef HM_LITEIPC_H #ifndef HM_LITEIPC_H
#define HM_LITEIPC_H #define HM_LITEIPC_H
#include "sys/ioctl.h" #include "sys/ioctl.h"
#include "los_config.h" #include "los_config.h"
#include "los_task_pri.h" #include "los_task_pri.h"
#include "los_typedef.h" #include "los_typedef.h"
#include "los_vm_map.h" #include "los_vm_map.h"
#ifdef __cplusplus #ifdef __cplusplus
#if __cplusplus #if __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* __cplusplus */ #endif /* __cplusplus */
#define LITEIPC_DRIVER "/dev/lite_ipc" #define LITEIPC_DRIVER "/dev/lite_ipc"
#define DRIVER_MODE 0666 #define DRIVER_MODE 0666
#define MAX_SERVICE_NUM LOSCFG_BASE_CORE_TSK_LIMIT #define MAX_SERVICE_NUM LOSCFG_BASE_CORE_TSK_LIMIT
#define USE_TIMESTAMP YES #define USE_TIMESTAMP YES
typedef enum { typedef enum {
HANDLE_NOT_USED, HANDLE_NOT_USED,
HANDLE_REGISTING, HANDLE_REGISTING,
HANDLE_REGISTED HANDLE_REGISTED
} HandleStatus; } HandleStatus;
typedef struct { typedef struct {//句柄信息
HandleStatus status; HandleStatus status; //状态
UINT32 taskID; UINT32 taskID; //任务ID,以任务当句柄
UINTPTR maxMsgSize; UINTPTR maxMsgSize;//最大消息大小
} HandleInfo; } HandleInfo;
typedef struct { typedef struct {
VOID *uvaddr; VOID *uvaddr;
VOID *kvaddr; VOID *kvaddr;
UINT32 poolSize; UINT32 poolSize;
} IpcPool; } IpcPool;
typedef struct { typedef struct {
IpcPool pool; IpcPool pool;
UINT32 ipcTaskID; UINT32 ipcTaskID;
UINT32 access[LOSCFG_BASE_CORE_TSK_LIMIT]; UINT32 access[LOSCFG_BASE_CORE_TSK_LIMIT];
} ProcIpcInfo; } ProcIpcInfo;
typedef enum { typedef enum {
OBJ_FD, OBJ_FD,
OBJ_PTR, OBJ_PTR,
OBJ_SVC OBJ_SVC
} ObjType; } ObjType;
typedef struct { typedef struct {
UINT32 buffSz; UINT32 buffSz;
VOID *buff; VOID *buff;
} BuffPtr; } BuffPtr;
typedef struct { typedef struct {
UINT32 handle; UINT32 handle;
UINT32 token; UINT32 token;
UINT32 cookie; UINT32 cookie;
} SvcIdentity; } SvcIdentity;
typedef union { typedef union {
UINT32 fd; UINT32 fd;
BuffPtr ptr; BuffPtr ptr;
SvcIdentity svc; SvcIdentity svc;
} ObjContent; } ObjContent;
typedef struct { typedef struct {
ObjType type; ObjType type;
ObjContent content; ObjContent content;
} SpecialObj; } SpecialObj;
typedef enum { typedef enum {
MT_REQUEST, MT_REQUEST,
MT_REPLY, MT_REPLY,
MT_FAILED_REPLY, MT_FAILED_REPLY,
MT_DEATH_NOTIFY, MT_DEATH_NOTIFY,
MT_NUM MT_NUM
} MsgType; } MsgType;
/* lite ipc ioctl */ /* lite ipc ioctl */
#define IPC_IOC_MAGIC 'i' #define IPC_IOC_MAGIC 'i'
#define IPC_SET_CMS _IO(IPC_IOC_MAGIC, 1) #define IPC_SET_CMS _IO(IPC_IOC_MAGIC, 1)
#define IPC_CMS_CMD _IOWR(IPC_IOC_MAGIC, 2, CmsCmdContent) #define IPC_CMS_CMD _IOWR(IPC_IOC_MAGIC, 2, CmsCmdContent)
#define IPC_SET_IPC_THREAD _IO(IPC_IOC_MAGIC, 3) #define IPC_SET_IPC_THREAD _IO(IPC_IOC_MAGIC, 3)
#define IPC_SEND_RECV_MSG _IOWR(IPC_IOC_MAGIC, 4, IpcContent) #define IPC_SEND_RECV_MSG _IOWR(IPC_IOC_MAGIC, 4, IpcContent)
typedef enum { typedef enum {
CMS_GEN_HANDLE, CMS_GEN_HANDLE,
CMS_REMOVE_HANDLE, CMS_REMOVE_HANDLE,
CMS_ADD_ACCESS CMS_ADD_ACCESS
} CmsCmd; } CmsCmd;
typedef struct { typedef struct {
CmsCmd cmd; CmsCmd cmd;
UINT32 taskID; UINT32 taskID;
UINT32 serviceHandle; UINT32 serviceHandle;
} CmsCmdContent; } CmsCmdContent;
typedef enum { typedef enum {
LITEIPC_FLAG_DEFAULT = 0, // send and reply LITEIPC_FLAG_DEFAULT = 0, // send and reply
LITEIPC_FLAG_ONEWAY, // send message only LITEIPC_FLAG_ONEWAY, // send message only
} IpcFlag; } IpcFlag;
typedef struct { typedef struct {
MsgType type; /**< cmd type, decide the data structure below*/ MsgType type; /**< cmd type, decide the data structure below*/
SvcIdentity target; /**< serviceHandle or targetTaskId, depending on type */ SvcIdentity target; /**< serviceHandle or targetTaskId, depending on type */
UINT32 code; /**< service function code */ UINT32 code; /**< service function code */
UINT32 flag; UINT32 flag;
#if (USE_TIMESTAMP == YES) #if (USE_TIMESTAMP == YES)
UINT64 timestamp; UINT64 timestamp;
#endif #endif
UINT32 dataSz; /**< size of data */ UINT32 dataSz; /**< size of data */
VOID *data; VOID *data;
UINT32 spObjNum; UINT32 spObjNum;
VOID *offsets; VOID *offsets;
UINT32 processID; /**< filled by kernel, processId of sender/reciever */ UINT32 processID; /**< filled by kernel, processId of sender/reciever */
UINT32 taskID; /**< filled by kernel, taskId of sender/reciever */ UINT32 taskID; /**< filled by kernel, taskId of sender/reciever */
#ifdef LOSCFG_SECURITY_CAPABILITY #ifdef LOSCFG_SECURITY_CAPABILITY
UINT32 userID; UINT32 userID;
UINT32 gid; UINT32 gid;
#endif #endif
} IpcMsg; } IpcMsg;
typedef struct { typedef struct {
IpcMsg msg; IpcMsg msg;
LOS_DL_LIST listNode; LOS_DL_LIST listNode;
} IpcListNode; } IpcListNode;
#define SEND (1 << 0) #define SEND (1 << 0)
#define RECV (1 << 1) #define RECV (1 << 1)
#define BUFF_FREE (1 << 2) #define BUFF_FREE (1 << 2)
typedef struct { typedef struct {
UINT32 flag; /**< size of writeData */ UINT32 flag; /**< size of writeData */
IpcMsg *outMsg; /**< data to send to target */ IpcMsg *outMsg; /**< data to send to target */
IpcMsg *inMsg; /**< data reply by target */ IpcMsg *inMsg; /**< data reply by target */
VOID *buffToFree; VOID *buffToFree;
} IpcContent; } IpcContent;
#define IPC_THREAD_STATUS_INVAL 0x0001U #define IPC_THREAD_STATUS_INVAL 0x0001U
#define IPC_THREAD_STATUS_START 0x0002U #define IPC_THREAD_STATUS_START 0x0002U
#define IPC_THREAD_STATUS_PEND 0x0004U #define IPC_THREAD_STATUS_PEND 0x0004U
#define IPC_THREAD_STATUS_STOP 0x0008U #define IPC_THREAD_STATUS_STOP 0x0008U
#if (LOSCFG_KERNEL_TRACE == YES) #if (LOSCFG_KERNEL_TRACE == YES)
#define LOS_TRACE_IPC 3 //IPC 对应..\kernel\include\los_trace.h TraceType 理解 #define LOS_TRACE_IPC 3 //IPC 对应..\kernel\include\los_trace.h TraceType 理解
typedef enum { typedef enum {
WRITE, WRITE,
WRITE_DROP, WRITE_DROP,
TRY_READ, TRY_READ,
READ, READ,
READ_DROP, READ_DROP,
READ_TIMEOUT, READ_TIMEOUT,
OPERATION_NUM OPERATION_NUM
} IpcOpertion; } IpcOpertion;
typedef struct { typedef struct {
UINT32 srcTid : 8; UINT32 srcTid : 8;
UINT32 srcPid : 8; UINT32 srcPid : 8;
UINT32 dstTid : 8; UINT32 dstTid : 8;
UINT32 dstPid : 8; UINT32 dstPid : 8;
} IdArg; } IdArg;
typedef struct { typedef struct {
UINT32 msgType : 8; UINT32 msgType : 8;
UINT32 code : 8; UINT32 code : 8;
UINT32 operation : 8; UINT32 operation : 8;
UINT32 ipcStatus : 8; UINT32 ipcStatus : 8;
} MsgArg; } MsgArg;
typedef struct { typedef struct {
UINT32 idInfo; UINT32 idInfo;
UINT32 msgInfo; UINT32 msgInfo;
UINT64 timestamp; UINT64 timestamp;
} IpcTraceFrame; } IpcTraceFrame;
#endif #endif
/* init liteipc driver */ /* init liteipc driver */
extern UINT32 LiteIpcInit(VOID); extern UINT32 LiteIpcInit(VOID);
/* init process liteipc memory pool */ /* init process liteipc memory pool */
extern UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo); extern UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo);
/* reinit process liteipc memory pool, using in fork situation */ /* reinit process liteipc memory pool, using in fork situation */
extern UINT32 LiteIpcPoolReInit(ProcIpcInfo *childIpcInfo, const ProcIpcInfo *parentIpcInfo); extern UINT32 LiteIpcPoolReInit(ProcIpcInfo *childIpcInfo, const ProcIpcInfo *parentIpcInfo);
/* delete process liteipc memory pool */ /* delete process liteipc memory pool */
extern VOID LiteIpcPoolDelete(ProcIpcInfo *ipcInfo); extern VOID LiteIpcPoolDelete(ProcIpcInfo *ipcInfo);
/* remove service handle and send death notify */ /* remove service handle and send death notify */
extern VOID LiteIpcRemoveServiceHandle(LosTaskCB *taskCB); extern VOID LiteIpcRemoveServiceHandle(LosTaskCB *taskCB);
#ifdef __cplusplus #ifdef __cplusplus
#if __cplusplus #if __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
...@@ -176,7 +176,7 @@ static int UserPoll(struct pollfd *fds, nfds_t nfds, int timeout) ...@@ -176,7 +176,7 @@ static int UserPoll(struct pollfd *fds, nfds_t nfds, int timeout)
free(pollFds); free(pollFds);
return ret; return ret;
} }
//复杂一个文件描述符
static int FcntlDupFd(int fd, void *arg, int (*fcntl)(int, int, ...)) static int FcntlDupFd(int fd, void *arg, int (*fcntl)(int, int, ...))
{ {
int ret; int ret;
...@@ -776,7 +776,25 @@ int SysIoctl(int fd, int req, void *arg) ...@@ -776,7 +776,25 @@ int SysIoctl(int fd, int req, void *arg)
} }
return ret; return ret;
} }
//文件控制 /********************************************************
用来修改已经打开文件的属性的函数包含5个功能:
1.复制一个已有文件描述符,功能和dup和dup2相同,对应的cmd:F_DUPFD、F_DUPFD_CLOEXEC。
当使用这两个cmd时,需要传入第三个参数,fcntl返回复制后的文件描述符,此返回值是之前未被占用的描述符,
并且必须一个大于等于第三个参数值。
F_DUPFD命令要求返回的文件描述符会清除对应的FD_CLOEXEC
F_DUPFD_CLOEXEC要求设置新描述符的FD_CLOEXEC标志。
2.获取、设置文件描述符标志,对应的cmd:F_GETFD、F_SETFD。
用于设置FD_CLOEXEC标志,此标志的含义是:当进程执行exec系统调用后此文件描述符会被自动关闭。
3.获取、设置文件访问状态标志,对应的cmd:F_GETFL、F_SETFL。
获取当前打开文件的访问标志,设置对应的访问标志,一般常用来设置做非阻塞读写操作。
4.获取、设置记录锁功能,对应的cmd:F_GETLK、F_SETLK、F_SETLKW。
5.获取、设置异步I/O所有权,对应的cmd:F_GETOWN、F_SETOWN。
获取和设置用来接收SIGIO/SIGURG信号的进程id或者进程组id。返回对应的进程id或者进程组id取负值。
********************************************************/
int SysFcntl(int fd, int cmd, void *arg) int SysFcntl(int fd, int cmd, void *arg)
{ {
/* Process fd convert to system global fd */ /* Process fd convert to system global fd */
...@@ -791,23 +809,38 @@ int SysFcntl(int fd, int cmd, void *arg) ...@@ -791,23 +809,38 @@ int SysFcntl(int fd, int cmd, void *arg)
} }
return ret; return ret;
} }
//创建管道 /********************************************************
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。
调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
① 数据自己读不能自己写。
② 数据一旦被读走,便不在管道中存在,不可反复读取。
③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
④ 只能在有公共祖先的进程间使用管道。
常见的通信方式有,单工通信、半双工通信、全双工通信。
********************************************************/
int SysPipe(int pipefd[2]) /* 2 : pipe fds for read and write */ int SysPipe(int pipefd[2]) /* 2 : pipe fds for read and write */
{ {
int ret; int ret;
int pipeFdIntr[2] = {0}; /* 2 : pipe fds for read and write */ int pipeFdIntr[2] = {0}; /* 2 : pipe fds for read and write */
int procFd0 = AllocProcessFd(); int procFd0 = AllocProcessFd();//读端管道,像 stdin对应标准输入
if (procFd0 < 0) { if (procFd0 < 0) {
return -EMFILE; return -EMFILE;
} }
int procFd1 = AllocProcessFd(); int procFd1 = AllocProcessFd();//写端管道,像 stdout对应标准输出
if (procFd1 < 0) { if (procFd1 < 0) {
FreeProcessFd(procFd0); FreeProcessFd(procFd0);
return -EMFILE; return -EMFILE;
} }
ret = pipe(pipeFdIntr); ret = pipe(pipeFdIntr);//创建管道
if (ret < 0) { if (ret < 0) {
FreeProcessFd(procFd0); FreeProcessFd(procFd0);
FreeProcessFd(procFd1); FreeProcessFd(procFd1);
...@@ -816,13 +849,13 @@ int SysPipe(int pipefd[2]) /* 2 : pipe fds for read and write */ ...@@ -816,13 +849,13 @@ int SysPipe(int pipefd[2]) /* 2 : pipe fds for read and write */
int sysPipeFd0 = pipeFdIntr[0]; int sysPipeFd0 = pipeFdIntr[0];
int sysPipeFd1 = pipeFdIntr[1]; int sysPipeFd1 = pipeFdIntr[1];
AssociateSystemFd(procFd0, sysPipeFd0); AssociateSystemFd(procFd0, sysPipeFd0);//进程FD和系统FD绑定
AssociateSystemFd(procFd1, sysPipeFd1); AssociateSystemFd(procFd1, sysPipeFd1);
pipeFdIntr[0] = procFd0; pipeFdIntr[0] = procFd0;
pipeFdIntr[1] = procFd1; pipeFdIntr[1] = procFd1;
ret = LOS_ArchCopyToUser(pipefd, pipeFdIntr, sizeof(pipeFdIntr)); ret = LOS_ArchCopyToUser(pipefd, pipeFdIntr, sizeof(pipeFdIntr));//参数都走两个进程FD
if (ret != 0) { if (ret != 0) {
FreeProcessFd(procFd0); FreeProcessFd(procFd0);
FreeProcessFd(procFd1); FreeProcessFd(procFd1);
...@@ -832,15 +865,17 @@ int SysPipe(int pipefd[2]) /* 2 : pipe fds for read and write */ ...@@ -832,15 +865,17 @@ int SysPipe(int pipefd[2]) /* 2 : pipe fds for read and write */
} }
return ret; return ret;
} }
//按指定条件复制文件描述字 /********************************************************
/复制文件描述符
********************************************************/
int SysDup2(int fd1, int fd2) int SysDup2(int fd1, int fd2)
{ {
int ret; int ret;
int sysfd1 = GetAssociatedSystemFd(fd1); int sysfd1 = GetAssociatedSystemFd(fd1);
int sysfd2 = GetAssociatedSystemFd(fd2); int sysfd2 = GetAssociatedSystemFd(fd2);
//检查参数是否有效,注意:socket fd不支持dup2
/* Check if the param is valid, note that: socket fd is not support dup2 */ /* Check if the param is valid, note that: socket fd is not support dup2 */
if ((sysfd1 < 0) || (sysfd1 >= CONFIG_NFILE_DESCRIPTORS) || (CheckProcessFd(fd2) != OK)) { if ((sysfd1 < 0) || (sysfd1 >= CONFIG_NFILE_DESCRIPTORS) || (CheckProcessFd(fd2) != OK)) {//socket的fd必大于CONFIG_NFILE_DESCRIPTORS
return -EBADF; return -EBADF;
} }
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include "los_signal.h" #include "los_signal.h"
#include "los_strncpy_from_user.h" #include "los_strncpy_from_user.h"
/******************************************************** /********************************************************
本文说明:系统调用|IPC 本文说明:包含消息队列和信号两部分内容,是实现IPC的其中两种方式
IPC(Inter-Process Communication,进程间通信) IPC(Inter-Process Communication,进程间通信)
每个进程各自有不同的用户地址空间,进程之间地址保护,相互隔离,任何一个进程的信息在另一个进程中都看不到, 每个进程各自有不同的用户地址空间,进程之间地址保护,相互隔离,任何一个进程的信息在另一个进程中都看不到,
所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区, 所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,
...@@ -84,7 +84,12 @@ int SysMqClose(mqd_t personal) ...@@ -84,7 +84,12 @@ int SysMqClose(mqd_t personal)
} }
return ret; return ret;
} }
/******************************************************
封装posix的标准接口,获取和设置消息队列的属性
new:来判断是否是获取还是设置功能
new==null 获取
否则为设置
******************************************************/
int SysMqGetSetAttr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old) int SysMqGetSetAttr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)
{ {
int ret; int ret;
...@@ -108,7 +113,14 @@ int SysMqGetSetAttr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old) ...@@ -108,7 +113,14 @@ int SysMqGetSetAttr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)
} }
return ret; return ret;
} }
/******************************************************
从内核中删除名为mqName的消息队列
如果该函数被调用了,但是仍然有进程已经打开了这个消息队列,那么这个消息队列
的销毁会被推迟到所有的引用都被关闭时执行.并且函数 mq_unlink() 不需要阻塞
到所有的引用都被关闭为止,它会立即返回.函数 mq_unlink()调用成功后, 如果在
随后调用 mq_open() 时重用这个消息队列名字,效果就像这个名字的消息队列不存在,
如果没有设置O_CREAT标志,函数mq_open() 会返回失败,否则会创建一个新的消息队列.
******************************************************/
int SysMqUnlink(const char *mqName) int SysMqUnlink(const char *mqName)
{ {
int ret; int ret;
...@@ -126,7 +138,9 @@ int SysMqUnlink(const char *mqName) ...@@ -126,7 +138,9 @@ int SysMqUnlink(const char *mqName)
} }
return ret; return ret;
} }
/******************************************************
定时时间发送消息,任务将被阻塞,等待被唤醒写入消息
******************************************************/
int SysMqTimedSend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio, int SysMqTimedSend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio,
const struct timespec *absTimeout) const struct timespec *absTimeout)
{ {
...@@ -152,14 +166,16 @@ int SysMqTimedSend(mqd_t personal, const char *msg, size_t msgLen, unsigned int ...@@ -152,14 +166,16 @@ int SysMqTimedSend(mqd_t personal, const char *msg, size_t msgLen, unsigned int
free(msgIntr); free(msgIntr);
return -EFAULT; return -EFAULT;
} }
ret = mq_timedsend(personal, msgIntr, msgLen, msgPrio, absTimeout ? &timeout : NULL); ret = mq_timedsend(personal, msgIntr, msgLen, msgPrio, absTimeout ? &timeout : NULL);//posix 接口的实现
free(msgIntr); free(msgIntr);
if (ret < 0) { if (ret < 0) {
return -get_errno(); return -get_errno();
} }
return ret; return ret;
} }
/******************************************************
定时接收消息,任务将被阻塞,等待被唤醒读取
******************************************************/
ssize_t SysMqTimedReceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio, ssize_t SysMqTimedReceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio,
const struct timespec *absTimeout) const struct timespec *absTimeout)
{ {
...@@ -181,7 +197,7 @@ ssize_t SysMqTimedReceive(mqd_t personal, char *msg, size_t msgLen, unsigned int ...@@ -181,7 +197,7 @@ ssize_t SysMqTimedReceive(mqd_t personal, char *msg, size_t msgLen, unsigned int
if (msgIntr == NULL) { if (msgIntr == NULL) {
return -ENOMEM; return -ENOMEM;
} }
receiveLen = mq_timedreceive(personal, msgIntr, msgLen, &kMsgPrio, absTimeout ? &timeout : NULL); receiveLen = mq_timedreceive(personal, msgIntr, msgLen, &kMsgPrio, absTimeout ? &timeout : NULL);//posix 接口的实现
if (receiveLen < 0) { if (receiveLen < 0) {
free(msgIntr); free(msgIntr);
return -get_errno(); return -get_errno();
......
git add -A git add -A
git commit -m '完善虚拟内存模块注解 git commit -m '字符图说明posix消息队列内在运行逻辑
搜索 @note_pic 可以查看全部字符图 搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善 搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方 搜索 @note_thinking 是注者的思考和吐槽的地方
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册