summaryrefslogtreecommitdiff
path: root/nuttx/sched/mq_receive.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-03-28 14:48:42 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-03-28 14:48:42 +0000
commit151a39425178ee628c924b8231ca65e24ee386d7 (patch)
treec509b82d096f72a52b58c51d7cca13d20ef818bb /nuttx/sched/mq_receive.c
parent02ca18a9e0cd6c8a31f501dcd05cef13caa5a911 (diff)
downloadpx4-nuttx-151a39425178ee628c924b8231ca65e24ee386d7.tar.gz
px4-nuttx-151a39425178ee628c924b8231ca65e24ee386d7.tar.bz2
px4-nuttx-151a39425178ee628c924b8231ca65e24ee386d7.zip
mq_receive/send: Return appropriate errnos and stop waiting if signal received.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@164 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/sched/mq_receive.c')
-rw-r--r--nuttx/sched/mq_receive.c198
1 files changed, 120 insertions, 78 deletions
diff --git a/nuttx/sched/mq_receive.c b/nuttx/sched/mq_receive.c
index 65fcb81c2..aab7847f1 100644
--- a/nuttx/sched/mq_receive.c
+++ b/nuttx/sched/mq_receive.c
@@ -43,6 +43,7 @@
#include <fcntl.h> /* O_NONBLOCK */
#include <string.h>
#include <assert.h>
+#include <errno.h>
#include <mqueue.h>
#include <sched.h>
#include <debug.h>
@@ -106,8 +107,17 @@
* priority.
*
* Return Value:
- * Length of the selected message in bytes, otherwise -1
- * (ERROR).
+ * One success, the length of the selected message in bytes.is
+ * returned. On failure, -1 (ERROR) is returned and the errno
+ * is set appropriately:
+ *
+ * EAGAIN The queue was empty, and the O_NONBLOCK flag was set
+ * for the message queue description referred to by 'mqdes'.
+ * EPERM Message queue opened not opened for reading.
+ * EMSGSIZE 'msglen' was less than the maxmsgsize attribute of the
+ * message queue.
+ * EINTR The call was interrupted by a signal handler.
+ * EINVAL Invalid 'msg' or 'mqdes'
*
* Assumptions:
*
@@ -125,110 +135,142 @@ int mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio)
/* Verify the input parameters */
- sched_lock();
- if (msg && mqdes && (mqdes->oflags & O_RDOK) != 0 &&
- msglen >= (size_t)mqdes->msgq->maxmsgsize)
+ if (!msg || !mqdes)
{
- /* Get a pointer to the message queue */
+ *get_errno_ptr() = EINVAL;
+ return ERROR;
+ }
- msgq = mqdes->msgq;
+ if ((mqdes->oflags & O_RDOK) == 0)
+ {
+ *get_errno_ptr() = EPERM;
+ return ERROR;
+ }
- /* Several operations must be performed below: We must determine if
- * a message is pending and, if not, wait for the message. Since
- * messages can be sent from the interrupt level, there is a race
- * condition that can only be eliminated by disabling interrupts!
- */
+ if (msglen < (size_t)mqdes->msgq->maxmsgsize)
+ {
+ *get_errno_ptr() = EMSGSIZE;
+ return ERROR;
+ }
+
+ /* Get a pointer to the message queue */
+
+ sched_lock();
+ msgq = mqdes->msgq;
+
+ /* Several operations must be performed below: We must determine if
+ * a message is pending and, if not, wait for the message. Since
+ * messages can be sent from the interrupt level, there is a race
+ * condition that can only be eliminated by disabling interrupts!
+ */
- saved_state = irqsave();
+ saved_state = irqsave();
- /* Get the message from the head of the queue */
+ /* Get the message from the head of the queue */
- while ((curr = (FAR mqmsg_t*)sq_remfirst(&msgq->msglist)) == NULL)
+ while ((curr = (FAR mqmsg_t*)sq_remfirst(&msgq->msglist)) == NULL)
+ {
+ /* Should we block until there the above condition has been
+ * satisfied?
+ */
+
+ if (!(mqdes->oflags & O_NONBLOCK))
{
- /* Should we block until there the above condition has been
- * satisfied?
- */
+ /* Block and try again */
- if (!(mqdes->oflags & O_NONBLOCK))
- {
- /* Block and try again */
+ rtcb = (FAR _TCB*)g_readytorun.head;
+ rtcb->msgwaitq = msgq;
+ msgq->nwaitnotempty++;
- rtcb = (FAR _TCB*)g_readytorun.head;
- rtcb->msgwaitq = msgq;
- msgq->nwaitnotempty++;
- up_block_task(rtcb, TSTATE_WAIT_MQNOTEMPTY);
- }
- else
+ *get_errno_ptr() = OK;
+ up_block_task(rtcb, TSTATE_WAIT_MQNOTEMPTY);
+
+ /* When we resume at this point, either (1) the message queue
+ * is no longer empty, or (2) the wait has been interrupted by
+ * a signal. We can detect the latter case be examining the
+ * errno value (should be EINTR).
+ */
+
+ if (*get_errno_ptr() != OK)
{
break;
}
}
-
- /* If we got message, then decrement the number of messages in
- * the queue while we are still in the critical section
- */
-
- if (curr)
+ else
{
- msgq->nmsgs--;
+ /* The queue was empty, and the O_NONBLOCK flag was set for the
+ * message queue description referred to by 'mqdes'.
+ */
+
+ *get_errno_ptr() = EAGAIN;
+ break;
}
- irqrestore(saved_state);
+ }
- /* Check (again) if we got a message from the message queue*/
+ /* If we got message, then decrement the number of messages in
+ * the queue while we are still in the critical section
+ */
- if (curr)
- {
- /* Get the length of the message (also the return value) */
+ if (curr)
+ {
+ msgq->nmsgs--;
+ }
+ irqrestore(saved_state);
- ret = rcvmsglen = curr->msglen;
+ /* Check (again) if we got a message from the message queue*/
- /* Copy the message into the caller's buffer */
+ if (curr)
+ {
+ /* Get the length of the message (also the return value) */
- memcpy(msg, (const void*)curr->mail, rcvmsglen);
+ ret = rcvmsglen = curr->msglen;
- /* Copy the message priority as well (if a buffer is provided) */
+ /* Copy the message into the caller's buffer */
- if (prio)
- {
- *prio = curr->priority;
- }
+ memcpy(msg, (const void*)curr->mail, rcvmsglen);
- /* We are done with the message. Deallocate it now. */
+ /* Copy the message priority as well (if a buffer is provided) */
- mq_msgfree(curr);
+ if (prio)
+ {
+ *prio = curr->priority;
+ }
- /* Check if any tasks are waiting for the MQ not full event. */
+ /* We are done with the message. Deallocate it now. */
- if (msgq->nwaitnotfull > 0)
+ mq_msgfree(curr);
+
+ /* Check if any tasks are waiting for the MQ not full event. */
+
+ if (msgq->nwaitnotfull > 0)
+ {
+ /* Find the highest priority task that is waiting for
+ * this queue to be not-full in g_waitingformqnotfull list.
+ * This must be performed in a critical section because
+ * messages can be sent from interrupt handlers.
+ */
+
+ saved_state = irqsave();
+ for (btcb = (FAR _TCB*)g_waitingformqnotfull.head;
+ btcb && btcb->msgwaitq != msgq;
+ btcb = btcb->flink);
+
+ /* If one was found, unblock it. NOTE: There is a race
+ * condition here: the queue might be full again by the
+ * time the task is unblocked
+ */
+
+ if (!btcb)
+ {
+ PANIC(OSERR_MQNOTFULLCOUNT);
+ }
+ else
{
- /* Find the highest priority task that is waiting for
- * this queue to be not-full in g_waitingformqnotfull list.
- * This must be performed in a critical section because
- * messages can be sent from interrupt handlers.
- */
-
- saved_state = irqsave();
- for (btcb = (FAR _TCB*)g_waitingformqnotfull.head;
- btcb && btcb->msgwaitq != msgq;
- btcb = btcb->flink);
-
- /* If one was found, unblock it. NOTE: There is a race
- * condition here: the queue might be full again by the
- * time the task is unblocked
- */
-
- if (!btcb)
- {
- PANIC(OSERR_MQNOTFULLCOUNT);
- }
- else
- {
- btcb->msgwaitq = NULL;
- msgq->nwaitnotfull--;
- up_unblock_task(btcb);
- }
- irqrestore(saved_state);
+ btcb->msgwaitq = NULL;
+ msgq->nwaitnotfull--;
+ up_unblock_task(btcb);
}
+ irqrestore(saved_state);
}
}