Add support for multiple work queues

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5081 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2012-09-04 00:54:09 +00:00
parent 6105b42d39
commit 561bea0899
28 changed files with 475 additions and 176 deletions

View File

@ -3250,3 +3250,5 @@
* sched/work_cancel.c: Fix a bad assertion (reported by Mike Smith) * sched/work_cancel.c: Fix a bad assertion (reported by Mike Smith)
* configs/stm3210e-eval/src/up_idle.c: Correct some power management * configs/stm3210e-eval/src/up_idle.c: Correct some power management
compilation errors (reported by Diego Sanchez). 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).

View File

@ -4068,6 +4068,20 @@ build
<code>CONFIG_SIG_SIGWORK</code>: The signal number that will be used to wake-up <code>CONFIG_SIG_SIGWORK</code>: The signal number that will be used to wake-up
the worker thread. Default: 4 the worker thread. Default: 4
</li> </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> <li>
<code>CONFIG_SCHED_WAITPID</code>: Enables the <a href="NuttxUserGuide.html#waitpid"><code>waitpid()</code><a> API <code>CONFIG_SCHED_WAITPID</code>: Enables the <a href="NuttxUserGuide.html#waitpid"><code>waitpid()</code><a> API
</li> </li>

View File

@ -1,8 +1,8 @@
/**************************************************************************** /****************************************************************************
* arch/arm/src/kinetis/kinetis_sdhc.c * arch/arm/src/kinetis/kinetis_sdhc.c
* *
* Copyright (C) 2011 Gregory Nutt. All rights reserved. * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr> * 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
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -2733,7 +2733,7 @@ static void kinetis_callback(void *arg)
/* Yes.. queue it */ /* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); 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 else
{ {

View File

@ -1,8 +1,8 @@
/**************************************************************************** /****************************************************************************
* arch/arm/src/sam3u/sam3u_sdio.c * arch/arm/src/sam3u/sam3u_sdio.c
* *
* Copyright (C) 2010 Gregory Nutt. All rights reserved. * Copyright (C) 2010, 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr> * 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
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -2343,7 +2343,7 @@ static void sam3u_callback(void *arg)
/* Yes.. queue it */ /* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); 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 else
{ {

View File

@ -2660,7 +2660,7 @@ static void stm32_callback(void *arg)
/* Yes.. queue it */ /* Yes.. queue it */
fvdbg("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); 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 else
{ {

View File

@ -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 if memory reclamation is of high priority). If CONFIG_SCHED_WORKQUEUE
is enabled, then the following options can also be used: is enabled, then the following options can also be used:
CONFIG_SCHED_WORKPRIORITY - The execution priority of the worker 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 CONFIG_SCHED_WORKPERIOD - How often the worker thread checks for
work in units of microseconds. Default: 50*1000 (50 MS). work in units of microseconds. Default: 50*1000 (50 MS).
CONFIG_SCHED_WORKSTACKSIZE - The stack size allocated for the worker CONFIG_SCHED_WORKSTACKSIZE - The stack size allocated for the worker
thread. Default: CONFIG_IDLETHREAD_STACKSIZE. thread. Default: CONFIG_IDLETHREAD_STACKSIZE.
CONFIG_SIG_SIGWORK - The signal number that will be used to wake-up CONFIG_SIG_SIGWORK - The signal number that will be used to wake-up
the worker thread. Default: 4 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_WAITPID - Enables the waitpid() API
CONFIG_SCHED_ATEXIT - Enables the atexit() API CONFIG_SCHED_ATEXIT - Enables the atexit() API
CONFIG_SCHED_ATEXIT_MAX - By default if CONFIG_SCHED_ATEXIT is CONFIG_SCHED_ATEXIT_MAX - By default if CONFIG_SCHED_ATEXIT is

View File

@ -972,7 +972,7 @@ static void tc_worker(FAR void *arg)
/* Set up the next sample event */ /* 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); ASSERT(ret == 0);
} }
@ -1420,7 +1420,7 @@ int arch_tcinitialize(int minor)
*/ */
priv->state = TC_READY; 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) if (ret != 0)
{ {
idbg("Failed to queue work: %d\n", ret); idbg("Failed to queue work: %d\n", ret);

View File

@ -521,7 +521,7 @@ static int ads7843e_schedule(FAR struct ads7843e_dev_s *priv)
*/ */
DEBUGASSERT(priv->work.worker == NULL); 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) if (ret != 0)
{ {
illdbg("Failed to queue work: %d\n", ret); illdbg("Failed to queue work: %d\n", ret);
@ -1179,7 +1179,7 @@ int ads7843e_register(FAR struct spi_dev_s *dev,
* availability conditions. * availability conditions.
*/ */
ret = work_queue(&priv->work, ads7843e_worker, priv, 0); ret = work_queue(HPWORK, &priv->work, ads7843e_worker, priv, 0);
if (ret != 0) if (ret != 0)
{ {
idbg("Failed to queue work: %d\n", ret); idbg("Failed to queue work: %d\n", ret);

View File

@ -195,7 +195,7 @@ static int stmpe811_interrupt(int irq, FAR void *context)
* action should be required to protect the work queue. * 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) if (ret != 0)
{ {
illdbg("Failed to queue work: %d\n", ret); illdbg("Failed to queue work: %d\n", ret);

View File

@ -783,7 +783,7 @@ static void stmpe811_timeout(int argc, uint32_t arg1, ...)
* action should be required to protect the work queue. * 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) if (ret != 0)
{ {
illdbg("Failed to queue work: %d\n", ret); illdbg("Failed to queue work: %d\n", ret);

View File

@ -775,7 +775,7 @@ static int tsc2007_interrupt(int irq, FAR void *context)
*/ */
DEBUGASSERT(priv->work.worker == NULL); 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) if (ret != 0)
{ {
illdbg("Failed to queue work: %d\n", ret); illdbg("Failed to queue work: %d\n", ret);
@ -1316,7 +1316,7 @@ int tsc2007_register(FAR struct i2c_dev_s *dev,
* availability conditions. * availability conditions.
*/ */
ret = work_queue(&priv->work, tsc2007_worker, priv, 0); ret = work_queue(HPWORK, &priv->work, tsc2007_worker, priv, 0);
if (ret != 0) if (ret != 0)
{ {
idbg("Failed to queue work: %d\n", ret); idbg("Failed to queue work: %d\n", ret);

View File

@ -1509,7 +1509,7 @@ static int enc_interrupt(int irq, FAR void *context)
* a good thing to do in any event. * 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 #endif
} }

View File

@ -328,7 +328,7 @@ void pm_update(int16_t accum)
/* The work will be performed on the worker thread */ /* The work will be performed on the worker thread */
DEBUGASSERT(g_pmglobals.work.worker == NULL); 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 */ #endif /* CONFIG_PM */

View File

@ -213,7 +213,7 @@ static void rwb_wrstarttimeout(FAR struct rwbuffer_s *rwb)
*/ */
int ticks = (CONFIG_FS_WRDELAY + CLK_TCK/2) / CLK_TCK; 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) static inline void rwb_wrcanceltimeout(struct rwbuffer_s *rwb)
{ {
(void)work_cancel(&rwb->work); (void)work_cancel(LPWORK, &rwb->work);
} }
/**************************************************************************** /****************************************************************************

View File

@ -1674,7 +1674,7 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
*/ */
DEBUGASSERT(priv->work.worker == NULL); 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; return OK;

View File

@ -1,8 +1,8 @@
/**************************************************************************** /****************************************************************************
* drivers/usbhost/usbhost_skeleton.c * drivers/usbhost/usbhost_skeleton.c
* *
* Copyright (C) 2011 Gregory Nutt. All rights reserved. * Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr> * 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
* modification, are permitted provided that the following conditions * 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); uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy);
DEBUGASSERT(priv->work.worker == NULL); 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 else
{ {

View File

@ -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); uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy);
DEBUGASSERT(priv->work.worker == NULL); 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 else
{ {

View File

@ -50,6 +50,75 @@
/**************************************************************************** /****************************************************************************
* Pre-Processor Definitions * 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 * Public Types
@ -86,10 +155,6 @@ extern "C" {
#define EXTERN extern #define EXTERN extern
#endif #endif
/* The task ID of the worker thread */
EXTERN pid_t g_worker;
/**************************************************************************** /****************************************************************************
* Public Function Prototypes * Public Function Prototypes
****************************************************************************/ ****************************************************************************/
@ -109,6 +174,7 @@ EXTERN pid_t g_worker;
* and remove it from the work queue. * and remove it from the work queue.
* *
* Input parameters: * Input parameters:
* qid - The work queue ID
* work - The work structure to queue * work - The work structure to queue
* worker - The worker callback to be invoked. The callback will invoked * worker - The worker callback to be invoked. The callback will invoked
* on the worker thread of execution. * 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 * Name: work_cancel
@ -133,6 +200,7 @@ EXTERN int work_queue(struct work_s *work, worker_t worker, FAR void *arg, uint3
* again. * again.
* *
* Input parameters: * Input parameters:
* qid - The work queue ID
* work - The previously queue work structure to cancel * work - The previously queue work structure to cancel
* *
* Returned Value: * 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 * 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. * user to force an immediate re-assessment of pending work.
* *
* Input parameters: * Input parameters:
* None * qid - The work queue ID
* *
* Returned Value: * Returned Value:
* Zero on success, a negated errno on failure * Zero on success, a negated errno on failure
* *
****************************************************************************/ ****************************************************************************/
#define work_signal() kill(g_worker, SIGWORK) EXTERN int work_signal(int qid);
/**************************************************************************** /****************************************************************************
* Name: work_available * Name: work_available

View File

@ -166,6 +166,39 @@ config SIG_SIGWORK
The signal number that will be used to wake-up the worker thread. The signal number that will be used to wake-up the worker thread.
Default: 4 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 config SCHED_WAITPID
bool "Enable waitpid() API" bool "Enable waitpid() API"
default n default n

View File

@ -141,7 +141,7 @@ TIMER_SRCS = timer_initialize.c timer_create.c timer_delete.c timer_getoverrun.c
endif endif
ifeq ($(CONFIG_SCHED_WORKQUEUE),y) 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 endif
ifeq ($(CONFIG_PAGING),y) ifeq ($(CONFIG_PAGING),y)

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* sched/os_bringup.c * 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> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* With extensions by: * With extensions by:
@ -47,6 +47,7 @@
#include <debug.h> #include <debug.h>
#include <nuttx/init.h> #include <nuttx/init.h>
#include <nuttx/wqueue.h>
#include "os_internal.h" #include "os_internal.h"
#ifdef CONFIG_PAGING #ifdef CONFIG_PAGING
@ -149,10 +150,23 @@ int os_bringup(void)
#ifdef CONFIG_SCHED_WORKQUEUE #ifdef CONFIG_SCHED_WORKQUEUE
svdbg("Starting worker thread\n"); svdbg("Starting worker thread\n");
g_worker = KERNEL_THREAD("work", CONFIG_SCHED_WORKPRIORITY, g_work[HPWORK].pid = KERNEL_THREAD("work0", CONFIG_SCHED_WORKPRIORITY,
CONFIG_SCHED_WORKSTACKSIZE, CONFIG_SCHED_WORKSTACKSIZE,
(main_t)work_thread, (const char **)NULL); (main_t)work_hpthread, (const char **)NULL);
ASSERT(g_worker != ERROR); 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 #endif
/* Once the operating system has been initialized, the system must be /* Once the operating system has been initialized, the system must be

View File

@ -1,7 +1,7 @@
/************************************************************************ /************************************************************************
* sched/sched_free.c * 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> * 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
@ -99,7 +99,7 @@ void sched_free(FAR void *address)
/* Signal the worker thread that is has some clean up to do */ /* Signal the worker thread that is has some clean up to do */
#ifdef CONFIG_SCHED_WORKQUEUE #ifdef CONFIG_SCHED_WORKQUEUE
work_signal(); work_signal(LPWORK);
#endif #endif
irqrestore(saved_state); irqrestore(saved_state);
} }

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* sched/work_cancel.c * 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> * 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
@ -74,6 +74,7 @@
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: work_cancel * Name: work_cancel
* *
@ -83,6 +84,7 @@
* again. * again.
* *
* Input parameters: * Input parameters:
* qid - The work queue ID
* work - The previously queue work structure to cancel * work - The previously queue work structure to cancel
* *
* Returned Value: * 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; irqstate_t flags;
DEBUGASSERT(work != NULL); DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS);
/* Cancelling the work is simply a matter of removing the work structure /* Cancelling the work is simply a matter of removing the work structure
* from the work queue. This must be done with interrupts disabled because * 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 */ /* 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.flink ||(FAR dq_entry_t *)work == wqueue->q.tail);
DEBUGASSERT(work->dq.blink ||(FAR dq_entry_t *)work == g_work.head); 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 /* Remove the entry from the work queue and make sure that it is
* mark as availalbe (i.e., the worker field is nullified). * 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; work->worker = NULL;
} }
irqrestore(flags); irqrestore(flags);
return OK; return OK;
} }
#endif /* CONFIG_SCHED_WORKQUEUE */ #endif /* CONFIG_SCHED_WORKQUEUE */

View File

@ -51,51 +51,49 @@
/* Configuration ************************************************************/ /* 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 #ifdef CONFIG_DISABLE_SIGNALS
# warning "Worker thread support requires signals" # warning "Worker thread support requires signals"
#endif #endif
#ifdef CONFIG_SCHED_LPWORK
# define NWORKERS 2
#else
# define NWORKERS 1
#endif
/**************************************************************************** /****************************************************************************
* Public Types * Public Types
****************************************************************************/ ****************************************************************************/
#ifndef __ASSEMBLY__ #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 * Public Data
****************************************************************************/ ****************************************************************************/
/* The queue of pending work */ /* The state of each work queue */
extern struct dq_queue_s g_work; extern struct wqueue_s g_work[NWORKERS];
/* The task ID of the worker thread */
extern pid_t g_worker;
/**************************************************************************** /****************************************************************************
* Public Function Prototypes * Public Function Prototypes
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: work_thread * Name: work_hpthread and work_lpthread
* *
* Description: * Description:
* This is the main worker thread that performs actions placed on the work * These are the main worker threads that performs actions placed on the
* queue. It also performs periodic garbage collection (that is performed * work lists. One thread also performs periodic garbage collection (that
* by the idle thread if CONFIG_SCHED_WORKQUEUE is not defined). * is performed by the idle thread if CONFIG_SCHED_WORKQUEUE is not defined).
* *
* Input parameters: * Input parameters:
* argc, argv (not used) * 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 /* __ASSEMBLY__ */
#endif /* CONFIG_SCHED_WORKQUEUE */ #endif /* CONFIG_SCHED_WORKQUEUE */

View File

@ -76,6 +76,7 @@
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: work_queue * Name: work_queue
* *
@ -91,6 +92,7 @@
* and remove it from the work queue. * and remove it from the work queue.
* *
* Input parameters: * Input parameters:
* qid - The work queue ID (index)
* work - The work structure to queue * work - The work structure to queue
* worker - The worker callback to be invoked. The callback will invoked * worker - The worker callback to be invoked. The callback will invoked
* on the worker thread of execution. * 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; irqstate_t flags;
DEBUGASSERT(work != NULL); DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS);
/* First, initialize the work structure */ /* 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(); flags = irqsave();
work->qtime = clock_systimer(); /* Time work queued */ 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); irqrestore(flags);
return OK; return OK;
} }

96
sched/work_signal.c Normal file
View File

@ -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 */

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* sched/work_thread.c * 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> * 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
@ -67,15 +67,9 @@
* Public Variables * Public Variables
****************************************************************************/ ****************************************************************************/
/* The queue of pending work */ /* The state of each work queue */
struct dq_queue_s g_work; struct wqueue_s g_work[NWORKERS];
/* The task ID of the worker thread */
#ifdef CONFIG_SCHED_WORKQUEUE
pid_t g_worker;
#endif
/**************************************************************************** /****************************************************************************
* Private Variables * Private Variables
@ -86,56 +80,28 @@ pid_t g_worker;
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Public Functions * Name: work_process
****************************************************************************/
/****************************************************************************
* Name: work_thread
* *
* Description: * Description:
* This is the main worker thread that performs actions placed on the work * This is the logic that performs actions placed on any work list.
* list. It also performs periodic garbage collection (that is performed
* by the idle thread if CONFIG_SCHED_WORKQUEUE is not defined).
* *
* Input parameters: * Input parameters:
* argc, argv (not used) * wqueue - Describes the work queue to be processed
* *
* Returned Value: * 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; volatile FAR struct work_s *work;
worker_t worker; worker_t worker;
irqstate_t flags;
FAR void *arg; FAR void *arg;
uint32_t elapsed; uint32_t elapsed;
uint32_t remaining; uint32_t remaining;
uint32_t next; uint32_t next;
int usec;
irqstate_t flags;
/* Loop forever */
usec = CONFIG_SCHED_WORKPERIOD;
flags = irqsave();
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(usec);
irqrestore(flags);
/* 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).
*/
sched_garbagecollection();
/* Then process queued work. We need to keep interrupts disabled while /* Then process queued work. We need to keep interrupts disabled while
* we process items in the work list. * we process items in the work list.
@ -143,7 +109,7 @@ int work_thread(int argc, char *argv[])
next = CONFIG_SCHED_WORKPERIOD / USEC_PER_TICK; next = CONFIG_SCHED_WORKPERIOD / USEC_PER_TICK;
flags = irqsave(); flags = irqsave();
work = (FAR struct work_s *)g_work.head; work = (FAR struct work_s *)wqueue->q.head;
while (work) while (work)
{ {
/* Is this work ready? It is ready if there is no delay or if /* Is this work ready? It is ready if there is no delay or if
@ -157,7 +123,7 @@ int work_thread(int argc, char *argv[])
{ {
/* Remove the ready-to-execute work from the list */ /* Remove the ready-to-execute work from the list */
(void)dq_rem((struct dq_entry_s *)work, &g_work); (void)dq_rem((struct dq_entry_s *)work, &wqueue->q);
/* Extract the work description from the entry (in case the work /* Extract the work description from the entry (in case the work
* instance by the re-used after it has been de-queued). * instance by the re-used after it has been de-queued).
@ -183,7 +149,7 @@ int work_thread(int argc, char *argv[])
*/ */
flags = irqsave(); flags = irqsave();
work = (FAR struct work_s *)g_work.head; work = (FAR struct work_s *)wqueue->q.head;
} }
else else
{ {
@ -205,11 +171,86 @@ int work_thread(int argc, char *argv[])
} }
} }
/* Now calculate the microsecond delay we should wait */ /* Wait awhile to check the work list. We will wait here until either
* the time elapses or until we are awakened by a signal.
*/
usec = next * USEC_PER_TICK; usleep(next * USEC_PER_TICK);
irqrestore(flags);
}
/****************************************************************************
* 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
*
****************************************************************************/
int work_hpthread(int argc, char *argv[])
{
/* Loop forever */
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).
*/
#ifdef CONFIG_SCHED_LPWORK
sched_garbagecollection();
#endif
/* Then process queued work. We need to keep interrupts disabled while
* we process items in the work list.
*/
work_process(&g_work[HPWORK]);
} }
return OK; /* To keep some compilers happy */ return OK; /* To keep some compilers happy */
} }
#ifdef CONFIG_SCHED_LPWORK
int work_lpthread(int argc, char *argv[])
{
/* Loop forever */
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).
*/
sched_garbagecollection();
/* 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 */ #endif /* CONFIG_SCHED_WORKQUEUE */

