summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/ChangeLog5
-rw-r--r--nuttx/Documentation/NuttX.html4
-rw-r--r--nuttx/drivers/rwbuffer.c4
-rw-r--r--nuttx/include/nuttx/rwbuffer.h2
-rwxr-xr-xnuttx/include/nuttx/wqueue.h17
-rw-r--r--nuttx/include/signal.h37
-rw-r--r--nuttx/sched/Makefile4
-rw-r--r--nuttx/sched/os_internal.h1
-rw-r--r--nuttx/sched/os_start.c51
-rw-r--r--nuttx/sched/sched_free.c64
-rwxr-xr-xnuttx/sched/sched_garbage.c127
-rwxr-xr-xnuttx/sched/work_internal.h32
-rwxr-xr-xnuttx/sched/work_queue.c1
-rwxr-xr-xnuttx/sched/work_thread.c166
14 files changed, 455 insertions, 60 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 85d2953a6..6d00bdb72 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -951,4 +951,9 @@
* arch/arm/src/stm32/stm32_gpio.c - Add support for configure an input GPIO
to generate an EXTI interrupt.
* config/stm3210e-eval/src/up_buttons.c - Add support for on-board buttons.
+ * include/nuttx/rwbuffer.h -- Add generic support for read-ahead buffering
+ and write buffering that can be used in any block driver.
+ * include/nuttx/wqueue.h -- Added a generic worker thread that can used to
+ defer processing from an interrupt to a task.
+
diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index efa24c38e..f92069e53 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -1599,6 +1599,10 @@ nuttx-0.4.14 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
* arch/arm/src/stm32/stm32_gpio.c - Add support for configure an input GPIO
to generate an EXTI interrupt.
* config/stm3210e-eval/src/up_buttons.c - Add support for on-board buttons.
+ * include/nuttx/rwbuffer.h -- Add generic support for read-ahead buffering
+ and write buffering that can be used in any block driver.
+ * include/nuttx/wqueue.h -- Added a generic worker thread that can used to
+ defer processing from an interrupt to a task.
pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
diff --git a/nuttx/drivers/rwbuffer.c b/nuttx/drivers/rwbuffer.c
index 440e8da83..eb696ae6a 100644
--- a/nuttx/drivers/rwbuffer.c
+++ b/nuttx/drivers/rwbuffer.c
@@ -59,6 +59,10 @@
/* Configuration ************************************************************/
+#ifndef CONFIG_SCHED_WORKQUEUE
+# error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
#ifndef CONFIG_FS_WRDELAY
# define CONFIG_FS_WRDELAY 350
#endif
diff --git a/nuttx/include/nuttx/rwbuffer.h b/nuttx/include/nuttx/rwbuffer.h
index 4e9d24d45..2db330a19 100644
--- a/nuttx/include/nuttx/rwbuffer.h
+++ b/nuttx/include/nuttx/rwbuffer.h
@@ -53,7 +53,7 @@
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD)
/**********************************************************************
- * Definitions
+ * Pre-processor Definitions
**********************************************************************/
/**********************************************************************
diff --git a/nuttx/include/nuttx/wqueue.h b/nuttx/include/nuttx/wqueue.h
index 5b6a3651e..f1ebc3ec0 100755
--- a/nuttx/include/nuttx/wqueue.h
+++ b/nuttx/include/nuttx/wqueue.h
@@ -42,6 +42,7 @@
#include <nuttx/config.h>
#include <sys/types.h>
+#include <signal.h>
#include <queue.h>
#ifdef CONFIG_SCHED_WORKQUEUE
@@ -132,6 +133,22 @@ EXTERN int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint3
EXTERN int work_cancel(struct work_s *work);
+/****************************************************************************
+ * Name: work_signal
+ *
+ * Description:
+ * Signal the worker thread to process the work queue now.
+ *
+ * Input parameters:
+ * None
+ *
+ * Returned Value:
+ * Zero on success, a negated errno on failure
+ *
+ ****************************************************************************/
+
+#define work_signal() kill(g_worker, SIGWORK)
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/nuttx/include/signal.h b/nuttx/include/signal.h
index 96f90be12..9357c4d7d 100644
--- a/nuttx/include/signal.h
+++ b/nuttx/include/signal.h
@@ -67,16 +67,45 @@
#define SIGRTMIN 0 /* First real time signal */
#define SIGRTMAX 31 /* Last real time signal */
-/* A few of the real time signals are used within the OS. The reset are all
- * user signals:
+/* A few of the real time signals are used within the OS. They have
+ * default values that can be overridden from the configuration file. The
+ * rest are all user signals:
*/
+#ifndef CONFIG_SIG_SIGUSR1
#define SIGUSR1 0 /* User signal 1 */
+#else
+#define SIGUSR1 CONFIG_SIG_SIGUSR1
+#endif
+
+#ifndef CONFIG_SIG_SIGUSR2
#define SIGUSR2 1 /* User signal 2 */
+#else
+#define SIGUSR2 CONFIG_SIG_SIGUSR2
+#endif
+
+#ifndef CONFIG_SIG_SIGALARM
#define SIGALRM 2 /* Default signal used with POSIX timers (used only */
/* no other signal is provided) */
-#define SIGCONDTIMEDOUT 3 /* Used in the implementation of */
- /* pthread_cond_timedwait */
+#else
+#define SIGALRM CONFIG_SIG_SIGALARM
+#endif
+
+#ifndef CONFIG_DISABLE_PTHREAD
+#ifndef CONFIG_SIG_SIGCONDTIMEDOUT
+#define SIGCONDTIMEDOUT 3 /* Used in the implementation of pthread_cond_timedwait */
+#else
+#define SIGCONDTIMEDOUT CONFIG_SIG_SIGCONDTIMEDOUT
+#endif
+#endif
+
+#ifdef CONFIG_SCHED_WORKQUEUE
+#ifndef CONFIG_SIG_SIGWORK
+#define SIGWORK 4 /* Used to wake up the work queue */
+#else
+#define SIGWORK CONFIG_SIG_SIGWORK
+#endif
+#endif
/* sigprocmask() "how" definitions. Only one of the following can be specified: */
diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile
index 3a2512662..ec9923e1c 100644
--- a/nuttx/sched/Makefile
+++ b/nuttx/sched/Makefile
@@ -38,7 +38,7 @@
ASRCS =
AOBJS = $(ASRCS:.S=$(OBJEXT))
-MISC_SRCS = os_start.c get_errno_ptr.c \
+MISC_SRCS = os_start.c get_errno_ptr.c sched_garbage.c \
sched_setupstreams.c sched_getfiles.c sched_getsockets.c sched_getstreams.c \
sched_setupidlefiles.c sched_setuptaskfiles.c sched_setuppthreadfiles.c \
sched_releasefiles.c
@@ -136,7 +136,7 @@ TIMER_SRCS = timer_initialize.c timer_create.c timer_delete.c timer_getoverrun.c
endif
ifeq ($(CONFIG_SCHED_WORKQUEUE),y)
-WORK_SRCS = work_queue.c work_cancel.c
+WORK_SRCS = work_thread.c work_queue.c work_cancel.c
endif
IRQ_SRCS = irq_initialize.c irq_attach.c irq_dispatch.c irq_unexpectedisr.c
diff --git a/nuttx/sched/os_internal.h b/nuttx/sched/os_internal.h
index b07818345..84a2997c7 100644
--- a/nuttx/sched/os_internal.h
+++ b/nuttx/sched/os_internal.h
@@ -273,5 +273,6 @@ extern int sched_releasefiles(FAR _TCB *tcb);
#endif
extern int sched_releasetcb(FAR _TCB *tcb);
+extern void sched_garbagecollection(void);
#endif /* __OS_INTERNAL_H */
diff --git a/nuttx/sched/os_start.c b/nuttx/sched/os_start.c
index 8e036a9f9..41fc735e3 100644
--- a/nuttx/sched/os_start.c
+++ b/nuttx/sched/os_start.c
@@ -61,6 +61,9 @@
#include "clock_internal.h"
#include "timer_internal.h"
#include "irq_internal.h"
+#ifdef CONFIG_SCHED_WORKQUEUE
+# include "work_internal.h"
+#endif
/****************************************************************************
* Definitions
@@ -156,6 +159,12 @@ volatile pid_t g_lastpid;
pidhash_t g_pidhash[CONFIG_MAX_TASKS];
+/* The task ID of the worker thread */
+
+#ifdef CONFIG_SCHED_WORKQUEUE
+pid_t g_worker;
+#endif
+
/* This is a table of task lists. This table is indexed by
* the task state enumeration type (tstate_t) and provides
* a pointer to the associated static task list (if there
@@ -423,6 +432,15 @@ void os_start(void)
(void)sched_setupidlefiles(&g_idletcb);
+ /* Start the worker thread that will perform misc garbage clean-up */
+
+#ifdef CONFIG_SCHED_WORKQUEUE
+ g_worker = task_create("work", CONFIG_SCHED_WORKPRIORITY,
+ CONFIG_SCHED_WORKSTACKSIZE,
+ (main_t)work_thread, (const char **)NULL);
+#endif
+ ASSERT(g_worker != ERROR);
+
/* Once the operating system has been initialized, the system must be
* started by spawning the user init thread of execution.
*/
@@ -443,33 +461,14 @@ void os_start(void)
sdbg("Beginning Idle Loop\n");
for (;;)
{
- /* Check if there is anything in the delayed deallocation list.
- * If there is deallocate it now. We must have exclusive access
- * to the memory manager to do this BUT the idle task cannot
- * wait on a semaphore. So we only do the cleanup now if we
- * can get the semaphore -- and this should be possible because
- * since we are running, no other task is!
+ /* Peform garbage collection (if it is not being done by the worker
+ * thread. This cleans-up memory de-allocations that was queued
+ * because it could not be freed in that execution context (for
+ * example, if the memory was freed from an interrupt handler).
*/
-
- if (mm_trysemaphore() == 0)
- {
- while (g_delayeddeallocations.head)
- {
- /* Remove the first delayed deallocation. */
-
- irqstate_t saved_state = irqsave();
- void *address = (void*)sq_remfirst((FAR sq_queue_t*)&g_delayeddeallocations);
- irqrestore(saved_state);
-
- /* Then deallocate it */
-
- if (address)
- {
- free(address);
- }
- }
- mm_givesemaphore();
- }
+#ifndef CONFIG_SCHED_WORKQEUE
+ sched_garbagecollection();
+#endif
/* Perform any processor-specific idle state operations */
diff --git a/nuttx/sched/sched_free.c b/nuttx/sched/sched_free.c
index 6078cc1b6..afa5e62c9 100644
--- a/nuttx/sched/sched_free.c
+++ b/nuttx/sched/sched_free.c
@@ -1,7 +1,7 @@
-/************************************************************
- * sched_free.c
+/************************************************************************
+ * sched/sched_free.c
*
- * Copyright (C) 2007 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +14,7 @@
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
- * 3. Neither the name Gregory Nutt nor the names of its contributors may be
+ * 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.
*
@@ -31,55 +31,59 @@
* 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 <sys/types.h>
-#include <nuttx/kmalloc.h>
+
#include <queue.h>
#include <assert.h>
+
+#include <nuttx/kmalloc.h>
#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
#include <nuttx/mm.h>
+
#include "os_internal.h"
-/************************************************************
+/************************************************************************
* Definitions
- ************************************************************/
+ ************************************************************************/
-/************************************************************
+/************************************************************************
* Private Type Declarations
- ************************************************************/
+ ************************************************************************/
-/************************************************************
+/************************************************************************
* Global Variables
- ************************************************************/
+ ************************************************************************/
-/************************************************************
+/************************************************************************
* Private Variables
- ************************************************************/
+ ************************************************************************/
-/************************************************************
+/************************************************************************
* Private Function Prototypes
- ************************************************************/
+ ************************************************************************/
-/************************************************************
+/************************************************************************
* Public Functions
- ************************************************************/
+ ************************************************************************/
-/************************************************************
+/************************************************************************
* Name: sched_free
*
* Description:
- * This function performs deallocations that
- * the operating system may need to make. This special
- * interface to free is used to handling corner cases
- * where the operating system may have to perform deallocations
- * from within an interrupt handler.
+ * This function performs deallocations that the operating system may
+ * need to make. This special interface to free is used to handling
+ * corner cases where the operating system may have to perform
+ * deallocations from within an interrupt handler.
*
- ************************************************************/
+ ************************************************************************/
void sched_free(FAR void *address)
{
@@ -95,6 +99,12 @@ void sched_free(FAR void *address)
irqstate_t saved_state = irqsave();
sq_addlast((FAR sq_entry_t*)address, (sq_queue_t*)&g_delayeddeallocations);
+
+ /* Signal the worker thread that is has some clean up to do */
+
+#ifdef CONFIG_SCHED_WORKQUEUE
+ work_signal();
+#endif
irqrestore(saved_state);
}
else
diff --git a/nuttx/sched/sched_garbage.c b/nuttx/sched/sched_garbage.c
new file mode 100755
index 000000000..6dc1a5c88
--- /dev/null
+++ b/nuttx/sched/sched_garbage.c
@@ -0,0 +1,127 @@
+/****************************************************************************
+ * sched/work_garbage.c
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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 <sys/types.h>
+
+#include <stdlib.h>
+
+#include <nuttx/mm.h>
+
+#include "os_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: sched_garbagecollection
+ *
+ * Description:
+ * Clean-up memory de-allocations that we queued because they could not
+ * be freed in that execution context (for example, if the memory was freed
+ * from an interrupt handler).
+ *
+ * This logic may be called from the worker thread (see work_thread.c).
+ * If, however, CONFIG_SCHED_WORKQUEUE is not defined, then this logic will
+ * be called from the IDLE thread. It is less optimal for the garbage
+ * collection to be called from the IDLE thread because it runs at a very
+ * low priority and could cause false memory out conditions.
+ *
+ * Input parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void sched_garbagecollection(void)
+{
+ /* Check if there is anything in the delayed deallocation list. If there
+ * is deallocate it now. We must have exclusive access to the memory manager
+ * to do this BUT the idle task cannot wait on a semaphore. So we only do
+ * the cleanup now if we can get the semaphore -- and this should be possible
+ * because if the IDLE thread is running, no other task is!
+ */
+
+#ifdef CONFIG_SCHED_WORKQUEUE
+ mm_takesemaphore();
+#else
+ if (mm_trysemaphore() == 0)
+#endif
+ {
+ while (g_delayeddeallocations.head)
+ {
+ /* Remove the first delayed deallocation. */
+
+ irqstate_t saved_state = irqsave();
+ void *address = (void*)sq_remfirst((FAR sq_queue_t*)&g_delayeddeallocations);
+ irqrestore(saved_state);
+
+ /* Then deallocate it */
+
+ if (address)
+ {
+ free(address);
+ }
+ }
+ mm_givesemaphore();
+ }
+}
+
diff --git a/nuttx/sched/work_internal.h b/nuttx/sched/work_internal.h
index e86ee0ac2..93ad57271 100755
--- a/nuttx/sched/work_internal.h
+++ b/nuttx/sched/work_internal.h
@@ -50,6 +50,20 @@
* Pre-Processor Definitions
****************************************************************************/
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SCHED_WORKPRIORITY
+# define CONFIG_SCHED_WORKPRIORITY 50
+#endif
+
+#ifndef CONFIG_SCHED_WORKPERIODUS
+# define CONFIG_SCHED_WORKPERIOD (50*1000) /* 50 milliseconds */
+#endif
+
+#ifndef CONFIG_SCHED_WORKSTACKSIZE
+# define CONFIG_SCHED_WORKSTACKSIZE CONFIG_IDLETHREAD_STACKSIZE
+#endif
+
/****************************************************************************
* Public Types
****************************************************************************/
@@ -68,6 +82,24 @@ extern struct dq_queue_s g_work;
* Public Function Prototypes
****************************************************************************/
+/****************************************************************************
+ * Name: work_thread
+ *
+ * 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).
+ *
+ * Input parameters:
+ * argc, argv (not used)
+ *
+ * Returned Value:
+ * Does not return
+ *
+ ****************************************************************************/
+
+extern int work_thread(int argc, char *argv[]);
+
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_SCHED_WORKQUEUE */
#endif /* __SCHED_WORK_INTERNAL_H */
diff --git a/nuttx/sched/work_queue.c b/nuttx/sched/work_queue.c
index 9e8c44e52..46afdc1d8 100755
--- a/nuttx/sched/work_queue.c
+++ b/nuttx/sched/work_queue.c
@@ -117,6 +117,7 @@ int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint32 delay
flags = irqsave();
work->qtime = g_system_timer; /* Time work queued */
dq_addlast((FAR dq_entry_t *)work, &g_work);
+ work_signal(); /* Wake up the worker thread */
irqrestore(flags);
return OK;
}
diff --git a/nuttx/sched/work_thread.c b/nuttx/sched/work_thread.c
new file mode 100755
index 000000000..4df29dd01
--- /dev/null
+++ b/nuttx/sched/work_thread.c
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * sched/work_thread.c
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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 <sys/types.h>
+
+#include <unistd.h>
+#include <queue.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/clock.h>
+
+#include "os_internal.h"
+#include "work_internal.h"
+
+#ifdef CONFIG_SCHED_WORKQUEUE
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+/* The queue of pending work */
+
+struct dq_queue_s g_work;
+
+/****************************************************************************
+ * Private Variables
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: work_thread
+ *
+ * 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).
+ *
+ * Input parameters:
+ * argc, argv (not used)
+ *
+ * Returned Value:
+ * Does not return
+ *
+ ****************************************************************************/
+
+int work_thread(int argc, char *argv[])
+{
+ volatile FAR struct work_s *work;
+ irqstate_t flags;
+
+ /* Loop forever */
+
+ for (;;)
+ {
+ /* Wait awhile to check the work list. We will wait here until either
+ * the time elapses or until we are awakened by a signal.
+ */
+
+ usleep(CONFIG_SCHED_WORKPERIOD);
+
+ /* First, clean-up any delayed memory deallocations */
+
+ sched_garbagecollection();
+
+ /* Then process queued work. We need to keep interrupts disabled while
+ * we process items in the work list.
+ */
+
+ flags = irqsave();
+ work = (FAR struct work_s *)g_work.head;
+ while (work)
+ {
+ /* Is this work ready? It is ready if there is no delay or if
+ * the delay has elapsed.
+ */
+
+ if (work->delay == 0 || g_system_timer - work->qtime > work->delay)
+ {
+ /* Remove the work at the head of the list. And re-enable
+ * interrupts while the work is performed.
+ */
+
+ (void)dq_remfirst(&g_work);
+
+ /* 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);
+ work->worker(work->arg);
+
+ /* Now, unfortunately, since we re-enabled interrupts we have
+ * to start back at the head of the list.
+ */
+
+ flags = irqsave();
+ work = (FAR struct work_s *)g_work.head;
+ }
+ else
+ {
+ /* This one is not ready, try the next in the list. */
+
+ work = (FAR struct work_s *)work->dq.flink;
+ }
+ }
+ irqrestore(flags);
+ }
+
+ return OK; /* To keep some compilers happy */
+}
+#endif /* CONFIG_SCHED_WORKQUEUE */