22#define TASK_IDLE_PRI (OS_CFG_PRIO_MAX - 1u)
24#define TASK_TIMER_PRI ((uint8_t)OS_CFG_TIMER_TASK_PRI)
26#define TASK_TIMER_STK_SIZE (100u)
31#define SIZE_OF_TCB (sizeof(task_tcb_t))
34task_tcb_t *
volatile tcb_curr_ptr = NULL;
35task_tcb_t *
volatile tcb_high_rdy_ptr = NULL;
38static list_t dly_task_list_1;
39static list_t dly_task_list_2;
40static list_t *
volatile dly_task_list_ptr;
41static list_t *
volatile overflow_dly_task_list_ptr;
42static list_t suspended_task_list;
44static volatile uint16_t num_of_tasks = (uint16_t)0U;
45static volatile uint32_t tick_count = (uint32_t)0u;
46static volatile uint32_t ticks_pended = (uint32_t)0U;
49static volatile uint8_t sched_is_running = (uint8_t)OS_FALSE;
51extern const thread_t __start_task_desc[] __attribute__((weak));
52extern const thread_t __stop_task_desc[] __attribute__((weak));
54static task_tcb_t **task_tcb_list = NULL;
55static uint8_t task_tcb_list_len = 0u;
56static uint8_t task_app_count = 0u;
57static uint8_t task_idle_id = 0u;
58static uint8_t task_timer_id = 0u;
71 return task_app_count;
88static void task_idle_func(
void *p_arg)
99static void task_timer_func(
void *p_arg)
109 volatile uint32_t *stk_ptr;
110 list_item_t state_list_item;
111 list_item_t event_list_item;
112 uint32_t *stk_limit_ptr;
115 uint32_t *stk_base_ptr;
117 msg_queue_t msg_queue;
124static void init_task_lists(
void)
135 dly_task_list_ptr = &dly_task_list_1;
136 overflow_dly_task_list_ptr = &dly_task_list_2;
143static void task_switch_delay_lists()
146 p_list_temp = dly_task_list_ptr;
147 dly_task_list_ptr = overflow_dly_task_list_ptr;
148 overflow_dly_task_list_ptr = p_list_temp;
150 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
164 task_tcb_t *p_tcb = list_get_owner_of_head_item(dly_task_list_ptr);
165 uint32_t item_value = list_item_get_value(&(p_tcb->state_list_item));
166 next_tick_to_unblock = item_value;
174static void add_new_task_to_rdy_list(task_tcb_t *p_tcb)
176 AKOS_CORE_ENTER_CRITICAL();
179 if (num_of_tasks == 1)
182 tcb_curr_ptr = p_tcb;
186 if (tcb_curr_ptr->prio <= p_tcb->prio)
188 tcb_curr_ptr = p_tcb;
192 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
199 AKOS_CORE_EXIT_CRITICAL();
206static void add_task_to_rdy_list(task_tcb_t *p_tcb)
209 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
222static void add_curr_task_to_delay_list(uint32_t tick_to_delay, uint8_t can_block_indefinitely)
224 uint32_t time_to_wake;
225 const uint32_t const_tick = tick_count;
230 if ((tick_to_delay ==
OS_CFG_DELAY_MAX) && (can_block_indefinitely != OS_FALSE))
241 time_to_wake = const_tick + tick_to_delay;
242 list_item_set_value(&(tcb_curr_ptr->state_list_item), time_to_wake);
244 if (time_to_wake < const_tick)
248 akos_list_insert(overflow_dly_task_list_ptr, &(tcb_curr_ptr->state_list_item));
260 if (time_to_wake < next_tick_to_unblock)
262 next_tick_to_unblock = time_to_wake;
269 tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[highest_prio]));
292 if (sched_is_running == OS_TRUE)
295 core_assert(0,
"OS_ERR_SCHED_IS_RUNNING");
301 core_assert(0,
"OS_ERR_TCB_PRIO_INVALID");
304 if (pf_thread == NULL)
307 core_assert(0,
"OS_ERR_TCB_FUNC_INVALID");
313 core_assert(0,
"OS_ERR_TCB_STK_SIZE_INVALID");
316 if ((task_tcb_list == NULL) || (
id >= task_tcb_list_len))
318 core_assert(0,
"OS_ERR_TASK_ID_INVALID");
321 if (task_tcb_list[
id] != NULL)
323 core_assert(0,
"OS_ERR_TASK_ID_ALREADY_USED");
328 task_tcb_t *p_new_tcb;
335 if (p_new_tcb != NULL)
337 memset((
void *)p_new_tcb, 0x00, SIZE_OF_TCB);
340 p_new_tcb->stk_limit_ptr = p_stack;
346 core_assert(0,
"OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
353 core_assert(0,
"OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
358 uint32_t *p_stack_ptr;
370 p_new_tcb->stk_ptr = p_stack_ptr;
373 p_new_tcb->stk_size = stack_size;
379 p_new_tcb->prio = prio;
388 list_item_set_owner(&(p_new_tcb->state_list_item), (
void *)p_new_tcb);
389 list_item_set_owner(&(p_new_tcb->event_list_item), (
void *)p_new_tcb);
391 list_item_set_value(&(p_new_tcb->state_list_item), prio);
393 add_new_task_to_rdy_list(p_new_tcb);
394 task_tcb_list[id] = p_new_tcb;
404 const thread_t *p_thread_desc = __start_task_desc;
405 const thread_t *p_thread_desc_end = __stop_task_desc;
406 size_t app_count = 0u;
408 if ((p_thread_desc == NULL) || (p_thread_desc_end == NULL) || (p_thread_desc == p_thread_desc_end))
414 app_count = (size_t)(p_thread_desc_end - p_thread_desc);
417 if (app_count > (
size_t)(UINT8_MAX - 2u))
419 core_assert(0,
"OS_ERR_TOO_MANY_TASKS");
423 task_app_count = (uint8_t)app_count;
424 task_idle_id = task_app_count;
425 task_timer_id = (uint8_t)(task_app_count + 1u);
426 task_tcb_list_len = (uint8_t)(task_app_count + 2u);
428 task_tcb_list = (task_tcb_t **)
akos_memory_malloc(
sizeof(task_tcb_t *) * task_tcb_list_len);
429 if (task_tcb_list == NULL)
431 core_assert(0,
"OS_ERR_TASK_TCB_TABLE_ALLOC");
434 memset(task_tcb_list, 0x00,
sizeof(task_tcb_t *) * task_tcb_list_len);
436 for (; p_thread_desc < p_thread_desc_end; ++p_thread_desc)
438 if (p_thread_desc->id >= task_app_count)
440 core_assert(0,
"OS_ERR_THREAD_ID_RESERVED");
444 (void)task_create(p_thread_desc->id,
445 p_thread_desc->pf_thread,
446 p_thread_desc->p_arg,
448 p_thread_desc->queue_size,
449 p_thread_desc->stack_size);
455 (uint8_t)TASK_TIMER_PRI,
457 (
size_t)TASK_TIMER_STK_SIZE);
462 (uint8_t)TASK_IDLE_PRI,
473 uint8_t is_switch_needed = OS_FALSE;
477 const uint32_t const_tick = tick_count + (uint32_t)1;
481 tick_count = const_tick;
483 if (const_tick == (uint32_t)0U)
485 task_switch_delay_lists();
488 if (const_tick >= next_tick_to_unblock)
492 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
499 p_tcb = list_get_owner_of_head_item(dly_task_list_ptr);
500 item_value = list_item_get_value(&(p_tcb->state_list_item));
501 if (item_value > const_tick)
504 next_tick_to_unblock = item_value;
511 if (list_item_get_list_contain(&(p_tcb->event_list_item)) != NULL)
515 add_task_to_rdy_list(p_tcb);
516 if (p_tcb->prio < tcb_curr_ptr->prio)
518 tcb_high_rdy_ptr = p_tcb;
519 is_switch_needed = OS_TRUE;
526 if (list_get_num_item(&(rdy_task_list[highest_prio])) > 1u)
529 is_switch_needed = OS_TRUE;
534 return is_switch_needed;
543 if (tick_to_delay > (uint32_t)0U)
545 AKOS_CORE_ENTER_CRITICAL();
546 add_curr_task_to_delay_list(tick_to_delay, OS_FALSE);
547 port_trigger_PendSV();
548 AKOS_CORE_EXIT_CRITICAL();
558 tcb_curr_ptr = tcb_high_rdy_ptr;
561 sched_is_running = OS_TRUE;
573 AKOS_CORE_ENTER_CRITICAL();
574 if ((task_tcb_list == NULL) || (des_thread_id >= task_tcb_list_len) || (task_tcb_list[des_thread_id] == NULL))
576 core_assert(0,
"OS_ERR_THREAD_ID_INVALID");
577 AKOS_CORE_EXIT_CRITICAL();
580 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
583 core_assert(0,
"OS_ERR_THREAD_POST_MSG_TO_ITSELF");
584 AKOS_CORE_EXIT_CRITICAL();
588 switch (task_tcb_list[des_thread_id]->state)
598 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
602 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
603 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
605 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
610 port_trigger_PendSV();
612 AKOS_CORE_EXIT_CRITICAL();
621 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
626 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
627 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
629 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
634 port_trigger_PendSV();
636 AKOS_CORE_EXIT_CRITICAL();
644 AKOS_CORE_EXIT_CRITICAL();
656 AKOS_CORE_ENTER_CRITICAL();
657 if ((task_tcb_list == NULL) || (des_thread_id >= task_tcb_list_len) || (task_tcb_list[des_thread_id] == NULL))
659 core_assert(0,
"OS_ERR_THREAD_ID_INVALID");
660 AKOS_CORE_EXIT_CRITICAL();
664 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
667 core_assert(0,
"OS_ERR_THREAD_POST_MSG_TO_ITSELF");
668 AKOS_CORE_EXIT_CRITICAL();
672 switch (task_tcb_list[des_thread_id]->state)
678 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
682 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
683 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
685 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
690 port_trigger_PendSV();
692 AKOS_CORE_EXIT_CRITICAL();
698 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
705 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
710 add_task_to_rdy_list(task_tcb_list[des_thread_id]);
711 if (task_tcb_list[des_thread_id]->prio < tcb_curr_ptr->prio)
713 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
718 port_trigger_PendSV();
720 AKOS_CORE_EXIT_CRITICAL();
725 AKOS_CORE_EXIT_CRITICAL();
737 AKOS_CORE_ENTER_CRITICAL();
739 if (time_out > (uint32_t)0U && p_msg == NULL)
741 add_curr_task_to_delay_list(time_out, OS_TRUE);
750 port_trigger_PendSV();
751 AKOS_CORE_EXIT_CRITICAL();
758 AKOS_CORE_EXIT_CRITICAL();
#define OS_CFG_TASK_MSG_Q_SIZE_NORMAL
#define OS_CFG_TASK_STK_SIZE_MIN
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.
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_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_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.
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.