View File

@ -101,17 +101,17 @@ if [ ! -d "${configpath}" ]; then
fi fi
if [ ! -r "${configpath}/Make.defs" ]; then if [ ! -r "${configpath}/Make.defs" ]; then
echo "File ${configpath}/Make.defs does not exist" echo "File \"${configpath}/Make.defs\" does not exist"
exit 4 exit 4
fi fi
if [ ! -r "${configpath}/setenv.sh" ]; then if [ ! -r "${configpath}/setenv.sh" ]; then
echo "File ${configpath}/setenv.sh does not exist" echo "File \"${configpath}/setenv.sh\" does not exist"
exit 5 exit 5
fi fi
if [ ! -r "${configpath}/defconfig" ]; then if [ ! -r "${configpath}/defconfig" ]; then
echo "File ${configpath}/defconfig does not exist" echo "File \"${configpath}/defconfig\" does not exist"
exit 6 exit 6
fi fi
@ -127,7 +127,7 @@ if [ -z "${appdir}" ]; then
appdir=`grep CONFIG_APPS_DIR= "${configpath}/defconfig" | cut -d'=' -f2` appdir=`grep CONFIG_APPS_DIR= "${configpath}/defconfig" | cut -d'=' -f2`
fi 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 if [ -z "${appdir}" ]; then
@ -152,7 +152,15 @@ if [ -z "${appdir}" ]; then
fi fi
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}/." || \ install -C "${configpath}/Make.defs" "${TOPDIR}/." || \
{ echo "Failed to copy ${configpath}/Make.defs" ; exit 7 ; } { echo "Failed to copy ${configpath}/Make.defs" ; exit 7 ; }