summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorhzt <[email protected]>2026-02-14 13:06:52 +0800
committerRbb666 <[email protected]>2026-02-24 13:39:05 +0800
commit1b39e04687052d22299abcbd040a45357f4c5bf1 (patch)
tree611fde541e9b7bd1444c52872d644ec1196c9699 /components
parent040c0290554f8604fd0522748b09b0e2c5632002 (diff)
[libc/posix] Fix mq_send() to block when queue is full per POSIX standard
The POSIX mq_send() function currently passes timeout=0 to rt_mq_send_wait_prio(), causing it to return immediately when the queue is full instead of blocking as required by POSIX.1-2017. This patch: 1. Changes mq_send() to use RT_WAITING_FOREVER for blocking behavior 2. Implements mq_timedsend() properly with timeout support 3. Fixes errno mapping for different error conditions Reference: POSIX.1-2017 mq_send(3p): "If the specified message queue is full, mq_send() shall block until space becomes available to enqueue the message, or until mq_send() is interrupted by a signal." Fixes: https://github.com/RT-Thread/rt-thread/issues/11196 Signed-off-by: hzt <[email protected]>
Diffstat (limited to 'components')
-rw-r--r--components/libc/posix/ipc/mqueue.c65
1 files changed, 50 insertions, 15 deletions
diff --git a/components/libc/posix/ipc/mqueue.c b/components/libc/posix/ipc/mqueue.c
index 17449662b0..03a412b812 100644
--- a/components/libc/posix/ipc/mqueue.c
+++ b/components/libc/posix/ipc/mqueue.c
@@ -226,10 +226,10 @@ RTM_EXPORT(mq_receive);
* The priority of the message is specified by the msg_prio parameter.
* If either the message queue identified by id or the msg_ptr buffer is a null pointer, errno is set to EINVAL,
* indicating an invalid argument, and the function returns -1.
- * The function then attempts to send the message to the message queue using the rt_mq_send_wait_prio() function
- * with zero timeout and uninterruptible mode.
+ * If the message queue is full, the function blocks until space becomes available,
+ * following POSIX standard behavior.
* If the message is successfully sent, the function returns 0.
- * If an error occurs during the send operation, errno is set to EBADF, indicating a bad file descriptor,
+ * If an error occurs during the send operation, errno is set appropriately,
* and the function returns -1.
*/
int mq_send(mqd_t id, const char *msg_ptr, size_t msg_len, unsigned msg_prio)
@@ -245,11 +245,18 @@ int mq_send(mqd_t id, const char *msg_ptr, size_t msg_len, unsigned msg_prio)
rt_set_errno(EINVAL);
return -1;
}
- result = rt_mq_send_wait_prio(mq, (void *)msg_ptr, msg_len, msg_prio, 0, RT_UNINTERRUPTIBLE);
+ result = rt_mq_send_wait_prio(mq, (void *)msg_ptr, msg_len, msg_prio, RT_WAITING_FOREVER, RT_UNINTERRUPTIBLE);
if (result == RT_EOK)
return 0;
- rt_set_errno(EBADF);
+ if (result == -RT_EINTR)
+ rt_set_errno(EINTR);
+ else if (result == -RT_ERROR)
+ rt_set_errno(EMSGSIZE);
+ else if (result == -RT_EINVAL)
+ rt_set_errno(EINVAL);
+ else
+ rt_set_errno(EBADF);
return -1;
}
@@ -320,21 +327,19 @@ ssize_t mq_timedreceive(mqd_t id,
RTM_EXPORT(mq_timedreceive);
/**
- * @brief Sends a message to a message queue with a timeout (not supported).
+ * @brief Sends a message to a message queue with a timeout.
* @param id Message queue descriptor.
* @param msg_ptr Pointer to the buffer containing the message to be sent.
* @param msg_len Size of the message to be sent.
* @param msg_prio Priority of the message to be sent.
- * @param abs_timeout Pointer to a struct timespec specifying the absolute timeout value (ignored).
+ * @param abs_timeout Pointer to a struct timespec specifying the absolute timeout value (ignored if null).
* @return Upon successful completion, returns 0;
* otherwise, returns -1 and sets errno to indicate the error.
*
- * @note This function attempts to send a message to the message queue identified by id with a specified timeout,
- * but timed send is not supported in the RT-Thread environment.
- * Therefore, the function simply delegates the message sending operation to the mq_send() function,
- * which does not involve a timeout.
- * The abs_timeout parameter is ignored, and the message is sent without waiting for a timeout to occur.
- * The function returns the result of the mq_send() function, which indicates whether the message was successfully sent.
+ * @note This function sends a message to the message queue identified by id with a specified timeout.
+ * If the message queue is full and the timeout has not expired, the function blocks.
+ * If abs_timeout is NULL, the function waits indefinitely (same as mq_send).
+ * If the timeout expires before space becomes available, errno is set to ETIMEDOUT.
*/
int mq_timedsend(mqd_t id,
const char *msg_ptr,
@@ -342,8 +347,38 @@ int mq_timedsend(mqd_t id,
unsigned msg_prio,
const struct timespec *abs_timeout)
{
- /* RT-Thread does not support timed send */
- return mq_send(id, msg_ptr, msg_len, msg_prio);
+ rt_mq_t mq;
+ rt_err_t result;
+ int tick = 0;
+ struct mqueue_file *mq_file;
+ mq_file = fd_get(id)->vnode->data;
+ mq = (rt_mq_t)mq_file->data;
+
+ if ((mq == RT_NULL) || (msg_ptr == RT_NULL))
+ {
+ rt_set_errno(EINVAL);
+ return -1;
+ }
+
+ if (abs_timeout != RT_NULL)
+ tick = rt_timespec_to_tick(abs_timeout);
+ else
+ tick = RT_WAITING_FOREVER;
+
+ result = rt_mq_send_wait_prio(mq, (void *)msg_ptr, msg_len, msg_prio, tick, RT_UNINTERRUPTIBLE);
+ if (result == RT_EOK)
+ return 0;
+
+ if (result == -RT_ETIMEOUT)
+ rt_set_errno(ETIMEDOUT);
+ else if (result == -RT_EINTR)
+ rt_set_errno(EINTR);
+ else if (result == -RT_ERROR)
+ rt_set_errno(EMSGSIZE);
+ else
+ rt_set_errno(EBADF);
+
+ return -1;
}
RTM_EXPORT(mq_timedsend);