If there mutliple low-priority worker threads, only one needs to perform garbage collection

This commit is contained in:
Gregory Nutt
2014-10-11 07:09:21 -06:00
parent 370b48d1e6
commit 0218f01f12
4 changed files with 94 additions and 53 deletions
+13 -8
View File
@@ -108,22 +108,27 @@ static int work_hpthread(int argc, char *argv[])
for (;;) for (;;)
{ {
/* First, perform garbage collection. This cleans-up memory de-allocations #ifndef CONFIG_SCHED_LPWORK
* that were queued because they could not be freed in that execution /* First, perform garbage collection. This cleans-up memory
* context (for example, if the memory was freed from an interrupt handler). * 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 * NOTE: If the work thread is disabled, this clean-up is performed by
* the IDLE thread (at a very, very low priority). * the IDLE thread (at a very, very low priority). If the low-priority
* work thread is enabled, then the garbage collection is done on that
* thread instead.
*/ */
#ifndef CONFIG_SCHED_LPWORK
sched_garbagecollection(); sched_garbagecollection();
#endif #endif
/* Then process queued work. We need to keep interrupts disabled while /* Then process queued work. work_process will not return until: (1)
* we process items in the work list. * there is no further work in the work queue, and (2) the polling
* period provided by g_hpwork.delay expires.
*/ */
work_process((FAR struct kwork_wqueue_s *)&g_hpwork, 0); work_process((FAR struct kwork_wqueue_s *)&g_hpwork, g_hpwork.delay, 0);
} }
return OK; /* To keep some compilers happy */ return OK; /* To keep some compilers happy */
+44 -31
View File
@@ -106,52 +106,65 @@ struct lp_wqueue_s g_lpwork;
static int work_lpthread(int argc, char *argv[]) static int work_lpthread(int argc, char *argv[])
{ {
#if CONFIG_SCHED_LPNTHREADS > 0
int wndx; int wndx;
pid_t me = getpid();
int i;
/* Find out thread index by search the workers in g_lpwork */ /* Find out thread index by search the workers in g_lpwork */
{ for (wndx = 0, i = 0; i < CONFIG_SCHED_LPNTHREADS; i++)
pid_t me = getpid(); {
int i; if (g_lpwork.worker[i].pid == me)
{
wndx = i;
break;
}
}
/* Check each entry if we have to */ DEBUGASSERT(i < CONFIG_SCHED_LPNTHREADS);
#endif
for (wndx = 0, i = 0; i < CONFIG_SCHED_LPNTHREADS; i++)
{
if (g_lpwork.worker[i].pid == me)
{
wndx = i;
break;
}
}
DEBUGASSERT(i < CONFIG_SCHED_LPNTHREADS);
}
/* Loop forever */ /* Loop forever */
for (;;) for (;;)
{ {
/* First, perform garbage collection. This cleans-up memory de-allocations #if CONFIG_SCHED_LPNTHREADS > 0
* that were queued because they could not be freed in that execution /* Thread 0 is special. Only thread 0 performs period garbage collection */
* 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 low priority).
*
* In the event of multiple low priority threads, on index == 0 will do
* the garbage collection.
*/
if (wndx == 0) if (wndx > 0)
{ {
sched_garbagecollection(); /* The other threads will perform work, waiting indefinitely until
* signalled for the next work availability.
*
* The special value of zero for the poll period instructs work_process
* to wait indefinitely until a signal is received.
*/
work_process((FAR struct kwork_wqueue_s *)&g_lpwork, 0, wndx);
} }
else
#endif
{
/* 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 low priority).
*
* In the event of multiple low priority threads, on index == 0 will do
* the garbage collection.
*/
/* Then process queued work. We need to keep interrupts disabled while sched_garbagecollection();
* we process items in the work list.
*/
work_process((FAR struct kwork_wqueue_s *)&g_lpwork, wndx); /* Then process queued work. work_process will not return until:
* (1) there is no further work in the work queue, and (2) the polling
* period provided by g_lpwork.delay expires.
*/
work_process((FAR struct kwork_wqueue_s *)&g_lpwork, g_lpwork.delay, 0);
}
} }
return OK; /* To keep some compilers happy */ return OK; /* To keep some compilers happy */
+34 -13
View File
@@ -41,6 +41,7 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h>
#include <queue.h> #include <queue.h>
#include <nuttx/clock.h> #include <nuttx/clock.h>
@@ -107,7 +108,7 @@
* *
****************************************************************************/ ****************************************************************************/
void work_process(FAR struct kwork_wqueue_s *wqueue, int wndx) void work_process(FAR struct kwork_wqueue_s *wqueue, uint32_t period, int wndx)
{ {
volatile FAR struct work_s *work; volatile FAR struct work_s *work;
worker_t worker; worker_t worker;
@@ -123,7 +124,7 @@ void work_process(FAR struct kwork_wqueue_s *wqueue, int wndx)
* we process items in the work list. * we process items in the work list.
*/ */
next = wqueue->delay; next = period;
flags = irqsave(); flags = irqsave();
/* Get the time that we started this polling cycle in clock ticks. */ /* Get the time that we started this polling cycle in clock ticks. */
@@ -221,21 +222,41 @@ void work_process(FAR struct kwork_wqueue_s *wqueue, int wndx)
} }
} }
/* Get the delay (in clock ticks) since we started the sampling */ #if defined(CONFIG_SCHED_LPWORK) && CONFIG_SCHED_LPNTHREADS > 0
/* Value of zero for period means that we should wait indefinitely until
* signalled. This option is used only for the case where there are
* multiple, low-priority worker threads. In that case, only one of
* the threads does the poll... the others simple. In all other cases
* period will be non-zero and equal to wqueue->delay.
*/
elapsed = clock_systimer() - stick; if (period == 0)
if (elapsed <= wqueue->delay) {
sigset_t set;
/* Wait indefinitely until signalled with SIGWORK */
sigemptyset(&set);
sigaddset(&set, SIGWORK);
DEBUGVERIFY(sigwaitinfo(&set, NULL));
}
else
#endif
{ {
/* How much time would we need to delay to get to the end of the /* Get the delay (in clock ticks) since we started the sampling */
* sampling period? The amount of time we delay should be the smaller
* of the time to the end of the sampling period and the time to the
* next work expiry.
*/
remaining = wqueue->delay - elapsed; elapsed = clock_systimer() - stick;
next = MIN(next, remaining); if (elapsed < period && next > 0)
if (next > 0)
{ {
/* How much time would we need to delay to get to the end of the
* sampling period? The amount of time we delay should be the smaller
* of the time to the end of the sampling period and the time to the
* next work expiry.
*/
remaining = period - elapsed;
next = MIN(next, remaining);
/* Wait awhile to check the work list. We will wait here until /* Wait awhile to check the work list. We will wait here until
* either the time elapses or until we are awakened by a signal. * either the time elapses or until we are awakened by a signal.
* Interrupts will be re-enabled while we wait. * Interrupts will be re-enabled while we wait.
+3 -1
View File
@@ -180,13 +180,15 @@ int work_lpstart(void);
* *
* Input parameters: * Input parameters:
* wqueue - Describes the work queue to be processed * wqueue - Describes the work queue to be processed
* period - The polling period in clock ticks
* wndx - The worker thread index
* *
* Returned Value: * Returned Value:
* None * None
* *
****************************************************************************/ ****************************************************************************/
void work_process(FAR struct kwork_wqueue_s *wqueue, int wndx); void work_process(FAR struct kwork_wqueue_s *wqueue, uint32_t period, int wndx);
#endif /* CONFIG_SCHED_WORKQUEUE */ #endif /* CONFIG_SCHED_WORKQUEUE */
#endif /* __SCHED_WQUEUE_WQUEUE_H */ #endif /* __SCHED_WQUEUE_WQUEUE_H */