mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 17:48:54 +08:00
mq_timedsend(): Do check for time errors if the message queue is not full. Noted by Freddie Chopin
This commit is contained in:
@@ -12,7 +12,7 @@ nuttx/
|
|||||||
(1) Memory Managment (mm/)
|
(1) Memory Managment (mm/)
|
||||||
(3) Signals (sched/signal, arch/)
|
(3) Signals (sched/signal, arch/)
|
||||||
(2) pthreads (sched/pthread)
|
(2) pthreads (sched/pthread)
|
||||||
(1) Message Queues (sched/mqueue)
|
(0) Message Queues (sched/mqueue)
|
||||||
(4) C++ Support
|
(4) C++ Support
|
||||||
(6) Binary loaders (binfmt/)
|
(6) Binary loaders (binfmt/)
|
||||||
(12) Network (net/, drivers/net)
|
(12) Network (net/, drivers/net)
|
||||||
@@ -393,25 +393,9 @@ o pthreads (sched/pthreads)
|
|||||||
solution. So I discarded a few hours of programming. Not a
|
solution. So I discarded a few hours of programming. Not a
|
||||||
big loss from the experience I gained."
|
big loss from the experience I gained."
|
||||||
|
|
||||||
Message Queues (sched/mqueue)
|
o Message Queues (sched/mqueue)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Title: mq_timedsend() ERROR DETECTION
|
|
||||||
Description: mq_timedsend() will always return an error an invalid time is
|
|
||||||
provided. However, OpenGroup.org says:
|
|
||||||
|
|
||||||
"Under no circumstance shall the operation fail with a timeout
|
|
||||||
if there is sufficient room in the queue to add the message
|
|
||||||
immediately. The validity of the abstime parameter need not be
|
|
||||||
checked when there is sufficient room in the queue."
|
|
||||||
|
|
||||||
Status: Open
|
|
||||||
Priority: Low. This is a valid POSIX compliance issue, but not thought
|
|
||||||
to be really important in real work programming. It could
|
|
||||||
be used to conditionally block like O_NONBLOCK by providing a
|
|
||||||
bad time to the function. That seeks hokey and I can't think
|
|
||||||
of any other real world use case the demands this functionality.
|
|
||||||
|
|
||||||
o Kernel/Protected Build
|
o Kernel/Protected Build
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|||||||
@@ -233,7 +233,11 @@ Configurations
|
|||||||
Configures the NuttShell (nsh) located at examples/nsh.
|
Configures the NuttShell (nsh) located at examples/nsh.
|
||||||
NOTES:
|
NOTES:
|
||||||
|
|
||||||
1. Default stack sizes are large and should really be tuned to reduce
|
1. The serial console is configured by default for use with and Arduino
|
||||||
|
serial shield (UART3). You will need to reconfigure if you will
|
||||||
|
to use a different U[S]ART.
|
||||||
|
|
||||||
|
2. Default stack sizes are large and should really be tuned to reduce
|
||||||
the RAM footprint:
|
the RAM footprint:
|
||||||
|
|
||||||
CONFIG_ARCH_INTERRUPTSTACK=2048
|
CONFIG_ARCH_INTERRUPTSTACK=2048
|
||||||
@@ -242,10 +246,18 @@ Configurations
|
|||||||
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
||||||
... and others ...
|
... and others ...
|
||||||
|
|
||||||
2. NSH built-in applications are supported.
|
3. NSH built-in applications are supported.
|
||||||
|
|
||||||
Binary Formats:
|
Binary Formats:
|
||||||
CONFIG_BUILTIN=y : Enable support for built-in programs
|
CONFIG_BUILTIN=y : Enable support for built-in programs
|
||||||
|
|
||||||
Application Configuration:
|
Application Configuration:
|
||||||
CONFIG_NSH_BUILTIN_APPS=y : Enable starting apps from NSH command line
|
CONFIG_NSH_BUILTIN_APPS=y : Enable starting apps from NSH command line
|
||||||
|
|
||||||
|
4. Performance-related Configuration settings:
|
||||||
|
|
||||||
|
# CONFIG_ARMV7M_ICACHE is not set : Can be enabled, not verified
|
||||||
|
# CONFIG_ARMV7M_DCACHE is not set : Can be enabled, not verified
|
||||||
|
# CONFIG_ARCH_FPU is not set : Can be enabled, not verified
|
||||||
|
# CONFIG_ARMV7M_ITCM is not set : Support not yet in place
|
||||||
|
# CONFIG_ARMV7M_DTCM is not set : Support not yet in place
|
||||||
|
|||||||
@@ -212,10 +212,10 @@ CONFIG_SAMV7_HAVE_USART2=y
|
|||||||
# CONFIG_SAMV7_TWIM0 is not set
|
# CONFIG_SAMV7_TWIM0 is not set
|
||||||
# CONFIG_SAMV7_TWIM1 is not set
|
# CONFIG_SAMV7_TWIM1 is not set
|
||||||
# CONFIG_SAMV7_TWIM2 is not set
|
# CONFIG_SAMV7_TWIM2 is not set
|
||||||
CONFIG_SAMV7_UART0=y
|
# CONFIG_SAMV7_UART0 is not set
|
||||||
# CONFIG_SAMV7_UART1 is not set
|
# CONFIG_SAMV7_UART1 is not set
|
||||||
# CONFIG_SAMV7_UART2 is not set
|
# CONFIG_SAMV7_UART2 is not set
|
||||||
# CONFIG_SAMV7_UART3 is not set
|
CONFIG_SAMV7_UART3=y
|
||||||
# CONFIG_SAMV7_UART4 is not set
|
# CONFIG_SAMV7_UART4 is not set
|
||||||
# CONFIG_SAMV7_USBDEVHS is not set
|
# CONFIG_SAMV7_USBDEVHS is not set
|
||||||
# CONFIG_SAMV7_USBHOSTHS is not set
|
# CONFIG_SAMV7_USBHOSTHS is not set
|
||||||
@@ -480,10 +480,10 @@ CONFIG_SERIAL=y
|
|||||||
# CONFIG_DEV_LOWCONSOLE is not set
|
# CONFIG_DEV_LOWCONSOLE is not set
|
||||||
# CONFIG_16550_UART is not set
|
# CONFIG_16550_UART is not set
|
||||||
# CONFIG_ARCH_HAVE_UART is not set
|
# CONFIG_ARCH_HAVE_UART is not set
|
||||||
CONFIG_ARCH_HAVE_UART0=y
|
# CONFIG_ARCH_HAVE_UART0 is not set
|
||||||
# CONFIG_ARCH_HAVE_UART1 is not set
|
# CONFIG_ARCH_HAVE_UART1 is not set
|
||||||
# CONFIG_ARCH_HAVE_UART2 is not set
|
# CONFIG_ARCH_HAVE_UART2 is not set
|
||||||
# CONFIG_ARCH_HAVE_UART3 is not set
|
CONFIG_ARCH_HAVE_UART3=y
|
||||||
# CONFIG_ARCH_HAVE_UART4 is not set
|
# CONFIG_ARCH_HAVE_UART4 is not set
|
||||||
# CONFIG_ARCH_HAVE_UART5 is not set
|
# CONFIG_ARCH_HAVE_UART5 is not set
|
||||||
# CONFIG_ARCH_HAVE_UART6 is not set
|
# CONFIG_ARCH_HAVE_UART6 is not set
|
||||||
@@ -511,21 +511,22 @@ CONFIG_STANDARD_SERIAL=y
|
|||||||
# CONFIG_SERIAL_OFLOWCONTROL is not set
|
# CONFIG_SERIAL_OFLOWCONTROL is not set
|
||||||
CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
|
CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
|
||||||
# CONFIG_SERIAL_TERMIOS is not set
|
# CONFIG_SERIAL_TERMIOS is not set
|
||||||
CONFIG_UART0_SERIAL_CONSOLE=y
|
# CONFIG_UART0_SERIAL_CONSOLE is not set
|
||||||
|
CONFIG_UART3_SERIAL_CONSOLE=y
|
||||||
# CONFIG_OTHER_SERIAL_CONSOLE is not set
|
# CONFIG_OTHER_SERIAL_CONSOLE is not set
|
||||||
# CONFIG_NO_SERIAL_CONSOLE is not set
|
# CONFIG_NO_SERIAL_CONSOLE is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# UART0 Configuration
|
# UART3 Configuration
|
||||||
#
|
#
|
||||||
CONFIG_UART0_RXBUFSIZE=256
|
CONFIG_UART3_RXBUFSIZE=256
|
||||||
CONFIG_UART0_TXBUFSIZE=256
|
CONFIG_UART3_TXBUFSIZE=256
|
||||||
CONFIG_UART0_BAUD=115200
|
CONFIG_UART3_BAUD=115200
|
||||||
CONFIG_UART0_BITS=8
|
CONFIG_UART3_BITS=8
|
||||||
CONFIG_UART0_PARITY=0
|
CONFIG_UART3_PARITY=0
|
||||||
CONFIG_UART0_2STOP=0
|
CONFIG_UART3_2STOP=0
|
||||||
# CONFIG_UART0_IFLOWCONTROL is not set
|
# CONFIG_UART3_IFLOWCONTROL is not set
|
||||||
# CONFIG_UART0_OFLOWCONTROL is not set
|
# CONFIG_UART3_OFLOWCONTROL is not set
|
||||||
# CONFIG_USBDEV is not set
|
# CONFIG_USBDEV is not set
|
||||||
# CONFIG_USBHOST is not set
|
# CONFIG_USBHOST is not set
|
||||||
# CONFIG_WIRELESS is not set
|
# CONFIG_WIRELESS is not set
|
||||||
|
|||||||
@@ -180,4 +180,3 @@ int mq_send(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio)
|
|||||||
sched_unlock();
|
sched_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ int mq_waitsend(mqd_t mqdes)
|
|||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* This is internal, common logic shared by both mq_send and mq_timesend.
|
* This is internal, common logic shared by both mq_send and mq_timesend.
|
||||||
* This function adds the specificied message (msg) to the message queue
|
* This function adds the specified message (msg) to the message queue
|
||||||
* (mqdes). Then it notifies any tasks that were waiting for message
|
* (mqdes). Then it notifies any tasks that were waiting for message
|
||||||
* queue notifications setup by mq_notify. And, finally, it awakens any
|
* queue notifications setup by mq_notify. And, finally, it awakens any
|
||||||
* tasks that were waiting for the message not empty event.
|
* tasks that were waiting for the message not empty event.
|
||||||
|
|||||||
+51
-40
@@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* sched/mqueue/mq_timedsend.c
|
* sched/mqueue/mq_timedsend.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2009, 2011, 2013-2014 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2009, 2011, 2013-2015 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -187,6 +187,8 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio,
|
|||||||
FAR struct mqueue_inode_s *msgq;
|
FAR struct mqueue_inode_s *msgq;
|
||||||
FAR struct mqueue_msg_s *mqmsg = NULL;
|
FAR struct mqueue_msg_s *mqmsg = NULL;
|
||||||
irqstate_t saved_state;
|
irqstate_t saved_state;
|
||||||
|
int ticks;
|
||||||
|
int result;
|
||||||
int ret = ERROR;
|
int ret = ERROR;
|
||||||
|
|
||||||
DEBUGASSERT(up_interrupt_context() == false && rtcb->waitdog == NULL);
|
DEBUGASSERT(up_interrupt_context() == false && rtcb->waitdog == NULL);
|
||||||
@@ -200,16 +202,42 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio,
|
|||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!abstime || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
|
|
||||||
{
|
|
||||||
set_errno(EINVAL);
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get a pointer to the message queue */
|
/* Get a pointer to the message queue */
|
||||||
|
|
||||||
msgq = mqdes->msgq;
|
msgq = mqdes->msgq;
|
||||||
|
|
||||||
|
/* OpenGroup.org: "Under no circumstance shall the operation fail with a
|
||||||
|
* timeout if there is sufficient room in the queue to add the message
|
||||||
|
* immediately. The validity of the abstime parameter need not be checked
|
||||||
|
* when there is sufficient room in the queue."
|
||||||
|
*
|
||||||
|
* Also ignore the time value if for some crazy reason we were called from
|
||||||
|
* an interrupt handler. This probably really should be an assertion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sched_lock();
|
||||||
|
if (msgq->nmsgs < msgq->maxmsgs || up_interrupt_context())
|
||||||
|
{
|
||||||
|
/* The message queue is not full... Ignore the time parameter and
|
||||||
|
* let mq_send do the work.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = mq_send(mqdes, msg, msglen, prio);
|
||||||
|
sched_unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The message queue is full... We are going to wait. Now we must have a
|
||||||
|
* valid time value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!abstime || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
|
||||||
|
{
|
||||||
|
set_errno(EINVAL);
|
||||||
|
sched_unlock();
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a watchdog. We will not actually need this watchdog
|
/* Create a watchdog. We will not actually need this watchdog
|
||||||
* unless the queue is full, but we will reserve it up front
|
* unless the queue is full, but we will reserve it up front
|
||||||
* before we enter the following critical section.
|
* before we enter the following critical section.
|
||||||
@@ -219,36 +247,19 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio,
|
|||||||
if (!rtcb->waitdog)
|
if (!rtcb->waitdog)
|
||||||
{
|
{
|
||||||
set_errno(EINVAL);
|
set_errno(EINVAL);
|
||||||
|
sched_unlock();
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a message structure:
|
/* We are not in an interrupt handler and the message queue is full.
|
||||||
* - If we are called from an interrupt handler, or
|
* Set up a timed wait for the message queue to become non-full.
|
||||||
* - If the message queue is not full, or
|
|
||||||
*/
|
|
||||||
|
|
||||||
sched_lock();
|
|
||||||
saved_state = irqsave();
|
|
||||||
if (up_interrupt_context() || /* In an interrupt handler */
|
|
||||||
msgq->nmsgs < msgq->maxmsgs) /* OR Message queue not full */
|
|
||||||
{
|
|
||||||
/* Allocate the message */
|
|
||||||
|
|
||||||
irqrestore(saved_state);
|
|
||||||
mqmsg = mq_msgalloc();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int ticks;
|
|
||||||
|
|
||||||
/* We are not in an interupt handler and the message queue is full.
|
|
||||||
* set up a timed wait for the message queue to become non-full.
|
|
||||||
*
|
*
|
||||||
* Convert the timespec to clock ticks. We must have interrupts
|
* Convert the timespec to clock ticks. We must have interrupts
|
||||||
* disabled here so that this time stays valid until the wait begins.
|
* disabled here so that this time stays valid until the wait begins.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int result = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks);
|
saved_state = irqsave();
|
||||||
|
result = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks);
|
||||||
|
|
||||||
/* If the time has already expired and the message queue is empty,
|
/* If the time has already expired and the message queue is empty,
|
||||||
* return immediately.
|
* return immediately.
|
||||||
@@ -269,7 +280,7 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio,
|
|||||||
|
|
||||||
/* Start the watchdog and begin the wait for MQ not full */
|
/* Start the watchdog and begin the wait for MQ not full */
|
||||||
|
|
||||||
if (result == OK)
|
else
|
||||||
{
|
{
|
||||||
/* Start the watchdog */
|
/* Start the watchdog */
|
||||||
|
|
||||||
@@ -298,20 +309,20 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio,
|
|||||||
if (ret == OK)
|
if (ret == OK)
|
||||||
{
|
{
|
||||||
mqmsg = mq_msgalloc();
|
mqmsg = mq_msgalloc();
|
||||||
}
|
if (!mqmsg)
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if we were able to get a message structure -- this can fail
|
|
||||||
* either because we cannot send the message (and didn't bother trying
|
|
||||||
* to allocate it) or because the allocation failed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (mqmsg)
|
|
||||||
{
|
{
|
||||||
/* Yes, peform the message send. */
|
/* Failed to allocate the message */
|
||||||
|
|
||||||
|
set_errno(ENOMEM);
|
||||||
|
ret = ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Perform the message send. */
|
||||||
|
|
||||||
ret = mq_dosend(mqdes, mqmsg, msg, msglen, prio);
|
ret = mq_dosend(mqdes, mqmsg, msg, msglen, prio);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sched_unlock();
|
sched_unlock();
|
||||||
wd_delete(rtcb->waitdog);
|
wd_delete(rtcb->waitdog);
|
||||||
|
|||||||
Reference in New Issue
Block a user