diff --git a/TODO b/TODO index 0b06bb6786..a2b3df9f00 100644 --- a/TODO +++ b/TODO @@ -12,7 +12,7 @@ nuttx/ (1) Memory Managment (mm/) (3) Signals (sched/signal, arch/) (2) pthreads (sched/pthread) - (1) Message Queues (sched/mqueue) + (0) Message Queues (sched/mqueue) (4) C++ Support (6) Binary loaders (binfmt/) (12) Network (net/, drivers/net) @@ -393,24 +393,8 @@ o pthreads (sched/pthreads) solution. So I discarded a few hours of programming. Not a big loss from the experience I gained." -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 Message Queues (sched/mqueue) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ o Kernel/Protected Build ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/configs/samv71-xult/README.txt b/configs/samv71-xult/README.txt index c73822d50c..b073a5fd9f 100644 --- a/configs/samv71-xult/README.txt +++ b/configs/samv71-xult/README.txt @@ -233,7 +233,11 @@ Configurations Configures the NuttShell (nsh) located at examples/nsh. 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: CONFIG_ARCH_INTERRUPTSTACK=2048 @@ -242,10 +246,18 @@ Configurations CONFIG_PTHREAD_STACK_DEFAULT=2048 ... and others ... - 2. NSH built-in applications are supported. + 3. NSH built-in applications are supported. Binary Formats: CONFIG_BUILTIN=y : Enable support for built-in programs Application Configuration: 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 diff --git a/configs/samv71-xult/nsh/defconfig b/configs/samv71-xult/nsh/defconfig index d3407be2b6..a2222654be 100644 --- a/configs/samv71-xult/nsh/defconfig +++ b/configs/samv71-xult/nsh/defconfig @@ -212,10 +212,10 @@ CONFIG_SAMV7_HAVE_USART2=y # CONFIG_SAMV7_TWIM0 is not set # CONFIG_SAMV7_TWIM1 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_UART2 is not set -# CONFIG_SAMV7_UART3 is not set +CONFIG_SAMV7_UART3=y # CONFIG_SAMV7_UART4 is not set # CONFIG_SAMV7_USBDEVHS is not set # CONFIG_SAMV7_USBHOSTHS is not set @@ -480,10 +480,10 @@ CONFIG_SERIAL=y # CONFIG_DEV_LOWCONSOLE is not set # CONFIG_16550_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_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_UART5 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_ARCH_HAVE_SERIAL_TERMIOS=y # 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_NO_SERIAL_CONSOLE is not set # -# UART0 Configuration +# UART3 Configuration # -CONFIG_UART0_RXBUFSIZE=256 -CONFIG_UART0_TXBUFSIZE=256 -CONFIG_UART0_BAUD=115200 -CONFIG_UART0_BITS=8 -CONFIG_UART0_PARITY=0 -CONFIG_UART0_2STOP=0 -# CONFIG_UART0_IFLOWCONTROL is not set -# CONFIG_UART0_OFLOWCONTROL is not set +CONFIG_UART3_RXBUFSIZE=256 +CONFIG_UART3_TXBUFSIZE=256 +CONFIG_UART3_BAUD=115200 +CONFIG_UART3_BITS=8 +CONFIG_UART3_PARITY=0 +CONFIG_UART3_2STOP=0 +# CONFIG_UART3_IFLOWCONTROL is not set +# CONFIG_UART3_OFLOWCONTROL is not set # CONFIG_USBDEV is not set # CONFIG_USBHOST is not set # CONFIG_WIRELESS is not set diff --git a/sched/mqueue/mq_send.c b/sched/mqueue/mq_send.c index 697e0a0ecb..007af988b0 100644 --- a/sched/mqueue/mq_send.c +++ b/sched/mqueue/mq_send.c @@ -180,4 +180,3 @@ int mq_send(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio) sched_unlock(); return ret; } - diff --git a/sched/mqueue/mq_sndinternal.c b/sched/mqueue/mq_sndinternal.c index 4291ee7213..6b521c05b7 100644 --- a/sched/mqueue/mq_sndinternal.c +++ b/sched/mqueue/mq_sndinternal.c @@ -306,7 +306,7 @@ int mq_waitsend(mqd_t mqdes) * * Description: * 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 * queue notifications setup by mq_notify. And, finally, it awakens any * tasks that were waiting for the message not empty event. diff --git a/sched/mqueue/mq_timedsend.c b/sched/mqueue/mq_timedsend.c index e144956491..1605fee98f 100644 --- a/sched/mqueue/mq_timedsend.c +++ b/sched/mqueue/mq_timedsend.c @@ -1,7 +1,7 @@ /**************************************************************************** * 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 * * 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_msg_s *mqmsg = NULL; irqstate_t saved_state; + int ticks; + int result; int ret = ERROR; 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; } - if (!abstime || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) - { - set_errno(EINVAL); - return ERROR; - } - /* Get a pointer to the message queue */ 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 * unless the queue is full, but we will reserve it up front * before we enter the following critical section. @@ -219,98 +247,81 @@ int mq_timedsend(mqd_t mqdes, FAR const char *msg, size_t msglen, int prio, if (!rtcb->waitdog) { set_errno(EINVAL); + sched_unlock(); return ERROR; } - /* Allocate a message structure: - * - If we are called from an interrupt handler, or - * - If the message queue is not full, or + /* We are not in an interrupt 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 + * disabled here so that this time stays valid until the wait begins. */ - 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 */ + result = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks); - irqrestore(saved_state); - mqmsg = mq_msgalloc(); + /* 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); + ret = ERROR; + } + + /* Start the watchdog and begin the wait for MQ not full */ + else { - int ticks; + /* Start the watchdog */ - /* 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 - * disabled here so that this time stays valid until the wait begins. + wd_start(rtcb->waitdog, ticks, (wdentry_t)mq_sndtimeout, 1, getpid()); + + /* And wait for the message queue to be non-empty */ + + ret = mq_waitsend(mqdes); + + /* This may return with an error and errno set to either EINTR + * or ETIMEOUT. Cancel the watchdog timer in any event. */ - 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); - ret = ERROR; - } - - /* Start the watchdog and begin the wait for MQ not full */ - - if (result == OK) - { - /* Start the watchdog */ - - wd_start(rtcb->waitdog, ticks, (wdentry_t)mq_sndtimeout, 1, getpid()); - - /* And wait for the message queue to be non-empty */ - - ret = mq_waitsend(mqdes); - - /* This may return with an error and errno set to either EINTR - * or ETIMEOUT. Cancel the watchdog timer in any event. - */ - - wd_cancel(rtcb->waitdog); - } - - /* That is the end of the atomic operations */ - - irqrestore(saved_state); - - /* If any of the above failed, set the errno. Otherwise, there should - * be space for another message in the message queue. NOW we can allocate - * the message structure. - */ - - if (ret == OK) - { - mqmsg = mq_msgalloc(); - } + wd_cancel(rtcb->waitdog); } - /* 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. + /* That is the end of the atomic operations */ + + irqrestore(saved_state); + + /* If any of the above failed, set the errno. Otherwise, there should + * be space for another message in the message queue. NOW we can allocate + * the message structure. */ - if (mqmsg) + if (ret == OK) { - /* Yes, peform the message send. */ + mqmsg = mq_msgalloc(); + if (!mqmsg) + { + /* Failed to allocate the message */ - ret = mq_dosend(mqdes, mqmsg, msg, msglen, prio); + set_errno(ENOMEM); + ret = ERROR; + } + else + { + /* Perform the message send. */ + + ret = mq_dosend(mqdes, mqmsg, msg, msglen, prio); + } } sched_unlock();