|
|
|
@ -88,97 +88,98 @@ sem_t _work_lock[NWORKERS];
@@ -88,97 +88,98 @@ sem_t _work_lock[NWORKERS];
|
|
|
|
|
* |
|
|
|
|
****************************************************************************/ |
|
|
|
|
|
|
|
|
|
static void work_process(FAR struct wqueue_s *wqueue, int lock_id) |
|
|
|
|
static void work_process(struct wqueue_s *wqueue, int lock_id) |
|
|
|
|
{ |
|
|
|
|
volatile FAR struct work_s *work; |
|
|
|
|
worker_t worker; |
|
|
|
|
FAR void *arg; |
|
|
|
|
uint64_t elapsed; |
|
|
|
|
uint32_t remaining; |
|
|
|
|
uint32_t next; |
|
|
|
|
|
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
next = CONFIG_SCHED_WORKPERIOD; |
|
|
|
|
|
|
|
|
|
work_lock(lock_id); |
|
|
|
|
|
|
|
|
|
work = (FAR struct work_s *)wqueue->q.head; |
|
|
|
|
while (work) |
|
|
|
|
{ |
|
|
|
|
/* 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. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
elapsed = USEC2TICK(clock_systimer() - work->qtime); |
|
|
|
|
//printf("work_process: in ticks elapsed=%lu delay=%u\n", elapsed, work->delay);
|
|
|
|
|
if (elapsed >= work->delay) |
|
|
|
|
{ |
|
|
|
|
/* Remove the ready-to-execute work from the list */ |
|
|
|
|
|
|
|
|
|
(void)dq_rem((struct dq_entry_s *)work, &wqueue->q); |
|
|
|
|
|
|
|
|
|
/* Extract the work description from the entry (in case the work
|
|
|
|
|
* instance by the re-used after it has been de-queued). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
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! |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
work_unlock(lock_id); |
|
|
|
|
if (!worker) { |
|
|
|
|
PX4_WARN("MESSED UP: worker = 0\n"); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
worker(arg); |
|
|
|
|
|
|
|
|
|
/* 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. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
work_lock(lock_id); |
|
|
|
|
work = (FAR struct work_s *)wqueue->q.head; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* This one is not ready.. will it be ready before the next
|
|
|
|
|
* scheduled wakeup interval? |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/* Here: elapsed < work->delay */ |
|
|
|
|
remaining = USEC_PER_TICK*(work->delay - elapsed); |
|
|
|
|
if (remaining < next) |
|
|
|
|
{ |
|
|
|
|
/* Yes.. Then schedule to wake up when the work is ready */ |
|
|
|
|
|
|
|
|
|
next = remaining; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Then try the next in the list. */ |
|
|
|
|
|
|
|
|
|
work = (FAR struct work_s *)work->dq.flink; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Wait awhile to check the work list. We will wait here until either
|
|
|
|
|
* the time elapses or until we are awakened by a signal. |
|
|
|
|
*/ |
|
|
|
|
work_unlock(lock_id); |
|
|
|
|
|
|
|
|
|
usleep(next); |
|
|
|
|
volatile struct work_s *work; |
|
|
|
|
worker_t worker; |
|
|
|
|
void *arg; |
|
|
|
|
uint64_t elapsed; |
|
|
|
|
uint32_t remaining; |
|
|
|
|
uint32_t next; |
|
|
|
|
|
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
next = CONFIG_SCHED_WORKPERIOD; |
|
|
|
|
|
|
|
|
|
work_lock(lock_id); |
|
|
|
|
|
|
|
|
|
work = (struct work_s *)wqueue->q.head; |
|
|
|
|
|
|
|
|
|
while (work) { |
|
|
|
|
/* 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. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
elapsed = USEC2TICK(clock_systimer() - work->qtime); |
|
|
|
|
|
|
|
|
|
//printf("work_process: in ticks elapsed=%lu delay=%u\n", elapsed, work->delay);
|
|
|
|
|
if (elapsed >= work->delay) { |
|
|
|
|
/* Remove the ready-to-execute work from the list */ |
|
|
|
|
|
|
|
|
|
(void)dq_rem((struct dq_entry_s *)work, &wqueue->q); |
|
|
|
|
|
|
|
|
|
/* Extract the work description from the entry (in case the work
|
|
|
|
|
* instance by the re-used after it has been de-queued). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
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! |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
work_unlock(lock_id); |
|
|
|
|
|
|
|
|
|
if (!worker) { |
|
|
|
|
PX4_WARN("MESSED UP: worker = 0\n"); |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
worker(arg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* 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. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
work_lock(lock_id); |
|
|
|
|
work = (struct work_s *)wqueue->q.head; |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
/* This one is not ready.. will it be ready before the next
|
|
|
|
|
* scheduled wakeup interval? |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/* Here: elapsed < work->delay */ |
|
|
|
|
remaining = USEC_PER_TICK * (work->delay - elapsed); |
|
|
|
|
|
|
|
|
|
if (remaining < next) { |
|
|
|
|
/* Yes.. Then schedule to wake up when the work is ready */ |
|
|
|
|
|
|
|
|
|
next = remaining; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Then try the next in the list. */ |
|
|
|
|
|
|
|
|
|
work = (struct work_s *)work->dq.flink; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Wait awhile to check the work list. We will wait here until either
|
|
|
|
|
* the time elapses or until we are awakened by a signal. |
|
|
|
|
*/ |
|
|
|
|
work_unlock(lock_id); |
|
|
|
|
|
|
|
|
|
usleep(next); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
@ -194,19 +195,19 @@ void work_queues_init(void)
@@ -194,19 +195,19 @@ void work_queues_init(void)
|
|
|
|
|
|
|
|
|
|
// Create high priority worker thread
|
|
|
|
|
g_work[HPWORK].pid = px4_task_spawn_cmd("wkr_high", |
|
|
|
|
SCHED_DEFAULT, |
|
|
|
|
SCHED_PRIORITY_MAX-1, |
|
|
|
|
2000, |
|
|
|
|
work_hpthread, |
|
|
|
|
(char* const*)NULL); |
|
|
|
|
SCHED_DEFAULT, |
|
|
|
|
SCHED_PRIORITY_MAX - 1, |
|
|
|
|
2000, |
|
|
|
|
work_hpthread, |
|
|
|
|
(char *const *)NULL); |
|
|
|
|
|
|
|
|
|
// Create low priority worker thread
|
|
|
|
|
g_work[LPWORK].pid = px4_task_spawn_cmd("wkr_low", |
|
|
|
|
SCHED_DEFAULT, |
|
|
|
|
SCHED_PRIORITY_MIN, |
|
|
|
|
2000, |
|
|
|
|
work_lpthread, |
|
|
|
|
(char* const*)NULL); |
|
|
|
|
SCHED_DEFAULT, |
|
|
|
|
SCHED_PRIORITY_MIN, |
|
|
|
|
2000, |
|
|
|
|
work_lpthread, |
|
|
|
|
(char *const *)NULL); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -245,56 +246,54 @@ void work_queues_init(void)
@@ -245,56 +246,54 @@ void work_queues_init(void)
|
|
|
|
|
|
|
|
|
|
int work_hpthread(int argc, char *argv[]) |
|
|
|
|
{ |
|
|
|
|
/* Loop forever */ |
|
|
|
|
/* 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 low priority). |
|
|
|
|
*/ |
|
|
|
|
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 low priority). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#ifndef CONFIG_SCHED_LPWORK |
|
|
|
|
sched_garbagecollection(); |
|
|
|
|
sched_garbagecollection(); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
work_process(&g_work[HPWORK], HPWORK); |
|
|
|
|
} |
|
|
|
|
work_process(&g_work[HPWORK], HPWORK); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return PX4_OK; /* To keep some compilers happy */ |
|
|
|
|
return PX4_OK; /* To keep some compilers happy */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SCHED_LPWORK |
|
|
|
|
|
|
|
|
|
int work_lpthread(int argc, char *argv[]) |
|
|
|
|
{ |
|
|
|
|
/* Loop forever */ |
|
|
|
|
/* 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 low priority). |
|
|
|
|
*/ |
|
|
|
|
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 low priority). |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
//sched_garbagecollection();
|
|
|
|
|
//sched_garbagecollection();
|
|
|
|
|
|
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
work_process(&g_work[LPWORK], LPWORK); |
|
|
|
|
} |
|
|
|
|
work_process(&g_work[LPWORK], LPWORK); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return PX4_OK; /* To keep some compilers happy */ |
|
|
|
|
return PX4_OK; /* To keep some compilers happy */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif /* CONFIG_SCHED_LPWORK */ |
|
|
|
@ -304,18 +303,17 @@ int work_lpthread(int argc, char *argv[])
@@ -304,18 +303,17 @@ int work_lpthread(int argc, char *argv[])
|
|
|
|
|
|
|
|
|
|
int work_usrthread(int argc, char *argv[]) |
|
|
|
|
{ |
|
|
|
|
/* Loop forever */ |
|
|
|
|
/* Loop forever */ |
|
|
|
|
|
|
|
|
|
for (;;) |
|
|
|
|
{ |
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
for (;;) { |
|
|
|
|
/* Then process queued work. We need to keep interrupts disabled while
|
|
|
|
|
* we process items in the work list. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
work_process(&g_work[USRWORK], USRWORK); |
|
|
|
|
} |
|
|
|
|
work_process(&g_work[USRWORK], USRWORK); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return PX4_OK; /* To keep some compilers happy */ |
|
|
|
|
return PX4_OK; /* To keep some compilers happy */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif /* CONFIG_SCHED_USRWORK */ |
|
|
|
|