diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-03-28 14:48:42 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-03-28 14:48:42 +0000 |
commit | 151a39425178ee628c924b8231ca65e24ee386d7 (patch) | |
tree | c509b82d096f72a52b58c51d7cca13d20ef818bb /nuttx/sched/mq_receive.c | |
parent | 02ca18a9e0cd6c8a31f501dcd05cef13caa5a911 (diff) | |
download | px4-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.c | 198 |
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); } } |