diff options
-rw-r--r-- | common/hooks.c | 11 | ||||
-rw-r--r-- | common/main.c | 3 | ||||
-rw-r--r-- | core/cortex-m/task.c | 14 | ||||
-rw-r--r-- | core/cortex-m0/task.c | 14 | ||||
-rw-r--r-- | core/host/main.c | 1 | ||||
-rw-r--r-- | core/host/task.c | 81 | ||||
-rw-r--r-- | core/nds32/task.c | 14 | ||||
-rw-r--r-- | include/hooks.h | 5 | ||||
-rw-r--r-- | include/task.h | 5 |
9 files changed, 113 insertions, 35 deletions
diff --git a/common/hooks.c b/common/hooks.c index c07a3d1d1c..6cca00c914 100644 --- a/common/hooks.c +++ b/common/hooks.c @@ -131,11 +131,6 @@ void hook_notify(enum hook_type type) #endif } -void hook_init(void) -{ - hook_notify(HOOK_INIT); -} - int hook_call_deferred(void (*routine)(void), int us) { const struct deferred_data *p; @@ -180,6 +175,12 @@ void hook_task(void) hook_task_started = 1; + /* Call HOOK_INIT hooks. */ + hook_notify(HOOK_INIT); + + /* Now, enable the rest of the tasks. */ + task_enable_all_tasks(); + while (1) { uint64_t t = get_time().val; int next = 0; diff --git a/common/main.c b/common/main.c index a2f86abdee..d70d987d43 100644 --- a/common/main.c +++ b/common/main.c @@ -160,9 +160,6 @@ test_mockable __keep int main(void) check_rw_signature(); #endif - /* Initialize the hook library. This calls HOOK_INIT hooks. */ - hook_init(); - /* * Print the init time. Not completely accurate because it can't take * into account the time before timer_init(), but it'll at least catch diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c index 639cef9d48..09d7108e7b 100644 --- a/core/cortex-m/task.c +++ b/core/cortex-m/task.c @@ -139,9 +139,11 @@ static int need_resched_or_profiling; /* * Bitmap of all tasks ready to be run. * - * Currently all tasks are enabled at startup. + * Start off with only the hooks task marked as ready such that all the modules + * can do their init within a task switching context. The hooks task will then + * make a call to enable all tasks. */ -static uint32_t tasks_ready = (1<<TASK_ID_COUNT) - 1; +static uint32_t tasks_ready = (1 << TASK_ID_HOOKS); static int start_called; /* Has task swapping started */ @@ -412,6 +414,14 @@ uint32_t task_wait_event_mask(uint32_t event_mask, int timeout_us) return events & event_mask; } +void task_enable_all_tasks(void) +{ + /* Mark all tasks as ready to run. */ + tasks_ready = (1 << TASK_ID_COUNT) - 1; + /* Reschedule the highest priority task. */ + __schedule(0, 0); +} + void task_enable_irq(int irq) { CPU_NVIC_EN(irq / 32) = 1 << (irq % 32); diff --git a/core/cortex-m0/task.c b/core/cortex-m0/task.c index 9d9b049c37..0a229fcbde 100644 --- a/core/cortex-m0/task.c +++ b/core/cortex-m0/task.c @@ -126,9 +126,11 @@ static task_ *current_task = (task_ *)scratchpad; /* * Bitmap of all tasks ready to be run. * - * Currently all tasks are enabled at startup. + * Start off with only the hooks task marked as ready such that all the modules + * can do their init within a task switching context. The hooks task will then + * make a call to enable all tasks. */ -static uint32_t tasks_ready = (1<<TASK_ID_COUNT) - 1; +static uint32_t tasks_ready = (1 << TASK_ID_HOOKS); static int start_called; /* Has task swapping started */ @@ -432,6 +434,14 @@ uint32_t task_wait_event_mask(uint32_t event_mask, int timeout_us) return events & event_mask; } +void task_enable_all_tasks(void) +{ + /* Mark all tasks as ready to run. */ + tasks_ready = (1 << TASK_ID_COUNT) - 1; + /* Reschedule the highest priority task. */ + __schedule(0, 0); +} + void task_enable_irq(int irq) { CPU_NVIC_EN(0) = 1 << irq; diff --git a/core/host/main.c b/core/host/main.c index 80c2f33bf5..fbb28d9127 100644 --- a/core/host/main.c +++ b/core/host/main.c @@ -45,7 +45,6 @@ int main(int argc, char **argv) #ifdef HAS_TASK_KEYSCAN keyboard_scan_init(); #endif - hook_init(); uart_init(); if (system_jumped_to_this_image()) { diff --git a/core/host/task.c b/core/host/task.c index 53f722e8b7..28c0cb0297 100644 --- a/core/host/task.c +++ b/core/host/task.c @@ -56,6 +56,8 @@ static int has_interrupt_generator = 1; static __thread task_id_t my_task_id; /* thread local task id */ +static void task_enable_all_tasks_callback(void); + #define TASK(n, r, d, s) void r(void *); CONFIG_TASK_LIST CONFIG_TEST_TASK_LIST @@ -331,6 +333,7 @@ static int fast_forward(void) return TASK_ID_IDLE; if (task_id != TASK_ID_INVALID && + tasks[task_id].thread != (pthread_t)NULL && tasks[task_id].wake_time.val < generator_sleep_deadline.val) { force_time(tasks[task_id].wake_time); return task_id; @@ -356,8 +359,15 @@ void task_scheduler(void) now = get_time(); i = TASK_ID_COUNT - 1; while (i >= 0) { - if (tasks[i].event || now.val >= tasks[i].wake_time.val) - break; + /* + * Only tasks with spawned threads are valid to be + * resumed. + */ + if (tasks[i].thread) { + if (tasks[i].event || + now.val >= tasks[i].wake_time.val) + break; + } --i; } if (i < 0) @@ -404,7 +414,7 @@ void *_task_int_generator_start(void *d) int task_start(void) { - int i; + int i = TASK_ID_HOOKS; task_register_interrupt(); @@ -414,31 +424,72 @@ int task_start(void) pthread_mutex_lock(&run_lock); + /* + * Initialize the hooks task first. After its init, it will callback to + * enable the remaining tasks. + */ + tasks[i].event = TASK_EVENT_WAKE; + tasks[i].wake_time.val = ~0ull; + tasks[i].started = 0; + pthread_cond_init(&tasks[i].resume, NULL); + pthread_create(&tasks[i].thread, NULL, _task_start_impl, + (void *)(uintptr_t)i); + pthread_cond_wait(&scheduler_cond, &run_lock); + /* + * Interrupt lock is grabbed by the task which just started. + * Let's unlock it so the next task can be started. + */ + pthread_mutex_unlock(&interrupt_lock); + + /* + * The hooks task is waiting in task_wait_event(). Lock interrupt_lock + * here so the first task chosen sees it locked. + */ + pthread_mutex_lock(&interrupt_lock); + + pthread_create(&interrupt_thread, NULL, + _task_int_generator_start, NULL); + + /* + * Tell the hooks task to continue so that it can call back to enable + * the other tasks. + */ + pthread_cond_signal(&tasks[i].resume); + pthread_cond_wait(&scheduler_cond, &run_lock); + task_enable_all_tasks_callback(); + + task_scheduler(); + + return 0; +} + +static void task_enable_all_tasks_callback(void) +{ + int i; + + /* Initialize the remaning tasks. */ for (i = 0; i < TASK_ID_COUNT; ++i) { + if (tasks[i].thread != (pthread_t)NULL) + continue; + tasks[i].event = TASK_EVENT_WAKE; tasks[i].wake_time.val = ~0ull; tasks[i].started = 0; pthread_cond_init(&tasks[i].resume, NULL); pthread_create(&tasks[i].thread, NULL, _task_start_impl, (void *)(uintptr_t)i); - pthread_cond_wait(&scheduler_cond, &run_lock); /* * Interrupt lock is grabbed by the task which just started. * Let's unlock it so the next task can be started. */ pthread_mutex_unlock(&interrupt_lock); + pthread_cond_wait(&scheduler_cond, &run_lock); } - /* - * All tasks are now waiting in task_wait_event(). Lock interrupt_lock - * here so the first task chosen sees it locked. - */ - pthread_mutex_lock(&interrupt_lock); - - pthread_create(&interrupt_thread, NULL, - _task_int_generator_start, NULL); - - task_scheduler(); +} - return 0; +void task_enable_all_tasks(void) +{ + /* Signal to the scheduler to enable the remaining tasks. */ + pthread_cond_signal(&scheduler_cond); } diff --git a/core/nds32/task.c b/core/nds32/task.c index 269513092b..baf87ffbf3 100644 --- a/core/nds32/task.c +++ b/core/nds32/task.c @@ -139,9 +139,11 @@ int need_resched; /* * Bitmap of all tasks ready to be run. * - * Currently all tasks are enabled at startup. + * Start off with only the hooks task marked as ready such that all the modules + * can do their init within a task switching context. The hooks task will then + * make a call to enable all tasks. */ -static uint32_t tasks_ready = (1<<TASK_ID_COUNT) - 1; +static uint32_t tasks_ready = (1 << TASK_ID_HOOKS); static int start_called; /* Has task swapping started */ @@ -306,6 +308,14 @@ static void set_int_priority(uint32_t val) asm volatile ("mtsr %0, $INT_PRI" : : "r"(val)); } +void task_enable_all_tasks(void) +{ + /* Mark all tasks are ready to run. */ + tasks_ready = (1 << TASK_ID_COUNT) - 1; + /* Reschedule the highest priority task. */ + __schedule(0, 0, 0); +} + void task_enable_irq(int irq) { int cpu_int = chip_enable_irq(irq); diff --git a/include/hooks.h b/include/hooks.h index f5a728d8e1..d62fca9b4a 100644 --- a/include/hooks.h +++ b/include/hooks.h @@ -168,11 +168,6 @@ struct hook_data { }; /** - * Initialize the hooks library. - */ -void hook_init(void); - -/** * Call all the hook routines of a specified type. * * This function must be called from the correct type-specific context (task); diff --git a/include/task.h b/include/task.h index 06cef86946..d7d6dd1ca3 100644 --- a/include/task.h +++ b/include/task.h @@ -184,6 +184,11 @@ void task_clear_fp_used(void); #endif /** + * Mark all tasks as ready to run and reschedule the highest priority task. + */ +void task_enable_all_tasks(void); + +/** * Enable an interrupt. */ void task_enable_irq(int irq); |