306 lines
10 KiB
Markdown
306 lines
10 KiB
Markdown
\[ English | [简体中文](../../../zh-cn/api/kernel/msgqueue.md) \]
|
|
|
|
# Message Queue API
|
|
|
|
openvela provides POSIX-compliant message queue interfaces for asynchronous message passing between tasks. Message queues support priority ordering, where higher-priority messages are received first.
|
|
|
|
Header file: `#include <mqueue.h>`
|
|
|
|
## openvela Implementation Notes
|
|
|
|
- **Sending from interrupts**: `mq_send()` can be called from interrupt context, but behaves differently: it does not check queue size, uses pre-allocated messages (quantity configured by `PREALLOC_MQ_IRQ_MSGS`)
|
|
- **Notification behavior difference**: `mq_notify()` sends the notification signal even when a task is waiting to receive a message, which is not fully consistent with the POSIX specification
|
|
- **Timeout values**: `mq_timedsend()` and `mq_timedreceive()` use Epoch-based absolute time
|
|
|
|
## Queue Management
|
|
|
|
### mq_open
|
|
|
|
```c
|
|
mqd_t mq_open(const char *mqName, int oflags, ...);
|
|
```
|
|
|
|
Establishes a connection between the calling task and a message queue. After a successful call, the returned message queue descriptor can be used for subsequent operations until `mq_close()` is called.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqName` Name of the message queue.
|
|
- `oflags` Open flags, which can be any combination of:
|
|
- `O_RDONLY` Read-only.
|
|
- `O_WRONLY` Write-only.
|
|
- `O_RDWR` Read-write.
|
|
- `O_CREAT` Create the message queue if it does not exist.
|
|
- `O_EXCL` Used with `O_CREAT`, fails if the queue already exists.
|
|
- `O_NONBLOCK` Non-blocking mode.
|
|
- `...` Optional arguments required when `O_CREAT` is used:
|
|
- `mode` (`mode_t`) File permission bits. Not used in the current implementation, but required by POSIX.
|
|
- `attr` (`struct mq_attr *`) Queue attributes. If `NULL`, default values are used. `mq_maxmsg` sets the maximum number of messages, `mq_msgsize` sets the maximum message size.
|
|
|
|
**Returns**:
|
|
|
|
Returns a message queue descriptor (`mqd_t`) on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `ENOENT` `O_CREAT` was not set and the specified queue does not exist.
|
|
- `EEXIST` Both `O_CREAT` and `O_EXCL` were set, but the queue already exists.
|
|
- `EINVAL` Invalid argument (e.g., `mqName` is `NULL`).
|
|
- `ENOMEM` Insufficient memory to create the queue.
|
|
- `ENFILE` System message queue limit reached.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
### mq_close
|
|
|
|
```c
|
|
int mq_close(mqd_t mqdes);
|
|
```
|
|
|
|
Closes a message queue descriptor, releasing system resources allocated to the task. If the task has registered a notification request on this queue, the notification is cancelled.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
|
|
**Returns**:
|
|
|
|
Returns 0 on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EBADF` `mqdes` is not a valid message queue descriptor.
|
|
|
|
**Notes**:
|
|
|
|
- Calling `mq_close()` while `mq_send()` or `mq_receive()` is blocked is undefined behavior.
|
|
- Using the same `mqdes` after closing is undefined behavior.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
### mq_unlink
|
|
|
|
```c
|
|
int mq_unlink(const char *mqName);
|
|
```
|
|
|
|
Removes the named message queue. If any tasks still have the queue open, the removal is deferred until all descriptors are closed.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqName` Name of the message queue.
|
|
|
|
**Returns**:
|
|
|
|
Returns 0 on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `ENOENT` The specified queue does not exist.
|
|
- `EINVAL` `mqName` is `NULL`.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
## Sending Messages
|
|
|
|
### mq_send
|
|
|
|
```c
|
|
int mq_send(mqd_t mqdes, const void *msg, size_t msglen, int prio);
|
|
```
|
|
|
|
Sends a message to a message queue. Messages are ordered by priority, with higher-priority messages placed before lower-priority ones. `prio` must not exceed `MQ_PRIO_MAX`.
|
|
|
|
If the queue is full and `O_NONBLOCK` is not set, the call blocks until space becomes available. If `O_NONBLOCK` is set, it returns an error immediately.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
- `msg` Message to send.
|
|
- `msglen` Length of the message in bytes, must not exceed `mq_msgsize`.
|
|
- `prio` Message priority.
|
|
|
|
**Returns**:
|
|
|
|
Returns 0 on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EAGAIN` Queue is full and `O_NONBLOCK` is set.
|
|
- `EINVAL` `msg` or `mqdes` is `NULL`, or `prio` is invalid.
|
|
- `EPERM` Message queue was not opened for writing.
|
|
- `EMSGSIZE` `msglen` exceeds the queue's `mq_msgsize`.
|
|
- `EINTR` Interrupted by a signal.
|
|
|
|
**Notes**:
|
|
|
|
- `mq_send()` can be called from interrupt context, but behaves differently: it does not check queue size (always sends), uses pre-allocated messages (quantity configured by `PREALLOC_MQ_IRQ_MSGS`), and does not allocate new memory.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
### mq_timedsend
|
|
|
|
```c
|
|
int mq_timedsend(mqd_t mqdes, const void *msg, size_t msglen, int prio,
|
|
const struct timespec *abstime);
|
|
```
|
|
|
|
Sends a message with a timeout. Behaves the same as `mq_send()`, but when the queue is full, blocks at most until the absolute time specified by `abstime`.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
- `msg` Message to send.
|
|
- `msglen` Length of the message in bytes.
|
|
- `prio` Message priority.
|
|
- `abstime` Absolute timeout (Epoch-based).
|
|
|
|
**Returns**:
|
|
|
|
Returns 0 on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EAGAIN` Queue is full and `O_NONBLOCK` is set.
|
|
- `EINVAL` `msg` or `mqdes` is `NULL`, or `prio` is invalid.
|
|
- `EPERM` Message queue was not opened for writing.
|
|
- `EMSGSIZE` `msglen` exceeds the queue's `mq_msgsize`.
|
|
- `EINTR` Interrupted by a signal.
|
|
- `ETIMEDOUT` Timed out.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
## Receiving Messages
|
|
|
|
### mq_receive
|
|
|
|
```c
|
|
ssize_t mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio);
|
|
```
|
|
|
|
Receives the oldest message with the highest priority from the message queue. `msglen` must not be less than the queue's `mq_msgsize`, otherwise an error is returned.
|
|
|
|
If the queue is empty and `O_NONBLOCK` is not set, the call blocks until a message is available. Among multiple waiting tasks, the one with the highest priority and longest wait time receives first.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
- `msg` Buffer to receive the message.
|
|
- `msglen` Buffer size in bytes.
|
|
- `prio` If not `NULL`, stores the priority of the received message.
|
|
|
|
**Returns**:
|
|
|
|
Returns the message length in bytes on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EAGAIN` Queue is empty and `O_NONBLOCK` is set.
|
|
- `EPERM` Message queue was not opened for reading.
|
|
- `EMSGSIZE` `msglen` is less than the queue's `mq_msgsize`.
|
|
- `EINTR` Interrupted by a signal.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
### mq_timedreceive
|
|
|
|
```c
|
|
ssize_t mq_timedreceive(mqd_t mqdes, char *msg, size_t msglen,
|
|
unsigned int *prio, const struct timespec *abstime);
|
|
```
|
|
|
|
Receives a message with a timeout. Behaves the same as `mq_receive()`, but when the queue is empty, blocks at most until the absolute time specified by `abstime`.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
- `msg` Buffer to receive the message.
|
|
- `msglen` Buffer size in bytes.
|
|
- `prio` If not `NULL`, stores the priority of the received message.
|
|
- `abstime` Absolute timeout (Epoch-based).
|
|
|
|
**Returns**:
|
|
|
|
Returns the message length in bytes on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EAGAIN` Queue is empty and `O_NONBLOCK` is set.
|
|
- `EPERM` Message queue was not opened for reading.
|
|
- `EMSGSIZE` `msglen` is less than the queue's `mq_msgsize`.
|
|
- `EINTR` Interrupted by a signal.
|
|
- `ETIMEDOUT` Timed out.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
## Queue Attributes
|
|
|
|
### mq_setattr
|
|
|
|
```c
|
|
int mq_setattr(mqd_t mqdes, const struct mq_attr *mqStat, struct mq_attr *oldMqStat);
|
|
```
|
|
|
|
Sets message queue attributes. Only the `O_NONBLOCK` bit in `mq_flags` can be modified.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
- `mqStat` New attributes.
|
|
- `oldMqStat` If not `NULL`, stores the attributes before modification.
|
|
|
|
**Returns**:
|
|
|
|
Returns 0 on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EBADF` `mqdes` is not a valid descriptor.
|
|
- `EINVAL` `mqStat` is `NULL`.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
### mq_getattr
|
|
|
|
```c
|
|
int mq_getattr(mqd_t mqdes, struct mq_attr *mqStat);
|
|
```
|
|
|
|
Gets the current attributes of a message queue.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
- `mqStat` Returns the attribute structure:
|
|
- `mq_maxmsg` Maximum number of messages in the queue.
|
|
- `mq_msgsize` Maximum message size in bytes.
|
|
- `mq_flags` Message queue flags.
|
|
- `mq_curmsgs` Current number of messages in the queue.
|
|
|
|
**Returns**:
|
|
|
|
Returns 0 on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EBADF` `mqdes` is not a valid descriptor.
|
|
- `EINVAL` `mqStat` is `NULL`.
|
|
|
|
**POSIX Compatibility**: Compatible with the POSIX interface of the same name.
|
|
|
|
## Notification
|
|
|
|
### mq_notify
|
|
|
|
```c
|
|
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
|
|
```
|
|
|
|
Registers or cancels message arrival notification. When a message arrives at a previously empty queue, a signal notification is sent to the registered task.
|
|
|
|
If `notification` is `NULL`, the current registration is cancelled. The registration is automatically cancelled after the notification is sent and must be re-registered.
|
|
|
|
**Parameters**:
|
|
|
|
- `mqdes` Message queue descriptor.
|
|
- `notification` Notification configuration, including:
|
|
- `sigev_notify` Notification method (should be `SIGEV_SIGNAL`).
|
|
- `sigev_signo` Signal number for notification.
|
|
- `sigev_value` Value passed with the signal.
|
|
|
|
**Returns**:
|
|
|
|
Returns 0 on success, or -1 (`ERROR`) on failure and sets `errno`:
|
|
|
|
- `EBADF` `mqdes` is not a valid descriptor.
|
|
- `EBUSY` Another task has already registered notification for this queue.
|
|
- `EINVAL` `sigev_notify` is not a valid value, or the signal number is invalid.
|
|
- `ENOMEM` Insufficient memory.
|
|
|
|
**Notes**:
|
|
|
|
- **Behavior difference from POSIX**: In openvela, the notification signal is still sent to the registered task even when a task is blocked on `mq_receive()` waiting for a message. The POSIX specification requires that no notification be sent in this case (the message directly satisfies the waiting `mq_receive()`).
|
|
|
|
**POSIX Compatibility**: Partially compatible with the POSIX interface of the same name (notification timing differs from the POSIX specification).
|