AKOS  v1.0.0
Documentation
Loading...
Searching...
No Matches
thread.c
Go to the documentation of this file.
1/****************************************************************************/
12
13#include "thread.h"
14#include "core.h"
15#include "list.h"
16#include "memory.h"
17#include "shell.h"
18#include "timer.h"
19#include "priority.h"
20#include "port.h"
21#include <string.h>
22
23#define TASK_IDLE_PRI (OS_CFG_PRIO_MAX - 1u)
24
25#define TASK_TIMER_PRI ((uint8_t)OS_CFG_TIMER_TASK_PRI)
26
27#define TASK_TIMER_STK_SIZE (100u)
28
29
30typedef struct task_tcb task_tcb_t;
31
32#define SIZE_OF_TCB (sizeof(task_tcb_t))
33
34
35task_tcb_t *volatile tcb_curr_ptr = NULL;
36task_tcb_t *volatile tcb_high_rdy_ptr = NULL;
37
38static list_t rdy_task_list[OS_CFG_PRIO_MAX]; /*< Prioritised ready tasks. */
39static list_t dly_task_list_1; /*< Delayed tasks. */
40static list_t dly_task_list_2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
41static list_t *volatile dly_task_list_ptr; /*< Points to the delayed task list currently being used. */
42static list_t *volatile overflow_dly_task_list_ptr; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
43static list_t suspended_task_list; /*< Tasks that are currently suspended. */
44
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;
48static volatile uint32_t next_tick_to_unblock = (uint32_t)OS_CFG_DELAY_MAX; /* Initialised to portMAX_DELAY before the scheduler starts. */
49
50static volatile uint8_t sched_is_running = (uint8_t)OS_FALSE;
51
52extern const thread_t __start_task_desc[] __attribute__((weak));
53extern const thread_t __stop_task_desc[] __attribute__((weak));
54
55static task_tcb_t **task_tcb_list = NULL; /*< Holds the list of task TCBs. */
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;
61
67{
68 return tick_count;
69}
70
72{
73 return task_app_count;
74}
75
77{
78 return task_idle_id;
79}
80
82{
83 return task_shell_id;
84}
85
87{
88 return task_timer_id;
89}
90
95static void task_idle_func(void *p_arg)
96{
97 (void)p_arg;
98
99 for (;;)
100 {
101 }
102}
103
108static void task_timer_func(void *p_arg)
109{
110 (void)p_arg;
111
112 for (;;)
113 {
115 }
116}
117
119{
120 volatile uint32_t *stk_ptr; /* Stack pointer, has to be the first member of TCB */
121 list_item_t state_list_item; /*Item in StateList include Ready, Blocked, Suspended List */
122 list_item_t event_list_item; /*Item in Event List */
123 uint32_t *stk_limit_ptr; /* Pointer used to set stack 'watermark' limit */
124 uint8_t prio;
125 size_t stk_size; /* Size of task stack (in number of stack elements) */
126 uint32_t *stk_base_ptr; /* Pointer to base address of stack */
127 thread_id_t id;
128 msg_queue_t msg_queue;
129 thread_state_t state; /* States */
130
131 /* Runtime stats */
132 uint32_t run_ticks; /* accumulated running ticks */
133 uint32_t last_run_ticks; /* snapshot for load calculation */
134 uint8_t cpu_load; /* 0 - 100 percent */
135};
136
137#if (OS_CFG_USE_SHELL != 0u)
138static const char *thread_get_name_by_id(thread_id_t id)
139{
140 const thread_t *p_thread_desc = __start_task_desc;
141
142 for (; p_thread_desc < __stop_task_desc; ++p_thread_desc)
143 {
144 if (p_thread_desc->id == id)
145 {
146 return p_thread_desc->name;
147 }
148 }
149
150 if (id == task_shell_id)
151 {
152 return "shell";
153 }
154 if (id == task_timer_id)
155 {
156 return "timer";
157 }
158 if (id == task_idle_id)
159 {
160 return "idle";
161 }
162
163 return NULL;
164}
165#endif
166
167#if (OS_CFG_USE_RUNTIME_STATS != 0u)
168static void akos_thread_calculate_cpu_load(void);
169#endif
170
174static void init_task_lists(void)
175{
176 /* Initialize lists */
177 uint8_t prio;
178 for (prio = 0; prio < OS_CFG_PRIO_MAX; prio++)
179 {
180 akos_list_init(&(rdy_task_list[prio]));
181 }
182 akos_list_init(&dly_task_list_1);
183 akos_list_init(&dly_task_list_2);
184 akos_list_init(&suspended_task_list);
185 dly_task_list_ptr = &dly_task_list_1;
186 overflow_dly_task_list_ptr = &dly_task_list_2;
187 /********************/
188}
189
193static void task_switch_delay_lists()
194{
195 list_t *p_list_temp;
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;
199
200 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
201 {
202 /* The new current delayed list is empty. Set xNextTaskUnblockTime to
203 * the maximum possible value so it is extremely unlikely that the
204 * if( xTickCount >= xNextTaskUnblockTime ) test will pass until
205 * there is an item in the delayed list. */
206 next_tick_to_unblock = OS_CFG_DELAY_MAX;
207 }
208 else
209 {
210 /* The new current delayed list is not empty, get the value of
211 * the item at the head of the delayed list. This is the time at
212 * which the task at the head of the delayed list should be removed
213 * from the Blocked state. */
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;
217 }
218}
219
224static void add_new_task_to_rdy_list(task_tcb_t *p_tcb)
225{
226 AKOS_CORE_ENTER_CRITICAL();
227 {
228 num_of_tasks++;
229 if (num_of_tasks == 1)
230 {
231 init_task_lists();
232 tcb_curr_ptr = p_tcb;
233 }
234 else
235 {
236 if (tcb_curr_ptr->prio <= p_tcb->prio)
237 {
238 tcb_curr_ptr = p_tcb;
239 }
240 }
241 akos_list_insert_end(&(rdy_task_list[p_tcb->prio]), &((p_tcb)->state_list_item));
242 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
243 {
244 akos_priority_insert(p_tcb->prio);
245 }
246 /*Save state*/
247 p_tcb->state = THREAD_STATE_READY;
248 }
249 AKOS_CORE_EXIT_CRITICAL();
250}
251
256static void add_task_to_rdy_list(task_tcb_t *p_tcb)
257{
258 akos_list_insert_end(&(rdy_task_list[p_tcb->prio]), &((p_tcb)->state_list_item));
259 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
260 {
261 akos_priority_insert(p_tcb->prio);
262 }
263 /*Save state*/
264 p_tcb->state = THREAD_STATE_READY;
265}
266
272static void add_curr_task_to_delay_list(uint32_t tick_to_delay, uint8_t can_block_indefinitely)
273{
274 uint32_t time_to_wake;
275 const uint32_t const_tick = tick_count;
276 if (akos_list_remove(&(tcb_curr_ptr->state_list_item)) == 0u)
277 {
278 akos_priority_remove(tcb_curr_ptr->prio);
279 }
280 if ((tick_to_delay == OS_CFG_DELAY_MAX) && (can_block_indefinitely != OS_FALSE))
281 {
282 /* Add the task to the suspended task list instead of a delayed task
283 * list to ensure it is not woken by a timing event. It will block
284 * indefinitely. */
285 akos_list_insert_end(&suspended_task_list, &(tcb_curr_ptr->state_list_item));
286 /*Save state*/
287 tcb_curr_ptr->state = THREAD_STATE_SUSPENDED;
288 }
289 else
290 {
291 time_to_wake = const_tick + tick_to_delay;
292 list_item_set_value(&(tcb_curr_ptr->state_list_item), time_to_wake);
293
294 if (time_to_wake < const_tick)
295 {
296 /* Wake time has overflowed. Place this item in the overflow
297 * list. */
298 akos_list_insert(overflow_dly_task_list_ptr, &(tcb_curr_ptr->state_list_item));
299 }
300 else
301 {
302 /* The wake time has not overflowed, so the current block list
303 * is used. */
304 akos_list_insert(dly_task_list_ptr, &(tcb_curr_ptr->state_list_item));
305
306 /*Update next tick to block is important in order scheduler not to miss this stamp
307 Just update next tick to block in this branch because overflow delay is just the background list
308 */
309
310 if (time_to_wake < next_tick_to_unblock)
311 {
312 next_tick_to_unblock = time_to_wake;
313 }
314 }
315 /*Save state*/
316 tcb_curr_ptr->state = THREAD_STATE_DELAYED;
317 }
318 uint8_t highest_prio = akos_priority_get_highest();
319 tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[highest_prio]));
320
321 /*Save state*/
322 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
323#if (OS_CFG_USE_RUNTIME_STATS != 0u)
324 akos_thread_calculate_cpu_load();
325#endif
326}
327
338static task_tcb_t *task_create(thread_id_t id,
339 thread_func_t pf_thread,
340 void *p_arg,
341 uint8_t prio,
342 size_t queue_size,
343 size_t stack_size)
344{
345 if (sched_is_running == OS_TRUE)
346 {
347 // OSUniversalError = OS_ERR_SCHED_IS_RUNNING;
348 core_assert(0, "OS_ERR_SCHED_IS_RUNNING");
349 return NULL;
350 }
351 if (prio > (OS_CFG_PRIO_MAX - 1U))
352 {
353 // OSUniversalError = OS_ERR_TCB_PRIO_INVALID;
354 core_assert(0, "OS_ERR_TCB_PRIO_INVALID");
355 return NULL;
356 }
357 if (pf_thread == NULL)
358 {
359 // OSUniversalError = OS_ERR_TCB_FUNC_INVALID;
360 core_assert(0, "OS_ERR_TCB_FUNC_INVALID");
361 return NULL;
362 }
363 if (stack_size < OS_CFG_TASK_STK_SIZE_MIN)
364 {
365 // OSUniversalError = OS_ERR_TCB_STK_SIZE_INVALID;
366 core_assert(0, "OS_ERR_TCB_STK_SIZE_INVALID");
367 return NULL;
368 }
369 if ((task_tcb_list == NULL) || (id >= task_tcb_list_len))
370 {
371 core_assert(0, "OS_ERR_TASK_ID_INVALID");
372 return NULL;
373 }
374 if (task_tcb_list[id] != NULL)
375 {
376 core_assert(0, "OS_ERR_TASK_ID_ALREADY_USED");
377 return NULL;
378 }
379
380
381 task_tcb_t *p_new_tcb;
382 uint32_t *p_stack;
383
384 p_stack = akos_memory_malloc(stack_size * sizeof(uint32_t));
385 if (p_stack != NULL)
386 {
387 p_new_tcb = (task_tcb_t *)akos_memory_malloc(SIZE_OF_TCB);
388 if (p_new_tcb != NULL)
389 {
390 memset((void *)p_new_tcb, 0x00, SIZE_OF_TCB);
391
392 /*Save stack limit pointer*/
393 p_new_tcb->stk_limit_ptr = p_stack;
394 }
395 else
396 {
397 akos_memory_free(p_stack);
398 // OSUniversalError = OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC;
399 core_assert(0, "OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
400 return NULL;
401 }
402 }
403 else
404 {
405 // OSUniversalError = OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC;
406 core_assert(0, "OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
407 return NULL;
408 }
409
410 /*Now TCB and stack are created*/
411 uint32_t *p_stack_ptr;
412
413 /* Fill the stack with a known value to assist debugging. */
414 //( void ) memset( p_new_tcb->stk_limit_ptr, OS_CFG_TASK_STACK_FILL_BYTE, stack_size );
415
416 /*Init stack frame*/
417 p_stack_ptr = akos_port_task_stack_init(p_stack,
418 stack_size,
419 pf_thread,
420 p_arg);
421
422 /*Save top of stack (Stack pointer)*/
423 p_new_tcb->stk_ptr = p_stack_ptr;
424
425 /*Save stack size*/
426 p_new_tcb->stk_size = stack_size;
427
428 /*Save ID*/
429 p_new_tcb->id = id;
430
431 /*Save prio*/
432 p_new_tcb->prio = prio;
433 // akos_priority_insert(prio);
434
435 akos_message_queue_init(&(p_new_tcb->msg_queue), queue_size);
436
437 /* Init linked lists */
438 akos_list_item_init(&(p_new_tcb->state_list_item));
439 akos_list_item_init(&(p_new_tcb->event_list_item));
440
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);
443
444 list_item_set_value(&(p_new_tcb->state_list_item), prio);
445
446 add_new_task_to_rdy_list(p_new_tcb);
447 task_tcb_list[id] = p_new_tcb;
448
449 return p_new_tcb;
450}
451
456{
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;
460
461 if ((p_thread_desc == NULL) || (p_thread_desc_end == NULL) || (p_thread_desc == p_thread_desc_end))
462 {
463 /* No application threads were linked in. */
464 }
465 else
466 {
467 app_count = (size_t)(p_thread_desc_end - p_thread_desc);
468 }
469
470 if (app_count > (size_t)(UINT8_MAX - 3u))
471 {
472 core_assert(0, "OS_ERR_TOO_MANY_TASKS");
473 return;
474 }
475
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);
482#else
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);
487#endif
488
489 task_tcb_list = (task_tcb_t **)akos_memory_malloc(sizeof(task_tcb_t *) * task_tcb_list_len);
490 if (task_tcb_list == NULL)
491 {
492 core_assert(0, "OS_ERR_TASK_TCB_TABLE_ALLOC");
493 return;
494 }
495 memset(task_tcb_list, 0x00, sizeof(task_tcb_t *) * task_tcb_list_len);
496
497 for (; p_thread_desc < p_thread_desc_end; ++p_thread_desc)
498 {
499 if (p_thread_desc->id >= task_app_count)
500 {
501 core_assert(0, "OS_ERR_THREAD_ID_RESERVED");
502 continue;
503 }
504
505 (void)task_create(p_thread_desc->id,
506 p_thread_desc->pf_thread,
507 p_thread_desc->p_arg,
508 p_thread_desc->prio,
509 p_thread_desc->queue_size,
510 p_thread_desc->stack_size);
511 }
512
513#if (OS_CFG_USE_SHELL != 0u)
514 (void)task_create((thread_id_t)task_shell_id,
515 (thread_func_t)akos_shell_thread,
516 (void *)NULL,
517 (uint8_t)OS_CFG_SHELL_TASK_PRI,
520#endif
521
522 (void)task_create((thread_id_t)task_timer_id,
523 (thread_func_t)task_timer_func,
524 (void *)NULL,
525 (uint8_t)TASK_TIMER_PRI,
527 (size_t)TASK_TIMER_STK_SIZE);
528
529 (void)task_create((thread_id_t)task_idle_id,
530 (thread_func_t)task_idle_func,
531 (void *)NULL,
532 (uint8_t)TASK_IDLE_PRI,
533 (size_t)(0u),
535}
536
537#if (OS_CFG_USE_RUNTIME_STATS != 0u)
538static void akos_thread_calculate_cpu_load(void)
539{
540 uint32_t current_tick = akos_thread_get_tick();
541
542 if (tcb_curr_ptr != NULL)
543 {
544 tcb_curr_ptr->run_ticks += current_tick - tcb_curr_ptr->last_run_ticks;
545 }
546
547 if (tcb_high_rdy_ptr != NULL) {
548 tcb_high_rdy_ptr->last_run_ticks = current_tick;
549 }
550}
551#endif
552
553
554
555
561{
562 uint8_t is_switch_needed = OS_FALSE;
563 task_tcb_t *p_tcb;
564 uint32_t item_value;
565
566 const uint32_t const_tick = tick_count + (uint32_t)1;
567
568 /* Increment the RTOS tick, switching the delayed and overflowed
569 * delayed lists if it wraps to 0. */
570 tick_count = const_tick;
571
572 if (const_tick == (uint32_t)0U) /* Overflowed, switch delaylist*/
573 {
574 task_switch_delay_lists();
575 }
576
577 if (const_tick >= next_tick_to_unblock)
578 {
579 for (;;)
580 {
581 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
582 {
583 next_tick_to_unblock = OS_CFG_DELAY_MAX;
584 break;
585 }
586 else
587 {
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)
591 {
592 /* Stop condition */
593 next_tick_to_unblock = item_value;
594 break;
595 }
596 akos_list_remove(&(p_tcb->state_list_item)); /*Remove from block state*/
597
598 /* Is the task waiting on an event also? If so remove
599 * it from the event list. */
600 if (list_item_get_list_contain(&(p_tcb->event_list_item)) != NULL)
601 {
602 akos_list_remove(&(p_tcb->event_list_item));
603 }
604 add_task_to_rdy_list(p_tcb);
605 if (p_tcb->prio < tcb_curr_ptr->prio)
606 {
607 tcb_high_rdy_ptr = p_tcb;
608 is_switch_needed = OS_TRUE;
609 }
610 }
611 }
612 }
613
614 uint8_t highest_prio = akos_priority_get_highest();
615 if (list_get_num_item(&(rdy_task_list[highest_prio])) > 1u)
616 {
617 tcb_high_rdy_ptr = akos_list_get_owner_of_next_item(&(rdy_task_list[highest_prio]));
618 is_switch_needed = OS_TRUE;
619 }
620 /*Save state*/
621 if(is_switch_needed == OS_TRUE)
622 {
623 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
624#if (OS_CFG_USE_RUNTIME_STATS != 0u)
625 akos_thread_calculate_cpu_load();
626#endif
627 }
628
629 return is_switch_needed;
630}
631
636void akos_thread_delay(const uint32_t tick_to_delay)
637{
638 if (tick_to_delay > (uint32_t)0U)
639 {
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();
644 }
645}
646
651{
652 tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[akos_priority_get_highest()]));
653 tcb_curr_ptr = tcb_high_rdy_ptr;
654 tick_count = 0u;
655 next_tick_to_unblock = OS_CFG_DELAY_MAX;
656 sched_is_running = OS_TRUE;
657#if (OS_CFG_USE_RUNTIME_STATS != 0u)
658 if (tcb_curr_ptr != NULL)
659 {
660 tcb_curr_ptr->last_run_ticks = 0u;
661 }
662#endif
663}
664
665void akos_thread_get_runtime_totals(uint32_t *p_idle_ticks, uint32_t *p_total_ticks)
666{
667 if ((p_idle_ticks == NULL) || (p_total_ticks == NULL))
668 {
669 return;
670 }
671
672#if (OS_CFG_USE_RUNTIME_STATS != 0u)
673 AKOS_CORE_ENTER_CRITICAL();
674 {
675 uint32_t current_tick = tick_count;
676 uint32_t idle_ticks = 0u;
677
678 if (tcb_curr_ptr != NULL)
679 {
680 tcb_curr_ptr->run_ticks += current_tick - tcb_curr_ptr->last_run_ticks;
681 tcb_curr_ptr->last_run_ticks = current_tick;
682 }
683
684 if (task_tcb_list != NULL)
685 {
686 if ((task_idle_id < task_tcb_list_len) && (task_tcb_list[task_idle_id] != NULL))
687 {
688 idle_ticks = task_tcb_list[task_idle_id]->run_ticks;
689 }
690 }
691
692 *p_idle_ticks = idle_ticks;
693 *p_total_ticks = current_tick;
694 }
695 AKOS_CORE_EXIT_CRITICAL();
696#else
697 *p_idle_ticks = 0u;
698 *p_total_ticks = 0u;
699#endif
700}
701
703{
704 return task_tcb_list_len;
705}
706
708{
709 if (p_snapshot == NULL)
710 {
711 return;
712 }
713
714 p_snapshot->id = UINT8_MAX;
715#if (OS_CFG_USE_SHELL != 0u)
716 p_snapshot->name = NULL;
717#endif
718 p_snapshot->prio = 0u;
719 p_snapshot->run_ticks = 0u;
720
721 if ((task_tcb_list == NULL) || (index >= task_tcb_list_len) || (task_tcb_list[index] == NULL))
722 {
723 return;
724 }
725
726#if (OS_CFG_USE_RUNTIME_STATS != 0u)
727 AKOS_CORE_ENTER_CRITICAL();
728 {
729 uint32_t current_tick = tick_count;
730
731 if (tcb_curr_ptr != NULL)
732 {
733 tcb_curr_ptr->run_ticks += current_tick - tcb_curr_ptr->last_run_ticks;
734 tcb_curr_ptr->last_run_ticks = current_tick;
735 }
736
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);
740#endif
741 p_snapshot->prio = task_tcb_list[index]->prio;
742 p_snapshot->run_ticks = task_tcb_list[index]->run_ticks;
743 }
744 AKOS_CORE_EXIT_CRITICAL();
745#else
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);
749#endif
750 p_snapshot->prio = task_tcb_list[index]->prio;
751#endif
752}
753
761void akos_thread_post_msg_dynamic(uint8_t des_thread_id, int32_t sig, void *p_content, uint8_t msg_size)
762{
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))
765 {
766 core_assert(0, "OS_ERR_THREAD_ID_INVALID");
767 AKOS_CORE_EXIT_CRITICAL();
768 return;
769 }
770 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
771 {
772 // OSUniversalError = OS_ERR_THREAD_POST_MSG_TO_ITSELF;
773 core_assert(0, "OS_ERR_THREAD_POST_MSG_TO_ITSELF");
774 AKOS_CORE_EXIT_CRITICAL();
775 return;
776 }
777
778 switch (task_tcb_list[des_thread_id]->state)
779 {
781 akos_message_queue_put_dynamic(&(task_tcb_list[des_thread_id]->msg_queue),
782 sig,
783 p_content,
784 msg_size);
785
786 /* Is the thread waiting on an event ? If so remove
787 * it from the event list. */
788 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
789 {
790 akos_list_remove(&(task_tcb_list[des_thread_id]->event_list_item));
791 }
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)
794 {
795 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
796
797 /*Save state*/
798 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
799
800#if (OS_CFG_USE_RUNTIME_STATS != 0u)
801 akos_thread_calculate_cpu_load();
802#endif
803 port_trigger_PendSV();
804 }
805 AKOS_CORE_EXIT_CRITICAL();
806 break;
808 akos_message_queue_put_dynamic(&(task_tcb_list[des_thread_id]->msg_queue),
809 sig,
810 p_content,
811 msg_size);
812 /* Is the thread waiting on an event ? If so remove
813 * it from the event list. */
814 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
815 {
816 akos_list_remove(&(task_tcb_list[des_thread_id]->state_list_item));
817 }
818
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)
821 {
822 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
823
824 /*Save state*/
825 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
826
827#if (OS_CFG_USE_RUNTIME_STATS != 0u)
828 akos_thread_calculate_cpu_load();
829#endif
830 port_trigger_PendSV();
831 }
832 AKOS_CORE_EXIT_CRITICAL();
833 break;
834
835 default:
836 akos_message_queue_put_dynamic(&(task_tcb_list[des_thread_id]->msg_queue),
837 sig,
838 p_content,
839 msg_size);
840 AKOS_CORE_EXIT_CRITICAL();
841 break;
842 }
843}
844
850void akos_thread_post_msg_pure(uint8_t des_thread_id, int32_t sig)
851{
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))
854 {
855 core_assert(0, "OS_ERR_THREAD_ID_INVALID");
856 AKOS_CORE_EXIT_CRITICAL();
857 return;
858 }
859#if 0 /* Under testing */
860 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
861 {
862 // OSUniversalError = OS_ERR_THREAD_POST_MSG_TO_ITSELF;
863 core_assert(0, "OS_ERR_THREAD_POST_MSG_TO_ITSELF");
864 AKOS_CORE_EXIT_CRITICAL();
865 return;
866 }
867#endif
868 switch (task_tcb_list[des_thread_id]->state)
869 {
871 akos_message_queue_put_pure(&(task_tcb_list[des_thread_id]->msg_queue), sig);
872 /* Is the thread waiting on an event ? If so remove
873 * it from the event list. */
874 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
875 {
876 akos_list_remove(&(task_tcb_list[des_thread_id]->event_list_item));
877 }
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)
880 {
881 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
882
883 /*Save state*/
884 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
885
886#if (OS_CFG_USE_RUNTIME_STATS != 0u)
887 akos_thread_calculate_cpu_load();
888#endif
889 port_trigger_PendSV();
890 }
891 AKOS_CORE_EXIT_CRITICAL();
892 break;
894 akos_message_queue_put_pure(&(task_tcb_list[des_thread_id]->msg_queue), sig);
895 /* Is the thread waiting on an event ? If so remove
896 * it from the event list. */
897 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
898 {
899 akos_list_remove(&(task_tcb_list[des_thread_id]->state_list_item));
900 }
901
902 /* Is the thread waiting on an event also? If so remove
903 * it from the event list. */
904 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
905 {
906 akos_list_remove(&(task_tcb_list[des_thread_id]->event_list_item));
907 }
908
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)
911 {
912 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
913
914 /*Save state*/
915 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
916
917#if (OS_CFG_USE_RUNTIME_STATS != 0u)
918 akos_thread_calculate_cpu_load();
919#endif
920 port_trigger_PendSV();
921 }
922 AKOS_CORE_EXIT_CRITICAL();
923 break;
924
925 default: /*DELAYED, SUSPEND, RUNNING*/
926 akos_message_queue_put_pure(&(task_tcb_list[des_thread_id]->msg_queue), sig);
927 AKOS_CORE_EXIT_CRITICAL();
928 break;
929 }
930}
931
937msg_t *akos_thread_wait_for_msg(uint32_t time_out)
938{
939 AKOS_CORE_ENTER_CRITICAL();
940 msg_t *p_msg = akos_message_queue_get(&(task_tcb_list[tcb_curr_ptr->id]->msg_queue));
941 if (time_out > (uint32_t)0U && p_msg == NULL)
942 {
943 add_curr_task_to_delay_list(time_out, OS_TRUE); // Can block indefinitely
944 if (time_out == OS_CFG_DELAY_MAX)
945 {
946 tcb_curr_ptr->state = THREAD_STATE_SUSPENDED_ON_MSG;
947 }
948 else
949 {
950 tcb_curr_ptr->state = THREAD_STATE_DELAYED_ON_MSG;
951 }
952 port_trigger_PendSV();
953 AKOS_CORE_EXIT_CRITICAL();
954
955 p_msg = akos_message_queue_get(&(task_tcb_list[tcb_curr_ptr->id]->msg_queue));
956 return p_msg;
957 }
958 else
959 {
960 AKOS_CORE_EXIT_CRITICAL();
961 return p_msg;
962 }
963}
#define OS_CFG_SHELL_TASK_PRI
Definition config.h:49
#define OS_CFG_TASK_MSG_Q_SIZE_NORMAL
Definition config.h:32
#define OS_CFG_TASK_STK_SIZE_MIN
Definition config.h:30
#define OS_CFG_SHELL_TASK_STK_SIZE
Definition config.h:51
#define OS_CFG_PRIO_MAX
Definition config.h:26
#define OS_CFG_SHELL_TASK_MSG_Q_SIZE
Definition config.h:50
#define OS_CFG_DELAY_MAX
Definition config.h:27
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.
Definition port.c:69
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.
Definition list.c:35
void akos_list_init(list_t *const p_list)
Initialize list metadata and sentinel.
Definition list.c:20
void * akos_list_get_owner_of_next_item(list_t *const p_list)
Get owner of next item and advance list cursor.
Definition list.c:169
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.
Definition list.c:104
void akos_list_insert_end(list_t *const p_list, list_item_t *const p_list_item)
Insert item at list tail.
Definition list.c:45
uint16_t akos_list_remove(list_item_t *const p_list_item)
Remove item from containing list.
Definition list.c:141
Static-heap allocator APIs.
void akos_memory_free(void *p_addr)
Free previously allocated memory block.
Definition memory.c:144
void * akos_memory_malloc(size_t size)
Allocate memory from OS heap.
Definition memory.c:65
msg_t * akos_message_queue_get(msg_queue_t *p_msg_q)
Dequeue next message.
Definition message.c:218
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.
Definition message.c:98
void akos_message_queue_init(msg_queue_t *p_msg_q, uint8_t size)
Initialize message queue.
Definition message.c:82
void akos_message_queue_put_pure(msg_queue_t *p_msg_q, int32_t sig)
Enqueue pure signal message.
Definition message.c:165
Priority bitmap scheduler helpers.
void akos_priority_insert(uint32_t prio)
Mark priority as ready.
Definition priority.c:35
void akos_priority_remove(uint32_t prio)
Clear priority from ready table.
Definition priority.c:49
uint32_t akos_priority_get_highest(void)
Get highest ready priority.
Definition priority.c:63
FIFO queue metadata for thread messaging.
Definition message.h:63
msg_t * akos_thread_wait_for_msg(uint32_t time_out)
Wait for a message on current thread queue.
Definition thread.c:937
uint8_t akos_thread_get_timer_thread_id(void)
Get the runtime thread ID assigned to the timer thread.
Definition thread.c:86
void akos_thread_register_static_threads(void)
Create all statically defined application tasks plus system tasks.
Definition thread.c:455
uint8_t akos_thread_get_runtime_count(void)
Get number of runtime thread slots, including internal threads.
Definition thread.c:702
uint32_t akos_thread_get_tick(void)
Get current tick counter.
Definition thread.c:66
void akos_thread_start(void)
Start scheduler state variables.
Definition thread.c:650
uint8_t akos_thread_increment_tick(void)
Tick hook: unblock delayed tasks and select next runnable task.
Definition thread.c:560
uint8_t akos_thread_get_app_thread_count(void)
Get number of application threads defined via AKOS_THREAD_DEFINE.
Definition thread.c:71
void akos_thread_get_runtime_totals(uint32_t *p_idle_ticks, uint32_t *p_total_ticks)
Snapshot accumulated runtime counters.
Definition thread.c:665
void akos_thread_delay(const uint32_t tick_to_delay)
Delay current thread for a number of ticks.
Definition thread.c:636
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.
Definition thread.c:761
uint8_t akos_thread_get_shell_thread_id(void)
Get the runtime thread ID assigned to the shell thread.
Definition thread.c:81
uint8_t akos_thread_get_idle_thread_id(void)
Get the runtime thread ID assigned to the idle thread.
Definition thread.c:76
void akos_thread_post_msg_pure(uint8_t des_thread_id, int32_t sig)
Post pure signal message to another thread.
Definition thread.c:850
void akos_thread_get_runtime_snapshot(uint8_t index, thread_runtime_snapshot_t *p_snapshot)
Snapshot one runtime thread slot by index.
Definition thread.c:707
Thread scheduling and thread messaging APIs.
void(* thread_func_t)(void *p_arg)
Thread entry function signature.
Definition thread.h:66
thread_state_t
Runtime state of a thread control block.
Definition thread.h:49
@ THREAD_STATE_READY
Definition thread.h:51
@ THREAD_STATE_DELAYED
Definition thread.h:52
@ THREAD_STATE_RUNNING
Definition thread.h:50
@ THREAD_STATE_DELAYED_ON_MSG
Definition thread.h:55
@ THREAD_STATE_SUSPENDED
Definition thread.h:53
@ THREAD_STATE_SUSPENDED_ON_MSG
Definition thread.h:54
uint8_t thread_id_t
Numeric thread identifier type.
Definition thread.h:72
Software timer APIs.
void akos_timer_processing()
Timer thread processing loop.
Definition timer.c:247