[ English | 简体中文 ]

消息队列 API

openvela 提供符合 POSIX 标准的消息队列接口,用于任务间的异步消息传递。消息队列支持优先级排序,高优先级消息优先被接收。

头文件:#include <mqueue.h>

openvela 实现说明

  • 中断中发送mq_send() 可在中断上下文中调用,但行为不同:不检查队列大小,使用预分配消息(数量由 PREALLOC_MQ_IRQ_MSGS 配置)
  • 通知行为差异mq_notify() 即使有任务在等待接收消息,仍会发送通知信号,与 POSIX 规范不完全一致
  • 超时时间mq_timedsend()mq_timedreceive() 使用基于 Epoch 的绝对时间

队列管理

mq_open

mqd_t mq_open(const char *mqName, int oflags, ...);

在调用任务和消息队列之间建立连接。成功调用后,返回的消息队列描述符可用于后续操作,直到调用 mq_close()

参数

  • mqName 消息队列的名称。
  • oflags 打开标志位,可以是以下的任意组合:
    • O_RDONLY 只读。
    • O_WRONLY 只写。
    • O_RDWR 读写。
    • O_CREAT 如果消息队列不存在则创建。
    • O_EXCLO_CREAT 配合,如果队列已存在则失败。
    • O_NONBLOCK 非阻塞模式。
  • ... 可选参数,当使用 O_CREAT 时需要提供:
    • modemode_t)文件权限位。当前实现中未使用,但 POSIX 要求提供。
    • attrstruct mq_attr *)队列属性。如果为 NULL 则使用默认值。mq_maxmsg 设置最大消息数,mq_msgsize 设置最大消息大小。

返回值

成功时返回消息队列描述符(mqd_t),失败时返回 -1(ERROR)并设置 errno

  • ENOENT 未设置 O_CREAT 且指定的队列不存在。
  • EEXIST 同时设置了 O_CREATO_EXCL,但队列已存在。
  • EINVAL 参数无效(如 mqNameNULL)。
  • ENOMEM 内存不足,无法创建队列。
  • ENFILE 系统消息队列数量已达上限。

POSIX 兼容性:兼容 POSIX 同名接口。

mq_close

int mq_close(mqd_t mqdes);

关闭消息队列描述符,释放系统分配给该任务的资源。如果任务在该队列上注册了通知请求,通知会被取消。

参数

  • mqdes 消息队列描述符。

返回值

成功时返回 0,失败时返回 -1(ERROR)并设置 errno

  • EBADF mqdes 不是有效的消息队列描述符。

注意

  • mq_send()mq_receive() 阻塞时调用 mq_close() 的行为是未定义的。
  • 关闭后再次使用同一 mqdes 的行为是未定义的。

POSIX 兼容性:兼容 POSIX 同名接口。

int mq_unlink(const char *mqName);

删除指定名称的消息队列。如果有任务仍然打开了该队列,删除会推迟到所有描述符都关闭后执行。

参数

  • mqName 消息队列的名称。

返回值

成功时返回 0,失败时返回 -1(ERROR)并设置 errno

  • ENOENT 指定名称的队列不存在。
  • EINVAL mqNameNULL

POSIX 兼容性:兼容 POSIX 同名接口。

消息发送

mq_send

int mq_send(mqd_t mqdes, const void *msg, size_t msglen, int prio);

将消息发送到消息队列。消息按优先级排序,高优先级消息排在低优先级之前。prio 不能超过 MQ_PRIO_MAX

如果队列已满且未设置 O_NONBLOCK,调用阻塞直到有空间可用。如果设置了 O_NONBLOCK,立即返回错误。

参数

  • mqdes 消息队列描述符。
  • msg 要发送的消息。
  • msglen 消息的字节长度,不能超过 mq_msgsize
  • prio 消息优先级。

返回值

成功时返回 0,失败时返回 -1(ERROR)并设置 errno

  • EAGAIN 队列已满且设置了 O_NONBLOCK
  • EINVAL msgmqdesNULL,或 prio 无效。
  • EPERM 消息队列未以写模式打开。
  • EMSGSIZE msglen 超过队列的 mq_msgsize
  • EINTR 被信号中断。

注意

  • mq_send() 可在中断上下文中调用,但行为不同:不检查队列大小(总是发送),使用预分配消息(数量由 PREALLOC_MQ_IRQ_MSGS 配置),不分配新内存。

POSIX 兼容性:兼容 POSIX 同名接口。

mq_timedsend

int mq_timedsend(mqd_t mqdes, const void *msg, size_t msglen, int prio,
                 const struct timespec *abstime);

带超时的消息发送。行为与 mq_send() 相同,但在队列满时最多阻塞到 abstime 指定的绝对时间。

参数

  • mqdes 消息队列描述符。
  • msg 要发送的消息。
  • msglen 消息的字节长度。
  • prio 消息优先级。
  • abstime 绝对超时时间(基于 Epoch)。

