summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nuttx/ChangeLog2
-rw-r--r--nuttx/Documentation/NuttxPortingGuide.html14
-rw-r--r--nuttx/arch/arm/src/kinetis/kinetis_sdhc.c6
-rw-r--r--nuttx/arch/arm/src/sam3u/sam3u_hsmci.c6
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_sdio.c2
-rw-r--r--nuttx/configs/README.txt13
-rw-r--r--nuttx/configs/pic32mx7mmb/src/up_touchscreen.c4
-rw-r--r--nuttx/drivers/input/ads7843e.c4
-rw-r--r--nuttx/drivers/input/stmpe811_base.c2
-rw-r--r--nuttx/drivers/input/stmpe811_tsc.c2
-rw-r--r--nuttx/drivers/input/tsc2007.c4
-rw-r--r--nuttx/drivers/net/enc28j60.c2
-rw-r--r--nuttx/drivers/power/pm_update.c4
-rw-r--r--nuttx/drivers/rwbuffer.c4
-rw-r--r--nuttx/drivers/usbhost/usbhost_hidkbd.c2
-rw-r--r--nuttx/drivers/usbhost/usbhost_skeleton.c6
-rw-r--r--nuttx/drivers/usbhost/usbhost_storage.c2
-rw-r--r--nuttx/include/nuttx/wqueue.h84
-rw-r--r--nuttx/sched/Kconfig33
-rw-r--r--nuttx/sched/Makefile2
-rw-r--r--nuttx/sched/os_bringup.c24
-rw-r--r--nuttx/sched/sched_free.c4
-rw-r--r--nuttx/sched/work_cancel.c16
-rw-r--r--nuttx/sched/work_internal.h48
-rw-r--r--nuttx/sched/work_queue.c14
-rw-r--r--nuttx/sched/work_signal.c96
-rw-r--r--nuttx/sched/work_thread.c215
-rwxr-xr-xnuttx/tools/configure.sh18
28 files changed, 466 insertions, 167 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index b67c066bcb..86e6b52572 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -3250,3 +3250,5 @@
* sched/work_cancel.c: Fix a bad assertion (reported by Mike Smith)
* configs/stm3210e-eval/src/up_idle.c: Correct some power management
compilation errors (reported by Diego Sanchez).
+ * include/nuttx/wqueue.h, sched/work*, and others: Added logic to support
+ a second, lower priority work queue (CONFIG_SCHED_LPWORK).
diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html
index 9df1f9378f..a03d9810fc 100644
--- a/nuttx/Documentation/NuttxPortingGuide.html
+++ b/nuttx/Documentation/NuttxPortingGuide.html
@@ -4069,6 +4069,20 @@ build
the worker thread. Default: 4
</li>
<li>
+ <code>CONFIG_SCHED_LPWORK</code>: If CONFIG_SCHED_WORKQUEUE</code> is defined, then a single work queue is created by default.
+ If <code>CONFIG_SCHED_LPWORK</code> is also defined then an additional, lower-priority work queue will also be created.
+ This lower priority work queue is better suited for more extended processing (such as file system clean-up operations)
+ </li>
+ <li>
+ <code>CONFIG_SCHED_LPWORKPRIORITY</code>: The execution priority of the lower priority worker thread. Default: 50
+ </li>
+ <li>
+ <code>CONFIG_SCHED_LPWORKPERIOD</code>: How often the lower priority worker thread checks for work in units of microseconds. Default: 50*1000 (50 MS).
+ </li>
+ <li>
+ <code>CONFIG_SCHED_LPWORKSTACKSIZE - The stack size allocated for the lower priority worker thread. Default: CONFIG_IDLETHREAD_STACKSIZE.
+ </li>
+ <li>
<code>CONFIG_SCHED_WAITPID</code>: Enables the <a href="NuttxUserGuide.html#waitpid"><code>waitpid()</code><a> API
</li>
<li>
diff --git a/nuttx/arch/arm/src/kinetis/kinetis_sdhc.c b/nuttx/arch/arm/src/kinetis/kinetis_sdhc.c
index 8be3e092af..eec5fba0e0 100644
--- a/nuttx/arch/arm/src/kinetis/kinetis_sdhc.c
+++ b/nuttx/arch/arm/src/kinetis/kinetis_sdhc.c
@@ -1,8 +1,8 @@
/****************************************************************************
* arch/arm/src/kinetis/kinetis_sdhc.c
*
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -2733,7 +2733,7 @@ static void kinetis_callback(void *arg)
/* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg);
- (void)work_queue(&priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
+ (void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
}
else
{
diff --git a/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c b/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
index b7872a2195..9d7c308ca3 100644
--- a/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
+++ b/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
@@ -1,8 +1,8 @@
/****************************************************************************
* arch/arm/src/sam3u/sam3u_sdio.c
*
- * Copyright (C) 2010 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ * Copyright (C) 2010, 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -2343,7 +2343,7 @@ static void sam3u_callback(void *arg)
/* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg);
- (void)work_queue(&priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
+ (void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
}
else
{
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c
index 57d5f80d96..057a5836fd 100644
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.c
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c
@@ -2660,7 +2660,7 @@ static void stm32_callback(void *arg)
/* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg);
- (void)work_queue(&priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
+ (void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
}
else
{
diff --git a/nuttx/configs/README.txt b/nuttx/configs/README.txt
index 1b405b3e45..7ad2825d0c 100644
--- a/nuttx/configs/README.txt
+++ b/nuttx/configs/README.txt
@@ -361,13 +361,24 @@ defconfig -- This is a configuration file similar to the Linux
if memory reclamation is of high priority). If CONFIG_SCHED_WORKQUEUE
is enabled, then the following options can also be used:
CONFIG_SCHED_WORKPRIORITY - The execution priority of the worker
- thread. Default: 50
+ thread. Default: 192
CONFIG_SCHED_WORKPERIOD - How often the worker thread checks for
work in units of microseconds. Default: 50*1000 (50 MS).
CONFIG_SCHED_WORKSTACKSIZE - The stack size allocated for the worker
thread. Default: CONFIG_IDLETHREAD_STACKSIZE.
CONFIG_SIG_SIGWORK - The signal number that will be used to wake-up
the worker thread. Default: 4
+ CONFIG_SCHED_LPWORK. If CONFIG_SCHED_WORKQUEUE is defined, then a single
+ work queue is created by default. If CONFIG_SCHED_LPWORK is also defined
+ then an additional, lower-priority work queue will also be created. This
+ lower priority work queue is better suited for more extended processing
+ (such as file system clean-up operations)
+ CONFIG_SCHED_LPWORKPRIORITY - The execution priority of the lower priority
+ worker thread. Default: 50
+ CONFIG_SCHED_LPWORKPERIOD - How often the lower priority worker thread
+ checks for work in units of microseconds. Default: 50*1000 (50 MS).
+ CONFIG_SCHED_LPWORKSTACKSIZE - The stack size allocated for the lower
+ priority worker thread. Default: CONFIG_IDLETHREAD_STACKSIZE.
CONFIG_SCHED_WAITPID - Enables the waitpid() API
CONFIG_SCHED_ATEXIT - Enables the atexit() API
CONFIG_SCHED_ATEXIT_MAX - By default if CONFIG_SCHED_ATEXIT is
diff --git a/nuttx/configs/pic32mx7mmb/src/up_touchscreen.c b/nuttx/configs/pic32mx7mmb/src/up_touchscreen.c
index 33d7dcbe3f..c8fe53507a 100644
--- a/nuttx/configs/pic32mx7mmb/src/up_touchscreen.c
+++ b/nuttx/configs/pic32mx7mmb/src/up_touchscreen.c
@@ -972,7 +972,7 @@ static void tc_worker(FAR void *arg)
/* Set up the next sample event */
- ret = work_queue(&priv->work, tc_worker, priv, delay);
+ ret = work_queue(HPWORK, &priv->work, tc_worker, priv, delay);
ASSERT(ret == 0);
}
@@ -1420,7 +1420,7 @@ int arch_tcinitialize(int minor)
*/
priv->state = TC_READY;
- ret = work_queue(&priv->work, tc_worker, priv, 0);
+ ret = work_queue(HPWORK, &priv->work, tc_worker, priv, 0);
if (ret != 0)
{
idbg("Failed to queue work: %d\n", ret);
diff --git a/nuttx/drivers/input/ads7843e.c b/nuttx/drivers/input/ads7843e.c
index 750b91ff2e..e08a7a7280 100644
--- a/nuttx/drivers/input/ads7843e.c
+++ b/nuttx/drivers/input/ads7843e.c
@@ -521,7 +521,7 @@ static int ads7843e_schedule(FAR struct ads7843e_dev_s *priv)
*/
DEBUGASSERT(priv->work.worker == NULL);
- ret = work_queue(&priv->work, ads7843e_worker, priv, 0);
+ ret = work_queue(HPWORK, &priv->work, ads7843e_worker, priv, 0);
if (ret != 0)
{
illdbg("Failed to queue work: %d\n", ret);
@@ -1179,7 +1179,7 @@ int ads7843e_register(FAR struct spi_dev_s *dev,
* availability conditions.
*/
- ret = work_queue(&priv->work, ads7843e_worker, priv, 0);
+ ret = work_queue(HPWORK, &priv->work, ads7843e_worker, priv, 0);
if (ret != 0)
{
idbg("Failed to queue work: %d\n", ret);
diff --git a/nuttx/drivers/input/stmpe811_base.c b/nuttx/drivers/input/stmpe811_base.c
index 72af1575a9..f37c24622c 100644
--- a/nuttx/drivers/input/stmpe811_base.c
+++ b/nuttx/drivers/input/stmpe811_base.c
@@ -195,7 +195,7 @@ static int stmpe811_interrupt(int irq, FAR void *context)
* action should be required to protect the work queue.
*/
- ret = work_queue(&priv->work, stmpe811_worker, priv, 0);
+ ret = work_queue(HPWORK, &priv->work, stmpe811_worker, priv, 0);
if (ret != 0)
{
illdbg("Failed to queue work: %d\n", ret);
diff --git a/nuttx/drivers/input/stmpe811_tsc.c b/nuttx/drivers/input/stmpe811_tsc.c
index e2ab2827d5..c7f8b473b8 100644
--- a/nuttx/drivers/input/stmpe811_tsc.c
+++ b/nuttx/drivers/input/stmpe811_tsc.c
@@ -783,7 +783,7 @@ static void stmpe811_timeout(int argc, uint32_t arg1, ...)
* action should be required to protect the work queue.
*/
- ret = work_queue(&priv->timeout, stmpe811_timeoutworker, priv, 0);
+ ret = work_queue(HPWORK, &priv->timeout, stmpe811_timeoutworker, priv, 0);
if (ret != 0)
{
illdbg("Failed to queue work: %d\n", ret);
diff --git a/nuttx/drivers/input/tsc2007.c b/nuttx/drivers/input/tsc2007.c
index 07acb53712..163118b95d 100644
--- a/nuttx/drivers/input/tsc2007.c
+++ b/nuttx/drivers/input/tsc2007.c
@@ -775,7 +775,7 @@ static int tsc2007_interrupt(int irq, FAR void *context)
*/
DEBUGASSERT(priv->work.worker == NULL);
- ret = work_queue(&priv->work, tsc2007_worker, priv, 0);
+ ret = work_queue(HPWORK, &priv->work, tsc2007_worker, priv, 0);
if (ret != 0)
{
illdbg("Failed to queue work: %d\n", ret);
@@ -1316,7 +1316,7 @@ int tsc2007_register(FAR struct i2c_dev_s *dev,
* availability conditions.
*/
- ret = work_queue(&priv->work, tsc2007_worker, priv, 0);
+ ret = work_queue(HPWORK, &priv->work, tsc2007_worker, priv, 0);
if (ret != 0)
{
idbg("Failed to queue work: %d\n", ret);
diff --git a/nuttx/drivers/net/enc28j60.c b/nuttx/drivers/net/enc28j60.c
index 76b0f205b1..0239406a1c 100644
--- a/nuttx/drivers/net/enc28j60.c
+++ b/nuttx/drivers/net/enc28j60.c
@@ -1509,7 +1509,7 @@ static int enc_interrupt(int irq, FAR void *context)
* a good thing to do in any event.
*/
- return work_queue(&priv->work, enc_worker, (FAR void *)priv, 0);
+ return work_queue(HPWORK, &priv->work, enc_worker, (FAR void *)priv, 0);
#endif
}
diff --git a/nuttx/drivers/power/pm_update.c b/nuttx/drivers/power/pm_update.c
index ae5e1f8409..4b6b58c550 100644
--- a/nuttx/drivers/power/pm_update.c
+++ b/nuttx/drivers/power/pm_update.c
@@ -328,7 +328,7 @@ void pm_update(int16_t accum)
/* The work will be performed on the worker thread */
DEBUGASSERT(g_pmglobals.work.worker == NULL);
- (void)work_queue(&g_pmglobals.work, pm_worker, (FAR void*)((intptr_t)accum), 0);
+ (void)work_queue(HPWORK, &g_pmglobals.work, pm_worker, (FAR void*)((intptr_t)accum), 0);
}
-#endif /* CONFIG_PM */ \ No newline at end of file
+#endif /* CONFIG_PM */
diff --git a/nuttx/drivers/rwbuffer.c b/nuttx/drivers/rwbuffer.c
index 1d924e2a05..076ebc7816 100644
--- a/nuttx/drivers/rwbuffer.c
+++ b/nuttx/drivers/rwbuffer.c
@@ -213,7 +213,7 @@ static void rwb_wrstarttimeout(FAR struct rwbuffer_s *rwb)
*/
int ticks = (CONFIG_FS_WRDELAY + CLK_TCK/2) / CLK_TCK;
- (void)work_queue(&rwb->work, rwb_wrtimeout, (FAR void *)rwb, ticks);
+ (void)work_queue(LPWORK, &rwb->work, rwb_wrtimeout, (FAR void *)rwb, ticks);
}
/****************************************************************************
@@ -222,7 +222,7 @@ static void rwb_wrstarttimeout(FAR struct rwbuffer_s *rwb)
static inline void rwb_wrcanceltimeout(struct rwbuffer_s *rwb)
{
- (void)work_cancel(&rwb->work);
+ (void)work_cancel(LPWORK, &rwb->work);
}
/****************************************************************************
diff --git a/nuttx/drivers/usbhost/usbhost_hidkbd.c b/nuttx/drivers/usbhost/usbhost_hidkbd.c
index 73224ff5c0..bb3ecad9e4 100644
--- a/nuttx/drivers/usbhost/usbhost_hidkbd.c
+++ b/nuttx/drivers/usbhost/usbhost_hidkbd.c
@@ -1674,7 +1674,7 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
*/
DEBUGASSERT(priv->work.worker == NULL);
- (void)work_queue(&priv->work, usbhost_destroy, priv, 0);
+ (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
}
return OK;
diff --git a/nuttx/drivers/usbhost/usbhost_skeleton.c b/nuttx/drivers/usbhost/usbhost_skeleton.c
index 0a88a4f1ba..c44a265e80 100644
--- a/nuttx/drivers/usbhost/usbhost_skeleton.c
+++ b/nuttx/drivers/usbhost/usbhost_skeleton.c
@@ -1,8 +1,8 @@
/****************************************************************************
* drivers/usbhost/usbhost_skeleton.c
*
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -1015,7 +1015,7 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy);
DEBUGASSERT(priv->work.worker == NULL);
- (void)work_queue(&priv->work, usbhost_destroy, priv, 0);
+ (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
}
else
{
diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c
index 2e3136b339..2b14676d71 100644
--- a/nuttx/drivers/usbhost/usbhost_storage.c
+++ b/nuttx/drivers/usbhost/usbhost_storage.c
@@ -1786,7 +1786,7 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy);
DEBUGASSERT(priv->work.worker == NULL);
- (void)work_queue(&priv->work, usbhost_destroy, priv, 0);
+ (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
}
else
{
diff --git a/nuttx/include/nuttx/wqueue.h b/nuttx/include/nuttx/wqueue.h
index dfd424c8dc..644585c56f 100644
--- a/nuttx/include/nuttx/wqueue.h
+++ b/nuttx/include/nuttx/wqueue.h
@@ -50,6 +50,75 @@
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_SCHED_WORKQUEUE. Create a dedicated "worker" thread to
+ * handle delayed processing from interrupt handlers. This feature
+ * is required for some drivers but, if there are not complaints,
+ * can be safely disabled. The worker thread also performs
+ * garbage collection -- completing any delayed memory deallocations
+ * from interrupt handlers. If the worker thread is disabled,
+ * then that clean will be performed by the IDLE thread instead
+ * (which runs at the lowest of priority and may not be appropriate
+ * if memory reclamation is of high priority). If CONFIG_SCHED_WORKQUEUE
+ * is enabled, then the following options can also be used:
+ * CONFIG_SCHED_WORKPRIORITY - The execution priority of the worker
+ * thread. Default: 192
+ * CONFIG_SCHED_WORKPERIOD - How often the worker thread checks for
+ * work in units of microseconds. Default: 50*1000 (50 MS).
+ * CONFIG_SCHED_WORKSTACKSIZE - The stack size allocated for the worker
+ * thread. Default: CONFIG_IDLETHREAD_STACKSIZE.
+ * CONFIG_SIG_SIGWORK - The signal number that will be used to wake-up
+ * the worker thread. Default: 4
+ *
+ * CONFIG_SCHED_LPWORK. If CONFIG_SCHED_WORKQUEUE is defined, then a single
+ * work queue is created by default. If CONFIG_SCHED_LPWORK is also defined
+ * then an additional, lower-priority work queue will also be created. This
+ * lower priority work queue is better suited for more extended processing
+ * (such as file system clean-up operations)
+ * CONFIG_SCHED_LPWORKPRIORITY - The execution priority of the lower priority
+ * worker thread. Default: 50
+ * CONFIG_SCHED_LPWORKPERIOD - How often the lower priority worker thread
+ * checks for work in units of microseconds. Default: 50*1000 (50 MS).
+ * CONFIG_SCHED_LPWORKSTACKSIZE - The stack size allocated for the lower
+ * priority worker thread. Default: CONFIG_IDLETHREAD_STACKSIZE.
+ */
+
+#ifndef CONFIG_SCHED_WORKPRIORITY
+# define CONFIG_SCHED_WORKPRIORITY 192
+#endif
+
+#ifndef CONFIG_SCHED_WORKPERIOD
+# define CONFIG_SCHED_WORKPERIOD (50*1000) /* 50 milliseconds */
+#endif
+
+#ifndef CONFIG_SCHED_WORKSTACKSIZE
+# define CONFIG_SCHED_WORKSTACKSIZE CONFIG_IDLETHREAD_STACKSIZE
+#endif
+
+#ifdef CONFIG_SCHED_LPWORK
+# ifndef CONFIG_SCHED_LPWORKPRIORITY
+# define CONFIG_SCHED_LPWORKPRIORITY 50
+# endif
+
+# ifndef CONFIG_SCHED_LPWORKPERIOD
+# define CONFIG_SCHED_LPWORKPERIOD (50*1000) /* 50 milliseconds */
+# endif
+
+# ifndef CONFIG_SCHED_LPWORKSTACKSIZE
+# define CONFIG_SCHED_LPWORKSTACKSIZE CONFIG_IDLETHREAD_STACKSIZE
+# endif
+#endif
+
+/* Work queue IDs (indices). These are both zero if there is only one work
+ * queue.
+ */
+
+#define HPWORK 0
+#ifdef CONFIG_SCHED_LPWORK
+# define LPWORK 1
+#else
+# define LPWORK HPWORK
+#endif
/****************************************************************************
* Public Types
@@ -86,10 +155,6 @@ extern "C" {
#define EXTERN extern
#endif
-/* The task ID of the worker thread */
-
-EXTERN pid_t g_worker;
-
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@@ -109,6 +174,7 @@ EXTERN pid_t g_worker;
* and remove it from the work queue.
*
* Input parameters:
+ * qid - The work queue ID
* work - The work structure to queue
* worker - The worker callback to be invoked. The callback will invoked
* on the worker thread of execution.
@@ -122,7 +188,8 @@ EXTERN pid_t g_worker;
*
****************************************************************************/
-EXTERN int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint32_t delay);
+EXTERN int work_queue(int qid, FAR struct work_s *work, worker_t worker,
+ FAR void *arg, uint32_t delay);
/****************************************************************************
* Name: work_cancel
@@ -133,6 +200,7 @@ EXTERN int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint3
* again.
*
* Input parameters:
+ * qid - The work queue ID
* work - The previously queue work structure to cancel
*
* Returned Value:
@@ -140,7 +208,7 @@ EXTERN int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint3
*
****************************************************************************/
-EXTERN int work_cancel(struct work_s *work);
+EXTERN int work_cancel(int qid, FAR struct work_s *work);
/****************************************************************************
* Name: work_signal
@@ -151,14 +219,14 @@ EXTERN int work_cancel(struct work_s *work);
* user to force an immediate re-assessment of pending work.
*
* Input parameters:
- * None
+ * qid - The work queue ID
*
* Returned Value:
* Zero on success, a negated errno on failure
*
****************************************************************************/
-#define work_signal() kill(g_worker, SIGWORK)
+EXTERN int work_signal(int qid);
/****************************************************************************
* Name: work_available
diff --git a/nuttx/sched/Kconfig b/nuttx/sched/Kconfig
index 37ce0ebd61..58d6ead703 100644
--- a/nuttx/sched/Kconfig
+++ b/nuttx/sched/Kconfig
@@ -166,6 +166,39 @@ config SIG_SIGWORK
The signal number that will be used to wake-up the worker thread.
Default: 4
+config SCHED_LPWORK
+ bool "Enable a lower priority worker thread"
+ default n
+ depends on SCHED_WORKQUEUE
+ ---help---
+ If SCHED_WORKQUEUE is defined, then a single work queue is created by
+ default. If SCHED_LPWORK is also defined then an additional, lower-
+ priority work queue will also be created. This lower priority work
+ queue is better suited for more extended processing (such as file system
+ clean-up operations)
+
+config SCHED_LPWORKPRIORITY
+ int "Lower priority worker thread priority"
+ default 192
+ depends on SCHED_LPWORK
+ ---help---
+ The execution priority of the lopwer priority worker thread. Default: 192
+
+config SCHED_LPWORKPERIOD
+ int "Lower priority worker thread period"
+ default 50000
+ depends on SCHED_LPWORK
+ ---help---
+ How often the lower priority worker thread checks for work in units
+ of microseconds. Default: 50*1000 (50 MS).
+
+config SCHED_LPWORKSTACKSIZE
+ int "Lower priority worker thread stack size"
+ default 2048
+ depends on SCHED_LPWORK
+ ---help---
+ The stack size allocated for the lower priority worker thread. Default: 2K.
+
config SCHED_WAITPID
bool "Enable waitpid() API"
default n
diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile
index dfdc6f68b6..1e0a55aeaf 100644
--- a/nuttx/sched/Makefile
+++ b/nuttx/sched/Makefile
@@ -141,7 +141,7 @@ TIMER_SRCS = timer_initialize.c timer_create.c timer_delete.c timer_getoverrun.c
endif
ifeq ($(CONFIG_SCHED_WORKQUEUE),y)
-WORK_SRCS = work_thread.c work_queue.c work_cancel.c
+WORK_SRCS = work_thread.c work_queue.c work_cancel.c work_signal.c
endif
ifeq ($(CONFIG_PAGING),y)
diff --git a/nuttx/sched/os_bringup.c b/nuttx/sched/os_bringup.c
index d6d9431377..ec61528914 100644
--- a/nuttx/sched/os_bringup.c
+++ b/nuttx/sched/os_bringup.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/os_bringup.c
*
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* With extensions by:
@@ -47,6 +47,7 @@
#include <debug.h>
#include <nuttx/init.h>
+#include <nuttx/wqueue.h>
#include "os_internal.h"
#ifdef CONFIG_PAGING
@@ -149,10 +150,23 @@ int os_bringup(void)
#ifdef CONFIG_SCHED_WORKQUEUE
svdbg("Starting worker thread\n");
- g_worker = KERNEL_THREAD("work", CONFIG_SCHED_WORKPRIORITY,
- CONFIG_SCHED_WORKSTACKSIZE,
- (main_t)work_thread, (const char **)NULL);
- ASSERT(g_worker != ERROR);
+ g_work[HPWORK].pid = KERNEL_THREAD("work0", CONFIG_SCHED_WORKPRIORITY,
+ CONFIG_SCHED_WORKSTACKSIZE,
+ (main_t)work_hpthread, (const char **)NULL);
+ ASSERT(g_work[HPWORK].pid != ERROR);
+
+ /* Start a lower priority worker thread for other, non-critical continuation
+ * tasks
+ */
+
+#ifdef CONFIG_SCHED_LPWORK
+ svdbg("Starting worker thread\n");
+
+ g_work[LPWORK].pid = KERNEL_THREAD("work1", CONFIG_SCHED_LPWORKPRIORITY,
+ CONFIG_SCHED_LPWORKSTACKSIZE,
+ (main_t)work_lpthread, (const char **)NULL);
+ ASSERT(g_work[LPWORK].pid != ERROR);
+#endif
#endif
/* Once the operating system has been initialized, the system must be
diff --git a/nuttx/sched/sched_free.c b/nuttx/sched/sched_free.c
index 4df77b109a..e5e0bdacf0 100644
--- a/nuttx/sched/sched_free.c
+++ b/nuttx/sched/sched_free.c
@@ -1,7 +1,7 @@
/************************************************************************
* sched/sched_free.c
*
- * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009, 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -99,7 +99,7 @@ void sched_free(FAR void *address)
/* Signal the worker thread that is has some clean up to do */
#ifdef CONFIG_SCHED_WORKQUEUE
- work_signal();
+ work_signal(LPWORK);
#endif
irqrestore(saved_state);
}
diff --git a/nuttx/sched/work_cancel.c b/nuttx/sched/work_cancel.c
index 30b650826b..55df86f44f 100644
--- a/nuttx/sched/work_cancel.c
+++ b/nuttx/sched/work_cancel.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/work_cancel.c
*
- * Copyright (C) 2009-2010 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2009-2010, 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -74,6 +74,7 @@
/****************************************************************************
* Public Functions
****************************************************************************/
+
/****************************************************************************
* Name: work_cancel
*
@@ -83,6 +84,7 @@
* again.
*
* Input parameters:
+ * qid - The work queue ID
* work - The previously queue work structure to cancel
*
* Returned Value:
@@ -90,11 +92,12 @@
*
****************************************************************************/
-int work_cancel(struct work_s *work)
+int work_cancel(int qid, FAR struct work_s *work)
{
+ FAR struct wqueue_s *wqueue = &g_work[qid];
irqstate_t flags;
- DEBUGASSERT(work != NULL);
+ DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS);
/* Cancelling the work is simply a matter of removing the work structure
* from the work queue. This must be done with interrupts disabled because
@@ -106,18 +109,19 @@ int work_cancel(struct work_s *work)
{
/* A little test of the integrity of the work queue */
- DEBUGASSERT(work->dq.flink ||(FAR dq_entry_t *)work == g_work.tail);
- DEBUGASSERT(work->dq.blink ||(FAR dq_entry_t *)work == g_work.head);
+ DEBUGASSERT(work->dq.flink ||(FAR dq_entry_t *)work == wqueue->q.tail);
+ DEBUGASSERT(work->dq.blink ||(FAR dq_entry_t *)work == wqueue->q.head);
/* Remove the entry from the work queue and make sure that it is
* mark as availalbe (i.e., the worker field is nullified).
*/
- dq_rem((FAR dq_entry_t *)work, &g_work);
+ dq_rem((FAR dq_entry_t *)work, &wqueue->q);
work->worker = NULL;
}
irqrestore(flags);
return OK;
}
+
#endif /* CONFIG_SCHED_WORKQUEUE */
diff --git a/nuttx/sched/work_internal.h b/nuttx/sched/work_internal.h
index 69b7bf5470..7f6c1a9373 100644
--- a/nuttx/sched/work_internal.h
+++ b/nuttx/sched/work_internal.h
@@ -51,51 +51,49 @@
/* Configuration ************************************************************/
-#ifndef CONFIG_SCHED_WORKPRIORITY
-# define CONFIG_SCHED_WORKPRIORITY 50
-#endif
-
-#ifndef CONFIG_SCHED_WORKPERIOD
-# define CONFIG_SCHED_WORKPERIOD (50*1000) /* 50 milliseconds */
-#endif
-
-#ifndef CONFIG_SCHED_WORKSTACKSIZE
-# define CONFIG_SCHED_WORKSTACKSIZE CONFIG_IDLETHREAD_STACKSIZE
-#endif
-
#ifdef CONFIG_DISABLE_SIGNALS
# warning "Worker thread support requires signals"
#endif
+#ifdef CONFIG_SCHED_LPWORK
+# define NWORKERS 2
+#else
+# define NWORKERS 1
+#endif
+
/****************************************************************************
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
+/* This structure defines the state on one work queue */
+
+struct wqueue_s
+{
+ pid_t pid; /* The task ID of the worker thread */
+ struct dq_queue_s q; /* The queue of pending work */
+};
+
/****************************************************************************
* Public Data
****************************************************************************/
-/* The queue of pending work */
-
-extern struct dq_queue_s g_work;
+/* The state of each work queue */
-/* The task ID of the worker thread */
-
-extern pid_t g_worker;
+extern struct wqueue_s g_work[NWORKERS];
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
- * Name: work_thread
+ * Name: work_hpthread and work_lpthread
*
* Description:
- * This is the main worker thread that performs actions placed on the work
- * queue. It also performs periodic garbage collection (that is performed
- * by the idle thread if CONFIG_SCHED_WORKQUEUE is not defined).
+ * These are the main worker threads that performs actions placed on the
+ * work lists. One thread also performs periodic garbage collection (that
+ * is performed by the idle thread if CONFIG_SCHED_WORKQUEUE is not defined).
*
* Input parameters:
* argc, argv (not used)
@@ -105,7 +103,11 @@ extern pid_t g_worker;
*
****************************************************************************/
-int work_thread(int argc, char *argv[]);
+int work_hpthread(int argc, char *argv[]);
+
+#ifdef CONFIG_SCHED_LPWORK
+int work_lpthread(int argc, char *argv[]);
+#endif
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_SCHED_WORKQUEUE */
diff --git a/nuttx/sched/work_queue.c b/nuttx/sched/work_queue.c
index beeac168dd..075f08a4d7 100644
--- a/nuttx/sched/work_queue.c
+++ b/nuttx/sched/work_queue.c
@@ -76,6 +76,7 @@
/****************************************************************************
* Public Functions
****************************************************************************/
+
/****************************************************************************
* Name: work_queue
*
@@ -91,6 +92,7 @@
* and remove it from the work queue.
*
* Input parameters:
+ * qid - The work queue ID (index)
* work - The work structure to queue
* worker - The worker callback to be invoked. The callback will invoked
* on the worker thread of execution.
@@ -104,11 +106,13 @@
*
****************************************************************************/
-int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint32_t delay)
+int work_queue(int qid, FAR struct work_s *work, worker_t worker,
+ FAR void *arg, uint32_t delay)
{
+ FAR struct wqueue_s *wqueue = &g_work[qid];
irqstate_t flags;
- DEBUGASSERT(work != NULL);
+ DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS);
/* First, initialize the work structure */
@@ -123,8 +127,10 @@ int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint32_t del
flags = irqsave();
work->qtime = clock_systimer(); /* Time work queued */
- dq_addlast((FAR dq_entry_t *)work, &g_work);
- work_signal(); /* Wake up the worker thread */
+
+ dq_addlast((FAR dq_entry_t *)work, &wqueue->q);
+ kill(wqueue->pid, SIGWORK); /* Wake up the worker thread */
+
irqrestore(flags);
return OK;
}
diff --git a/nuttx/sched/work_signal.c b/nuttx/sched/work_signal.c
new file mode 100644
index 0000000000..6e6838c695
--- /dev/null
+++ b/nuttx/sched/work_signal.c
@@ -0,0 +1,96 @@
+/****************************************************************************
+ * sched/work_signal.c
+ *
+ * Copyright (C) 2009-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <signal.h>
+#include <assert.h>
+
+#include <nuttx/wqueue.h>
+
+#include "work_internal.h"
+
+#ifdef CONFIG_SCHED_WORKQUEUE
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: work_signal
+ *
+ * Description:
+ * Signal the worker thread to process the work queue now. This function
+ * is used internally by the work logic but could also be used by the
+ * user to force an immediate re-assessment of pending work.
+ *
+ * Input parameters:
+ * qid - The work queue ID
+ *
+ * Returned Value:
+ * Zero on success, a negated errno on failure
+ *
+ ****************************************************************************/
+
+int work_signal(int qid)
+{
+ DEBUGASSERT((unsigned)qid < NWORKERS);
+ return kill(g_work[qid].pid, SIGWORK);
+}
+
+#endif /* CONFIG_SCHED_WORKQUEUE */
diff --git a/nuttx/sched/work_thread.c b/nuttx/sched/work_thread.c
index fe14ae5e58..abd86f7710 100644
--- a/nuttx/sched/work_thread.c
+++ b/nuttx/sched/work_thread.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/work_thread.c
*
- * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2009-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -67,15 +67,9 @@
* Public Variables
****************************************************************************/
-/* The queue of pending work */
+/* The state of each work queue */
-struct dq_queue_s g_work;
-
-/* The task ID of the worker thread */
-
-#ifdef CONFIG_SCHED_WORKQUEUE
-pid_t g_worker;
-#endif
+struct wqueue_s g_work[NWORKERS];
/****************************************************************************
* Private Variables
@@ -86,130 +80,177 @@ pid_t g_worker;
****************************************************************************/
/****************************************************************************
- * Public Functions
- ****************************************************************************/
-/****************************************************************************
- * Name: work_thread
+ * Name: work_process
*
* Description:
- * This is the main worker thread that performs actions placed on the work
- * list. It also performs periodic garbage collection (that is performed
- * by the idle thread if CONFIG_SCHED_WORKQUEUE is not defined).
+ * This is the logic that performs actions placed on any work list.
*
* Input parameters:
- * argc, argv (not used)
+ * wqueue - Describes the work queue to be processed
*
* Returned Value:
- * Does not return
+ * None
*
****************************************************************************/
-int work_thread(int argc, char *argv[])
+static void work_process(FAR struct wqueue_s *wqueue)
{
volatile FAR struct work_s *work;
worker_t worker;
+ irqstate_t flags;
FAR void *arg;
uint32_t elapsed;
uint32_t remaining;
uint32_t next;
- int usec;
- irqstate_t flags;
- /* Loop forever */
+ /* Then process queued work. We need to keep interrupts disabled while
+ * we process items in the work list.
+ */
- usec = CONFIG_SCHED_WORKPERIOD;
+ next = CONFIG_SCHED_WORKPERIOD / USEC_PER_TICK;
flags = irqsave();
- for (;;)
+ work = (FAR struct work_s *)wqueue->q.head;
+ while (work)
{
- /* Wait awhile to check the work list. We will wait here until either
- * the time elapses or until we are awakened by a signal.
+ /* Is this work ready? It is ready if there is no delay or if
+ * the delay has elapsed. qtime is the time that the work was added
+ * to the work queue. It will always be greater than or equal to
+ * zero. Therefore a delay of zero will always execute immediately.
*/
- usleep(usec);
- irqrestore(flags);
+ elapsed = clock_systimer() - work->qtime;
+ if (elapsed >= work->delay)
+ {
+ /* Remove the ready-to-execute work from the list */
- /* First, perform garbage collection. This cleans-up memory de-allocations
- * that were queued because they could not be freed in that execution
- * context (for example, if the memory was freed from an interrupt handler).
- * NOTE: If the work thread is disabled, this clean-up is performed by
- * the IDLE thread (at a very, very lower priority).
- */
+ (void)dq_rem((struct dq_entry_s *)work, &wqueue->q);
- sched_garbagecollection();
+ /* Extract the work description from the entry (in case the work
+ * instance by the re-used after it has been de-queued).
+ */
- /* Then process queued work. We need to keep interrupts disabled while
- * we process items in the work list.
- */
+ worker = work->worker;
+ arg = work->arg;
+
+ /* Mark the work as no longer being queued */
+
+ work->worker = NULL;
+
+ /* Do the work. Re-enable interrupts while the work is being
+ * performed... we don't have any idea how long that will take!
+ */
+
+ irqrestore(flags);
+ worker(arg);
- next = CONFIG_SCHED_WORKPERIOD / USEC_PER_TICK;
- flags = irqsave();
- work = (FAR struct work_s *)g_work.head;
- while (work)
+ /* Now, unfortunately, since we re-enabled interrupts we don't
+ * know the state of the work list and we will have to start
+ * back at the head of the list.
+ */
+
+ flags = irqsave();
+ work = (FAR struct work_s *)wqueue->q.head;
+ }
+ else
{
- /* Is this work ready? It is ready if there is no delay or if
- * the delay has elapsed. qtime is the time that the work was added
- * to the work queue. It will always be greater than or equal to
- * zero. Therefore a delay of zero will always execute immediately.
+ /* This one is not ready.. will it be ready before the next
+ * scheduled wakeup interval?
*/
- elapsed = clock_systimer() - work->qtime;
- if (elapsed >= work->delay)
+ remaining = elapsed - work->delay;
+ if (remaining < next)
{
- /* Remove the ready-to-execute work from the list */
+ /* Yes.. Then schedule to wake up when the work is ready */
- (void)dq_rem((struct dq_entry_s *)work, &g_work);
+ next = remaining;
+ }
+
+ /* Then try the next in the list. */
- /* Extract the work description from the entry (in case the work
- * instance by the re-used after it has been de-queued).
- */
+ work = (FAR struct work_s *)work->dq.flink;
+ }
+ }
- worker = work->worker;
- arg = work->arg;
+ /* Wait awhile to check the work list. We will wait here until either
+ * the time elapses or until we are awakened by a signal.
+ */
- /* Mark the work as no longer being queued */
+ usleep(next * USEC_PER_TICK);
+ irqrestore(flags);
+}
- work->worker = NULL;
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: work_hpthread and work_lpthread
+ *
+ * Description:
+ * These are the main worker threads that performs actions placed on the
+ * work lists. One thread also performs periodic garbage collection (that
+ * is performed by the idle thread if CONFIG_SCHED_WORKQUEUE is not defined).
+ *
+ * Input parameters:
+ * argc, argv (not used)
+ *
+ * Returned Value:
+ * Does not return
+ *
+ ****************************************************************************/
- /* Do the work. Re-enable interrupts while the work is being
- * performed... we don't have any idea how long that will take!
- */
+int work_hpthread(int argc, char *argv[])
+{
+ /* Loop forever */
- irqrestore(flags);
- worker(arg);
+ for (;;)
+ {
+ /* First, perform garbage collection. This cleans-up memory de-allocations
+ * that were queued because they could not be freed in that execution
+ * context (for example, if the memory was freed from an interrupt handler).
+ * NOTE: If the work thread is disabled, this clean-up is performed by
+ * the IDLE thread (at a very, very lower priority).
+ */
- /* Now, unfortunately, since we re-enabled interrupts we don't
- * know the state of the work list and we will have to start
- * back at the head of the list.
- */
+#ifdef CONFIG_SCHED_LPWORK
+ sched_garbagecollection();
+#endif
- flags = irqsave();
- work = (FAR struct work_s *)g_work.head;
- }
- else
- {
- /* This one is not ready.. will it be ready before the next
- * scheduled wakeup interval?
- */
+ /* Then process queued work. We need to keep interrupts disabled while
+ * we process items in the work list.
+ */
+
+ work_process(&g_work[HPWORK]);
+ }
- remaining = elapsed - work->delay;
- if (remaining < next)
- {
- /* Yes.. Then schedule to wake up when the work is ready */
+ return OK; /* To keep some compilers happy */
+}
- next = remaining;
- }
-
- /* Then try the next in the list. */
+#ifdef CONFIG_SCHED_LPWORK
+int work_lpthread(int argc, char *argv[])
+{
+ /* Loop forever */
- work = (FAR struct work_s *)work->dq.flink;
- }
- }
+ for (;;)
+ {
+ /* First, perform garbage collection. This cleans-up memory de-allocations
+ * that were queued because they could not be freed in that execution
+ * context (for example, if the memory was freed from an interrupt handler).
+ * NOTE: If the work thread is disabled, this clean-up is performed by
+ * the IDLE thread (at a very, very lower priority).
+ */
- /* Now calculate the microsecond delay we should wait */
+ sched_garbagecollection();
- usec = next * USEC_PER_TICK;
+ /* Then process queued work. We need to keep interrupts disabled while
+ * we process items in the work list.
+ */
+
+ work_process(&g_work[LPWORK]);
}
return OK; /* To keep some compilers happy */
}
+
+#endif /* CONFIG_SCHED_LPWORK */
+
#endif /* CONFIG_SCHED_WORKQUEUE */
diff --git a/nuttx/tools/configure.sh b/nuttx/tools/configure.sh
index 0d6c412a5c..c0df7035f0 100755
--- a/nuttx/tools/configure.sh
+++ b/nuttx/tools/configure.sh
@@ -101,17 +101,17 @@ if [ ! -d "${configpath}" ]; then
fi
if [ ! -r "${configpath}/Make.defs" ]; then
- echo "File ${configpath}/Make.defs does not exist"
+ echo "File \"${configpath}/Make.defs\" does not exist"
exit 4
fi
if [ ! -r "${configpath}/setenv.sh" ]; then
- echo "File ${configpath}/setenv.sh does not exist"
+ echo "File \"${configpath}/setenv.sh\" does not exist"
exit 5
fi
if [ ! -r "${configpath}/defconfig" ]; then
- echo "File ${configpath}/defconfig does not exist"
+ echo "File \"${configpath}/defconfig\" does not exist"
exit 6
fi
@@ -127,7 +127,7 @@ if [ -z "${appdir}" ]; then
appdir=`grep CONFIG_APPS_DIR= "${configpath}/defconfig" | cut -d'=' -f2`
fi
-# Check for the apps/ dir in the usual place if appdir was not provided
+# Check for the apps/ directory in the usual place if appdir was not provided
if [ -z "${appdir}" ]; then
@@ -152,7 +152,15 @@ if [ -z "${appdir}" ]; then
fi
fi
-# Okay... setup the configuration
+# If appsdir was provided (or discovered) then make sure that the apps/
+# directory exists
+
+if [ ! -z "${appdir}" -a ! -d "${TOPDIR}/${appdir}" ]; then
+ echo "Directory \"${TOPDIR}/${appdir}\" does not exist"
+ exit 7
+fi
+
+# Okay... Everything looks good. Setup the configuration
install -C "${configpath}/Make.defs" "${TOPDIR}/." || \
{ echo "Failed to copy ${configpath}/Make.defs" ; exit 7 ; }