23#define TASK_IDLE_PRI (OS_CFG_PRIO_MAX - 1u)
25#define TASK_TIMER_PRI ((uint8_t)OS_CFG_TIMER_TASK_PRI)
27#define TASK_TIMER_STK_SIZE (100u)
32#define SIZE_OF_TCB (sizeof(task_tcb_t))
35task_tcb_t *
volatile tcb_curr_ptr = NULL;
36task_tcb_t *
volatile tcb_high_rdy_ptr = NULL;
39static list_t dly_task_list_1;
40static list_t dly_task_list_2;
41static list_t *
volatile dly_task_list_ptr;
42static list_t *
volatile overflow_dly_task_list_ptr;
43static list_t suspended_task_list;
45static volatile uint16_t num_of_tasks = (uint16_t)0U;
46static volatile uint32_t tick_count = (uint32_t)0u;
47static volatile uint32_t ticks_pended = (uint32_t)0U;
50static volatile uint8_t sched_is_running = (uint8_t)OS_FALSE;
52extern const thread_t __start_task_desc[] __attribute__((weak));
53extern const thread_t __stop_task_desc[] __attribute__((weak));
55static task_tcb_t **task_tcb_list = NULL;
56static uint8_t task_tcb_list_len = 0u;
57static uint8_t task_app_count = 0u;
58static uint8_t task_shell_id = UINT8_MAX;
59static uint8_t task_idle_id = 0u;
60static uint8_t task_timer_id = 0u;
73 return task_app_count;
95static void task_idle_func(
void *p_arg)
108static void task_timer_func(
void *p_arg)
120 volatile uint32_t *stk_ptr;
121 list_item_t state_list_item;
122 list_item_t event_list_item;
123 uint32_t *stk_limit_ptr;
126 uint32_t *stk_base_ptr;
128 msg_queue_t msg_queue;
133 uint32_t last_run_ticks;
137#if (OS_CFG_USE_SHELL != 0u)
138static const char *thread_get_name_by_id(
thread_id_t id)
140 const thread_t *p_thread_desc = __start_task_desc;
142 for (; p_thread_desc < __stop_task_desc; ++p_thread_desc)
144 if (p_thread_desc->id ==
id)
146 return p_thread_desc->name;
150 if (
id == task_shell_id)
154 if (
id == task_timer_id)
158 if (
id == task_idle_id)
167#if (OS_CFG_USE_RUNTIME_STATS != 0u)
168static void akos_thread_calculate_cpu_load(
void);
174static void init_task_lists(
void)
185 dly_task_list_ptr = &dly_task_list_1;
186 overflow_dly_task_list_ptr = &dly_task_list_2;
193static void task_switch_delay_lists()
196 p_list_temp = dly_task_list_ptr;
197 dly_task_list_ptr = overflow_dly_task_list_ptr;
198 overflow_dly_task_list_ptr = p_list_temp;
200 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
214 task_tcb_t *p_tcb = list_get_owner_of_head_item(dly_task_list_ptr);
215 uint32_t item_value = list_item_get_value(&(p_tcb->state_list_item));
216 next_tick_to_unblock = item_value;
224static void add_new_task_to_rdy_list(task_tcb_t *p_tcb)
226 AKOS_CORE_ENTER_CRITICAL();
229 if (num_of_tasks == 1)
232 tcb_curr_ptr = p_tcb;
236 if (tcb_curr_ptr->prio <= p_tcb->prio)
238 tcb_curr_ptr = p_tcb;
242 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
249 AKOS_CORE_EXIT_CRITICAL();
256static void add_task_to_rdy_list(task_tcb_t *p_tcb)
259 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
272static void add_curr_task_to_delay_list(uint32_t tick_to_delay, uint8_t can_block_indefinitely)
274 uint32_t time_to_wake;
275 const uint32_t const_tick = tick_count;
280 if ((tick_to_delay ==
OS_CFG_DELAY_MAX) && (can_block_indefinitely != OS_FALSE))
291 time_to_wake = const_tick + tick_to_delay;
292 list_item_set_value(&(tcb_curr_ptr->state_list_item), time_to_wake);
294 if (time_to_wake < const_tick)
298 akos_list_insert(overflow_dly_task_list_ptr, &(tcb_curr_ptr->state_list_item));
310 if (time_to_wake < next_tick_to_unblock)
312 next_tick_to_unblock = time_to_wake;
319 tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[highest_prio]));
323#if (OS_CFG_USE_RUNTIME_STATS != 0u)
324 akos_thread_calculate_cpu_load();
345 if (sched_is_running == OS_TRUE)
348 core_assert(0,
"OS_ERR_SCHED_IS_RUNNING");
354 core_assert(0,
"OS_ERR_TCB_PRIO_INVALID");
357 if (pf_thread == NULL)
360 core_assert(0,
"OS_ERR_TCB_FUNC_INVALID");
366 core_assert(0,
"OS_ERR_TCB_STK_SIZE_INVALID");
369 if ((task_tcb_list == NULL) || (
id >= task_tcb_list_len))
371 core_assert(0,
"OS_ERR_TASK_ID_INVALID");
374 if (task_tcb_list[
id] != NULL)
376 core_assert(0,
"OS_ERR_TASK_ID_ALREADY_USED");
381 task_tcb_t *p_new_tcb;
388 if (p_new_tcb != NULL)
390 memset((
void *)p_new_tcb, 0x00, SIZE_OF_TCB);
393 p_new_tcb->stk_limit_ptr = p_stack;
399 core_assert(0,
"OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
406 core_assert(0,
"OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
411 uint32_t *p_stack_ptr;
423 p_new_tcb->stk_ptr = p_stack_ptr;
426 p_new_tcb->stk_size = stack_size;
432 p_new_tcb->prio = prio;
441 list_item_set_owner(&(p_new_tcb->state_list_item), (
void *)p_new_tcb);
442 list_item_set_owner(&(p_new_tcb->event_list_item), (
void *)p_new_tcb);
444 list_item_set_value(&(p_new_tcb->state_list_item), prio);
446 add_new_task_to_rdy_list(p_new_tcb);
447 task_tcb_list[id] = p_new_tcb;
457 const thread_t *p_thread_desc = __start_task_desc;
458 const thread_t *p_thread_desc_end = __stop_task_desc;
459 size_t app_count = 0u;
461 if ((p_thread_desc == NULL) || (p_thread_desc_end == NULL) || (p_thread_desc == p_thread_desc_end))
467 app_count = (size_t)(p_thread_desc_end - p_thread_desc);
470 if (app_count > (
size_t)(UINT8_MAX - 3u))
472 core_assert(0,
"OS_ERR_TOO_MANY_TASKS");
476 task_app_count = (uint8_t)app_count;
477#if (OS_CFG_USE_SHELL != 0u)
478 task_shell_id = task_app_count;
479 task_timer_id = (uint8_t)(task_app_count + 1u);
480 task_idle_id = (uint8_t)(task_app_count + 2u);
481 task_tcb_list_len = (uint8_t)(task_app_count + 3u);
483 task_shell_id = UINT8_MAX;
484 task_idle_id = task_app_count;
485 task_timer_id = (uint8_t)(task_app_count + 1u);
486 task_tcb_list_len = (uint8_t)(task_app_count + 2u);
489 task_tcb_list = (task_tcb_t **)
akos_memory_malloc(
sizeof(task_tcb_t *) * task_tcb_list_len);
490 if (task_tcb_list == NULL)
492 core_assert(0,
"OS_ERR_TASK_TCB_TABLE_ALLOC");
495 memset(task_tcb_list, 0x00,
sizeof(task_tcb_t *) * task_tcb_list_len);
497 for (; p_thread_desc < p_thread_desc_end; ++p_thread_desc)
499 if (p_thread_desc->id >= task_app_count)
501 core_assert(0,
"OS_ERR_THREAD_ID_RESERVED");
505 (void)task_create(p_thread_desc->id,
506 p_thread_desc->pf_thread,
507 p_thread_desc->p_arg,
509 p_thread_desc->queue_size,
510 p_thread_desc->stack_size);
513#if (OS_CFG_USE_SHELL != 0u)
525 (uint8_t)TASK_TIMER_PRI,
527 (
size_t)TASK_TIMER_STK_SIZE);
532 (uint8_t)TASK_IDLE_PRI,
537#if (OS_CFG_USE_RUNTIME_STATS != 0u)
538static void akos_thread_calculate_cpu_load(
void)
542 if (tcb_curr_ptr != NULL)
544 tcb_curr_ptr->run_ticks += current_tick - tcb_curr_ptr->last_run_ticks;
547 if (tcb_high_rdy_ptr != NULL) {
548 tcb_high_rdy_ptr->last_run_ticks = current_tick;
562 uint8_t is_switch_needed = OS_FALSE;
566 const uint32_t const_tick = tick_count + (uint32_t)1;
570 tick_count = const_tick;
572 if (const_tick == (uint32_t)0U)
574 task_switch_delay_lists();
577 if (const_tick >= next_tick_to_unblock)
581 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
588 p_tcb = list_get_owner_of_head_item(dly_task_list_ptr);
589 item_value = list_item_get_value(&(p_tcb->state_list_item));
590 if (item_value > const_tick)
593 next_tick_to_unblock = item_value;
600 if (list_item_get_list_contain(&(p_tcb->event_list_item)) != NULL)
604 add_task_to_rdy_list(p_tcb);
605 if (p_tcb->prio < tcb_curr_ptr->prio)
607 tcb_high_rdy_ptr = p_tcb;
608 is_switch_needed = OS_TRUE;
615 if (list_get_num_item(&(rdy_task_list[highest_prio])) > 1u)
618 is_switch_needed = OS_TRUE;
621 if(is_switch_needed == OS_TRUE)
624#if (OS_CFG_USE_RUNTIME_STATS != 0u)
625 akos_thread_calculate_cpu_load();
629 return is_switch_needed;
638 if (tick_to_delay > (uint32_t)0U)
640 AKOS_CORE_ENTER_CRITICAL();
641 add_curr_task_to_delay_list(tick_to_delay, OS_FALSE);
642 port_trigger_PendSV();
643 AKOS_CORE_EXIT_CRITICAL();
653 tcb_curr_ptr = tcb_high_rdy_ptr;
656 sched_is_running = OS_TRUE;
657#if (OS_CFG_USE_RUNTIME_STATS != 0u)
658 if (tcb_curr_ptr != NULL)
660 tcb_curr_ptr->last_run_ticks = 0u;
667 if ((p_idle_ticks == NULL) || (p_total_ticks == NULL))
672#if (OS_CFG_USE_RUNTIME_STATS != 0u)
673 AKOS_CORE_ENTER_CRITICAL();
675 uint32_t current_tick = tick_count;
676 uint32_t idle_ticks = 0u;
678 if (tcb_curr_ptr != NULL)
680 tcb_curr_ptr->run_ticks += current_tick - tcb_curr_ptr->last_run_ticks;
681 tcb_curr_ptr->last_run_ticks = current_tick;
684 if (task_tcb_list != NULL)
686 if ((task_idle_id < task_tcb_list_len) && (task_tcb_list[task_idle_id] != NULL))
688 idle_ticks = task_tcb_list[task_idle_id]->run_ticks;
692 *p_idle_ticks = idle_ticks;
693 *p_total_ticks = current_tick;
695 AKOS_CORE_EXIT_CRITICAL();
704 return task_tcb_list_len;
709 if (p_snapshot == NULL)
714 p_snapshot->id = UINT8_MAX;
715#if (OS_CFG_USE_SHELL != 0u)
716 p_snapshot->name = NULL;
718 p_snapshot->prio = 0u;
719 p_snapshot->run_ticks = 0u;
721 if ((task_tcb_list == NULL) || (index >= task_tcb_list_len) || (task_tcb_list[index] == NULL))
726#if (OS_CFG_USE_RUNTIME_STATS != 0u)
727 AKOS_CORE_ENTER_CRITICAL();
729 uint32_t current_tick = tick_count;
731 if (tcb_curr_ptr != NULL)
733 tcb_curr_ptr->run_ticks += current_tick - tcb_curr_ptr->last_run_ticks;
734 tcb_curr_ptr->last_run_ticks = current_tick;
737 p_snapshot->id = task_tcb_list[index]->id;
738#if (OS_CFG_USE_SHELL != 0u)
739 p_snapshot->name = thread_get_name_by_id(task_tcb_list[index]->
id);
741 p_snapshot->prio = task_tcb_list[index]->prio;
742 p_snapshot->run_ticks = task_tcb_list[index]->run_ticks;
744 AKOS_CORE_EXIT_CRITICAL();
746 p_snapshot->id = task_tcb_list[index]->id;
747#if (OS_CFG_USE_SHELL != 0u)
748 p_snapshot->name = thread_get_name_by_id(task_tcb_list[index]->
id);
750 p_snapshot->prio = task_tcb_list[index]->prio;
763 AKOS_CORE_ENTER_CRITICAL();
764 if ((task_tcb_list == NULL) || (des_thread_id >= task_tcb_list_len) || (task_tcb_list[des_thread_id] == NULL))
766 core_assert(0,
"OS_ERR_THREAD_ID_INVALID");
767 AKOS_CORE_EXIT_CRITICAL();
770 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
773 core_assert(0,
"OS_ERR_THREAD_POST_MSG_TO_ITSELF");
774 AKOS_CORE_EXIT_CRITICAL();
778 switch (task_tcb_list[des_thread_id]->state)
788 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
792 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
793 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
795 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
800#if (OS_CFG_USE_RUNTIME_STATS != 0u)
801 akos_thread_calculate_cpu_load();
803 port_trigger_PendSV();
805 AKOS_CORE_EXIT_CRITICAL();
814 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
819 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
820 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
822 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
827#if (OS_CFG_USE_RUNTIME_STATS != 0u)
828 akos_thread_calculate_cpu_load();
830 port_trigger_PendSV();
832 AKOS_CORE_EXIT_CRITICAL();
840 AKOS_CORE_EXIT_CRITICAL();
852 AKOS_CORE_ENTER_CRITICAL();
853 if ((task_tcb_list == NULL) || (des_thread_id >= task_tcb_list_len) || (task_tcb_list[des_thread_id] == NULL))
855 core_assert(0,
"OS_ERR_THREAD_ID_INVALID");
856 AKOS_CORE_EXIT_CRITICAL();
860 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
863 core_assert(0,
"OS_ERR_THREAD_POST_MSG_TO_ITSELF");
864 AKOS_CORE_EXIT_CRITICAL();
868 switch (task_tcb_list[des_thread_id]->state)
874 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
878 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
879 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
881 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
886#if (OS_CFG_USE_RUNTIME_STATS != 0u)
887 akos_thread_calculate_cpu_load();
889 port_trigger_PendSV();
891 AKOS_CORE_EXIT_CRITICAL();
897 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
904 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
909 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
910 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
912 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
917#if (OS_CFG_USE_RUNTIME_STATS != 0u)
918 akos_thread_calculate_cpu_load();
920 port_trigger_PendSV();
922 AKOS_CORE_EXIT_CRITICAL();
927 AKOS_CORE_EXIT_CRITICAL();
939 AKOS_CORE_ENTER_CRITICAL();
941 if (time_out > (uint32_t)0U && p_msg == NULL)
943 add_curr_task_to_delay_list(time_out, OS_TRUE);
952 port_trigger_PendSV();
953 AKOS_CORE_EXIT_CRITICAL();
960 AKOS_CORE_EXIT_CRITICAL();
#define OS_CFG_SHELL_TASK_PRI
#define OS_CFG_TASK_MSG_Q_SIZE_NORMAL
#define OS_CFG_TASK_STK_SIZE_MIN
#define OS_CFG_SHELL_TASK_STK_SIZE
#define OS_CFG_SHELL_TASK_MSG_Q_SIZE
Kernel control and critical-section API.
uint32_t * akos_port_task_stack_init(uint32_t *p_stack, size_t stack_size, void(*pf_task)(void *), void *p_arg)
Build the initial Cortex-M thread stack frame.
Doubly-linked list types and APIs for scheduler internals.
void akos_list_item_init(list_item_t *const p_list_item)
Initialize list item linkage and ownership metadata.
void akos_list_init(list_t *const p_list)
Initialize list metadata and sentinel.
void * akos_list_get_owner_of_next_item(list_t *const p_list)
Get owner of next item and advance list cursor.
void akos_list_insert(list_t *const p_list, list_item_t *const p_list_item)
Insert item in ascending order by list_item::value.
void akos_list_insert_end(list_t *const p_list, list_item_t *const p_list_item)
Insert item at list tail.
uint16_t akos_list_remove(list_item_t *const p_list_item)
Remove item from containing list.
Static-heap allocator APIs.
void akos_memory_free(void *p_addr)
Free previously allocated memory block.
void * akos_memory_malloc(size_t size)
Allocate memory from OS heap.
msg_t * akos_message_queue_get(msg_queue_t *p_msg_q)
Dequeue next message.
void akos_message_queue_put_dynamic(msg_queue_t *p_msg_q, int32_t sig, void *p_content, uint8_t size)
Enqueue dynamic message with payload copy.
void akos_message_queue_init(msg_queue_t *p_msg_q, uint8_t size)
Initialize message queue.
void akos_message_queue_put_pure(msg_queue_t *p_msg_q, int32_t sig)
Enqueue pure signal message.
Priority bitmap scheduler helpers.
void akos_priority_insert(uint32_t prio)
Mark priority as ready.
void akos_priority_remove(uint32_t prio)
Clear priority from ready table.
uint32_t akos_priority_get_highest(void)
Get highest ready priority.
FIFO queue metadata for thread messaging.
msg_t * akos_thread_wait_for_msg(uint32_t time_out)
Wait for a message on current thread queue.
uint8_t akos_thread_get_timer_thread_id(void)
Get the runtime thread ID assigned to the timer thread.
void akos_thread_register_static_threads(void)
Create all statically defined application tasks plus system tasks.
uint8_t akos_thread_get_runtime_count(void)
Get number of runtime thread slots, including internal threads.
uint32_t akos_thread_get_tick(void)
Get current tick counter.
void akos_thread_start(void)
Start scheduler state variables.
uint8_t akos_thread_increment_tick(void)
Tick hook: unblock delayed tasks and select next runnable task.
uint8_t akos_thread_get_app_thread_count(void)
Get number of application threads defined via AKOS_THREAD_DEFINE.
void akos_thread_get_runtime_totals(uint32_t *p_idle_ticks, uint32_t *p_total_ticks)
Snapshot accumulated runtime counters.
void akos_thread_delay(const uint32_t tick_to_delay)
Delay current thread for a number of ticks.
void akos_thread_post_msg_dynamic(uint8_t des_thread_id, int32_t sig, void *p_content, uint8_t msg_size)
Post dynamic payload message to another thread.
uint8_t akos_thread_get_shell_thread_id(void)
Get the runtime thread ID assigned to the shell thread.
uint8_t akos_thread_get_idle_thread_id(void)
Get the runtime thread ID assigned to the idle thread.
void akos_thread_post_msg_pure(uint8_t des_thread_id, int32_t sig)
Post pure signal message to another thread.
void akos_thread_get_runtime_snapshot(uint8_t index, thread_runtime_snapshot_t *p_snapshot)
Snapshot one runtime thread slot by index.
Thread scheduling and thread messaging APIs.
void(* thread_func_t)(void *p_arg)
Thread entry function signature.
thread_state_t
Runtime state of a thread control block.
@ THREAD_STATE_DELAYED_ON_MSG
@ THREAD_STATE_SUSPENDED_ON_MSG
uint8_t thread_id_t
Numeric thread identifier type.
void akos_timer_processing()
Timer thread processing loop.