返回值

成功时返回 0,失败时返回 -1(ERROR)并设置 errno

  • EAGAIN 队列已满且设置了 O_NONBLOCK
  • EINVAL msgmqdesNULL,或 prio 无效。
  • EPERM 消息队列未以写模式打开。
  • EMSGSIZE msglen 超过队列的 mq_msgsize
  • EINTR 被信号中断。
  • ETIMEDOUT 超时。

POSIX 兼容性:兼容 POSIX 同名接口。

消息接收

mq_receive

ssize_t mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio);

从消息队列接收优先级最高且最早的消息。msglen 不能小于队列的 mq_msgsize,否则返回错误。

如果队列为空且未设置 O_NONBLOCK,调用阻塞直到有消息可用。多个等待任务中,优先级最高且等待最久的任务优先接收。

参数

  • mqdes 消息队列描述符。
  • msg 接收消息的缓冲区。
  • msglen 缓冲区大小(字节)。
  • prio 如果非 NULL,存储接收到的消息的优先级。

返回值

成功时返回消息长度(字节),失败时返回 -1(ERROR)并设置 errno

  • EAGAIN 队列为空且设置了 O_NONBLOCK
  • EPERM 消息队列未以读模式打开。
  • EMSGSIZE msglen 小于队列的 mq_msgsize
  • EINTR 被信号中断。

POSIX 兼容性:兼容 POSIX 同名接口。

mq_timedreceive

ssize_t mq_timedreceive(mqd_t mqdes, char *msg, size_t msglen,
                        unsigned int *prio, const struct timespec *abstime);

带超时的消息接收。行为与 mq_receive() 相同,但在队列空时最多阻塞到 abstime 指定的绝对时间。

参数

  • mqdes 消息队列描述符。
  • msg 接收消息的缓冲区。
  • msglen 缓冲区大小(字节)。
  • prio 如果非 NULL,存储接收到的消息的优先级。
  • abstime 绝对超时时间(基于 Epoch)。

返回值

成功时返回消息长度(字节),失败时返回 -1(ERROR)并设置 errno

  • EAGAIN 队列为空且设置了 O_NONBLOCK
  • EPERM 消息队列未以读模式打开。
  • EMSGSIZE msglen 小于队列的 mq_msgsize
  • EINTR 被信号中断。
  • ETIMEDOUT 超时。

POSIX 兼容性:兼容 POSIX 同名接口。

队列属性

mq_setattr

int mq_setattr(mqd_t mqdes, const struct mq_attr *mqStat, struct mq_attr *oldMqStat);

设置消息队列属性。mq_flags 中只有 O_NONBLOCK 位可以被修改。

参数

  • mqdes 消息队列描述符。
  • mqStat 新属性。
  • oldMqStat 如果非 NULL,存储修改前的属性。

返回值

成功时返回 0,失败时返回 -1(ERROR)并设置 errno

  • EBADF mqdes 不是有效的描述符。
  • EINVAL mqStatNULL

POSIX 兼容性:兼容 POSIX 同名接口。

mq_getattr

int mq_getattr(mqd_t mqdes, struct mq_attr *mqStat);

获取消息队列的当前属性。

参数

  • mqdes 消息队列描述符。
  • mqStat 返回属性结构体:
    • mq_maxmsg 队列中的最大消息数。
    • mq_msgsize 最大消息大小(字节)。
    • mq_flags 消息队列标志。
    • mq_curmsgs 当前队列中的消息数。

返回值

成功时返回 0,失败时返回 -1(ERROR)并设置 errno

  • EBADF mqdes 不是有效的描述符。
  • EINVAL mqStatNULL

POSIX 兼容性:兼容 POSIX 同名接口。

通知

mq_notify

int mq_notify(mqd_t mqdes, const struct sigevent *notification);

注册或取消消息到达通知。当消息到达先前为空的队列时,向注册的任务发送信号通知。

如果 notificationNULL,取消当前注册。通知发送后注册自动取消,需要重新注册。

参数

  • mqdes 消息队列描述符。
  • notification 通知配置,包括:
    • sigev_notify 通知方式(应为 SIGEV_SIGNAL)。
    • sigev_signo 通知使用的信号编号。
    • sigev_value 随信号传递的值。

返回值

成功时返回 0,失败时返回 -1(ERROR)并设置 errno

  • EBADF mqdes 不是有效的描述符。
  • EBUSY 另一个任务已注册了该队列的通知。
  • EINVAL sigev_notify 不是有效值,或信号编号无效。
  • ENOMEM 内存不足。

注意

  • 与 POSIX 的行为差异:在 openvela 中,即使有任务正在 mq_receive() 上阻塞等待消息,通知信号仍会发送给注册的任务。POSIX 规范要求此时不发送通知(消息直接满足等待的 mq_receive())。

POSIX 兼容性:部分兼容 POSIX 同名接口(通知时机与 POSIX 规范有差异)。