ssize_t mq_receive(mqd_t mqdes, FAR char *msg, size_t msglen, FAR int *prio) { FAR struct mqueue_msg_s *mqmsg; irqstate_t saved_state; ssize_t ret = ERROR; DEBUGASSERT(up_interrupt_context() == false); /* Verify the input parameters and, in case of an error, set * errno appropriately. */ if (mq_verifyreceive(mqdes, msg, msglen) != OK) { return ERROR; } /* Get the next message from the message queue. We will disable * pre-emption until we have completed the message received. This * is not too bad because if the receipt takes a long time, it will * be because we are blocked waiting for a message and pre-emption * will be re-enabled while we are blocked */ sched_lock(); /* Furthermore, mq_waitreceive() expects to have interrupts disabled * because messages can be sent from interrupt level. */ saved_state = irqsave(); /* Get the message from the message queue */ mqmsg = mq_waitreceive(mqdes); irqrestore(saved_state); /* Check if we got a message from the message queue. We might * not have a message if: * * - The message queue is empty and O_NONBLOCK is set in the mqdes * - The wait was interrupted by a signal */ if (mqmsg) { ret = mq_doreceive(mqdes, mqmsg, msg, prio); } sched_unlock(); return ret; }
ssize_t mq_timedreceive(mqd_t mqdes, void *msg, size_t msglen, int *prio, const struct timespec *abstime) { FAR struct tcb_s *rtcb = (FAR struct tcb_s *)g_readytorun.head; FAR mqmsg_t *mqmsg; irqstate_t saved_state; int ret = ERROR; DEBUGASSERT(up_interrupt_context() == false && rtcb->waitdog == NULL); /* Verify the input parameters and, in case of an error, set * errno appropriately. */ if (mq_verifyreceive(mqdes, msg, msglen) != OK) { return ERROR; } if (!abstime || abstime->tv_sec < 0 || abstime->tv_nsec > 1000000000) { set_errno(EINVAL); return ERROR; } /* Create a watchdog. We will not actually need this watchdog * unless the queue is not empty, but we will reserve it up front * before we enter the following critical section. */ rtcb->waitdog = wd_create(); if (!rtcb->waitdog) { set_errno(EINVAL); return ERROR; } /* Get the next mesage from the message queue. We will disable * pre-emption until we have completed the message received. This * is not too bad because if the receipt takes a long time, it will * be because we are blocked waiting for a message and pre-emption * will be re-enabled while we are blocked */ sched_lock(); /* Furthermore, mq_waitreceive() expects to have interrupts disabled * because messages can be sent from interrupt level. */ saved_state = irqsave(); /* Check if the message queue is empty. If it is NOT empty, then we * will not need to start timer. */ if (mqdes->msgq->msglist.head == NULL) { int ticks; /* Convert the timespec to clock ticks. We must have interrupts * disabled here so that this time stays valid until the wait begins. */ int result = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks); /* If the time has already expired and the message queue is empty, * return immediately. */ if (result == OK && ticks <= 0) { result = ETIMEDOUT; } /* Handle any time-related errors */ if (result != OK) { set_errno(result); irqrestore(saved_state); sched_unlock(); wd_delete(rtcb->waitdog); rtcb->waitdog = NULL; return ERROR; } /* Start the watchdog */ wd_start(rtcb->waitdog, ticks, (wdentry_t)mq_rcvtimeout, 1, getpid()); } /* Get the message from the message queue */ mqmsg = mq_waitreceive(mqdes); /* Stop the watchdog timer (this is not harmful in the case where * it was never started) */ wd_cancel(rtcb->waitdog); /* We can now restore interrupts */ irqrestore(saved_state); /* Check if we got a message from the message queue. We might * not have a message if: * * - The message queue is empty and O_NONBLOCK is set in the mqdes * - The wait was interrupted by a signal * - The watchdog timeout expired */ if (mqmsg) { ret = mq_doreceive(mqdes, mqmsg, msg, prio); } sched_unlock(); wd_delete(rtcb->waitdog); rtcb->waitdog = NULL; return ret; }