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 "timer.h"
18#include "priority.h"
19#include "port.h"
20#include <string.h>
21
22#define TASK_IDLE_PRI (OS_CFG_PRIO_MAX - 1u)
23
24#define TASK_TIMER_PRI ((uint8_t)OS_CFG_TIMER_TASK_PRI)
25
26#define TASK_TIMER_STK_SIZE (100u)
27
28
29typedef struct task_tcb task_tcb_t;
30
31#define SIZE_OF_TCB (sizeof(task_tcb_t))
32
33
34task_tcb_t *volatile tcb_curr_ptr = NULL;
35task_tcb_t *volatile tcb_high_rdy_ptr = NULL;
36
37static list_t rdy_task_list[OS_CFG_PRIO_MAX]; /*< Prioritised ready tasks. */
38static list_t dly_task_list_1; /*< Delayed tasks. */
39static list_t dly_task_list_2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
40static list_t *volatile dly_task_list_ptr; /*< Points to the delayed task list currently being used. */
41static 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. */
42static list_t suspended_task_list; /*< Tasks that are currently suspended. */
43
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;
47static volatile uint32_t next_tick_to_unblock = (uint32_t)OS_CFG_DELAY_MAX; /* Initialised to portMAX_DELAY before the scheduler starts. */
48
49static volatile uint8_t sched_is_running = (uint8_t)OS_FALSE;
50
51extern const thread_t __start_task_desc[] __attribute__((weak));
52extern const thread_t __stop_task_desc[] __attribute__((weak));
53
54static task_tcb_t **task_tcb_list = NULL; /*< Holds the list of task TCBs. */
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;
59
65{
66 return tick_count;
67}
68
70{
71 return task_app_count;
72}
73
75{
76 return task_idle_id;
77}
78
80{
81 return task_timer_id;
82}
83
88static void task_idle_func(void *p_arg)
89{
90 for (;;)
91 {
92 }
93}
94
99static void task_timer_func(void *p_arg)
100{
101 for (;;)
102 {
104 }
105}
106
108{
109 volatile uint32_t *stk_ptr; /* Stack pointer, has to be the first member of TCB */
110 list_item_t state_list_item; /*Item in StateList include Ready, Blocked, Suspended List */
111 list_item_t event_list_item; /*Item in Event List */
112 uint32_t *stk_limit_ptr; /* Pointer used to set stack 'watermark' limit */
113 uint8_t prio;
114 size_t stk_size; /* Size of task stack (in number of stack elements) */
115 uint32_t *stk_base_ptr; /* Pointer to base address of stack */
116 thread_id_t id;
117 msg_queue_t msg_queue;
118 thread_state_t state; /* States */
119};
120
124static void init_task_lists(void)
125{
126 /* Initialize lists */
127 uint8_t prio;
128 for (prio = 0; prio < OS_CFG_PRIO_MAX; prio++)
129 {
130 akos_list_init(&(rdy_task_list[prio]));
131 }
132 akos_list_init(&dly_task_list_1);
133 akos_list_init(&dly_task_list_2);
134 akos_list_init(&suspended_task_list);
135 dly_task_list_ptr = &dly_task_list_1;
136 overflow_dly_task_list_ptr = &dly_task_list_2;
137 /********************/
138}
139
143static void task_switch_delay_lists()
144{
145 list_t *p_list_temp;
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;
149
150 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
151 {
152 /* The new current delayed list is empty. Set xNextTaskUnblockTime to
153 * the maximum possible value so it is extremely unlikely that the
154 * if( xTickCount >= xNextTaskUnblockTime ) test will pass until
155 * there is an item in the delayed list. */
156 next_tick_to_unblock = OS_CFG_DELAY_MAX;
157 }
158 else
159 {
160 /* The new current delayed list is not empty, get the value of
161 * the item at the head of the delayed list. This is the time at
162 * which the task at the head of the delayed list should be removed
163 * from the Blocked state. */
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;
167 }
168}
169
174static void add_new_task_to_rdy_list(task_tcb_t *p_tcb)
175{
176 AKOS_CORE_ENTER_CRITICAL();
177 {
178 num_of_tasks++;
179 if (num_of_tasks == 1)
180 {
181 init_task_lists();
182 tcb_curr_ptr = p_tcb;
183 }
184 else
185 {
186 if (tcb_curr_ptr->prio <= p_tcb->prio)
187 {
188 tcb_curr_ptr = p_tcb;
189 }
190 }
191 akos_list_insert_end(&(rdy_task_list[p_tcb->prio]), &((p_tcb)->state_list_item));
192 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
193 {
194 akos_priority_insert(p_tcb->prio);
195 }
196 /*Save state*/
197 p_tcb->state = THREAD_STATE_READY;
198 }
199 AKOS_CORE_EXIT_CRITICAL();
200}
201
206static void add_task_to_rdy_list(task_tcb_t *p_tcb)
207{
208 akos_list_insert_end(&(rdy_task_list[p_tcb->prio]), &((p_tcb)->state_list_item));
209 if (list_get_num_item(&(rdy_task_list[p_tcb->prio])) == 1u)
210 {
211 akos_priority_insert(p_tcb->prio);
212 }
213 /*Save state*/
214 p_tcb->state = THREAD_STATE_READY;
215}
216
222static void add_curr_task_to_delay_list(uint32_t tick_to_delay, uint8_t can_block_indefinitely)
223{
224 uint32_t time_to_wake;
225 const uint32_t const_tick = tick_count;
226 if (akos_list_remove(&(tcb_curr_ptr->state_list_item)) == 0u)
227 {
228 akos_priority_remove(tcb_curr_ptr->prio);
229 }
230 if ((tick_to_delay == OS_CFG_DELAY_MAX) && (can_block_indefinitely != OS_FALSE))
231 {
232 /* Add the task to the suspended task list instead of a delayed task
233 * list to ensure it is not woken by a timing event. It will block
234 * indefinitely. */
235 akos_list_insert_end(&suspended_task_list, &(tcb_curr_ptr->state_list_item));
236 /*Save state*/
237 tcb_curr_ptr->state = THREAD_STATE_SUSPENDED;
238 }
239 else
240 {
241 time_to_wake = const_tick + tick_to_delay;
242 list_item_set_value(&(tcb_curr_ptr->state_list_item), time_to_wake);
243
244 if (time_to_wake < const_tick)
245 {
246 /* Wake time has overflowed. Place this item in the overflow
247 * list. */
248 akos_list_insert(overflow_dly_task_list_ptr, &(tcb_curr_ptr->state_list_item));
249 }
250 else
251 {
252 /* The wake time has not overflowed, so the current block list
253 * is used. */
254 akos_list_insert(dly_task_list_ptr, &(tcb_curr_ptr->state_list_item));
255
256 /*Update next tick to block is important in order scheduler not to miss this stamp
257 Just update next tick to block in this branch because overflow delay is just the background list
258 */
259
260 if (time_to_wake < next_tick_to_unblock)
261 {
262 next_tick_to_unblock = time_to_wake;
263 }
264 }
265 /*Save state*/
266 tcb_curr_ptr->state = THREAD_STATE_DELAYED;
267 }
268 uint8_t highest_prio = akos_priority_get_highest();
269 tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[highest_prio]));
270
271 /*Save state*/
272 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
273}
274
285static task_tcb_t *task_create(thread_id_t id,
286 thread_func_t pf_thread,
287 void *p_arg,
288 uint8_t prio,
289 size_t queue_size,
290 size_t stack_size)
291{
292 if (sched_is_running == OS_TRUE)
293 {
294 // OSUniversalError = OS_ERR_SCHED_IS_RUNNING;
295 core_assert(0, "OS_ERR_SCHED_IS_RUNNING");
296 return NULL;
297 }
298 if (prio > (OS_CFG_PRIO_MAX - 1U))
299 {
300 // OSUniversalError = OS_ERR_TCB_PRIO_INVALID;
301 core_assert(0, "OS_ERR_TCB_PRIO_INVALID");
302 return NULL;
303 }
304 if (pf_thread == NULL)
305 {
306 // OSUniversalError = OS_ERR_TCB_FUNC_INVALID;
307 core_assert(0, "OS_ERR_TCB_FUNC_INVALID");
308 return NULL;
309 }
310 if (stack_size < OS_CFG_TASK_STK_SIZE_MIN)
311 {
312 // OSUniversalError = OS_ERR_TCB_STK_SIZE_INVALID;
313 core_assert(0, "OS_ERR_TCB_STK_SIZE_INVALID");
314 return NULL;
315 }
316 if ((task_tcb_list == NULL) || (id >= task_tcb_list_len))
317 {
318 core_assert(0, "OS_ERR_TASK_ID_INVALID");
319 return NULL;
320 }
321 if (task_tcb_list[id] != NULL)
322 {
323 core_assert(0, "OS_ERR_TASK_ID_ALREADY_USED");
324 return NULL;
325 }
326
327
328 task_tcb_t *p_new_tcb;
329 uint32_t *p_stack;
330
331 p_stack = akos_memory_malloc(stack_size * sizeof(uint32_t));
332 if (p_stack != NULL)
333 {
334 p_new_tcb = (task_tcb_t *)akos_memory_malloc(SIZE_OF_TCB);
335 if (p_new_tcb != NULL)
336 {
337 memset((void *)p_new_tcb, 0x00, SIZE_OF_TCB);
338
339 /*Save stack limit pointer*/
340 p_new_tcb->stk_limit_ptr = p_stack;
341 }
342 else
343 {
344 akos_memory_free(p_stack);
345 // OSUniversalError = OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC;
346 core_assert(0, "OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
347 return NULL;
348 }
349 }
350 else
351 {
352 // OSUniversalError = OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC;
353 core_assert(0, "OS_ERR_TCB_NOT_ENOUGH_MEM_ALLOC");
354 return NULL;
355 }
356
357 /*Now TCB and stack are created*/
358 uint32_t *p_stack_ptr;
359
360 /* Fill the stack with a known value to assist debugging. */
361 //( void ) memset( p_new_tcb->stk_limit_ptr, OS_CFG_TASK_STACK_FILL_BYTE, stack_size );
362
363 /*Init stack frame*/
364 p_stack_ptr = akos_port_task_stack_init(p_stack,
365 stack_size,
366 pf_thread,
367 p_arg);
368
369 /*Save top of stack (Stack pointer)*/
370 p_new_tcb->stk_ptr = p_stack_ptr;
371
372 /*Save stack size*/
373 p_new_tcb->stk_size = stack_size;
374
375 /*Save ID*/
376 p_new_tcb->id = id;
377
378 /*Save prio*/
379 p_new_tcb->prio = prio;
380 // akos_priority_insert(prio);
381
382 akos_message_queue_init(&(p_new_tcb->msg_queue), queue_size);
383
384 /* Init linked lists */
385 akos_list_item_init(&(p_new_tcb->state_list_item));
386 akos_list_item_init(&(p_new_tcb->event_list_item));
387
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);
390
391 list_item_set_value(&(p_new_tcb->state_list_item), prio);
392
393 add_new_task_to_rdy_list(p_new_tcb);
394 task_tcb_list[id] = p_new_tcb;
395
396 return p_new_tcb;
397}
398
403{
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;
407
408 if ((p_thread_desc == NULL) || (p_thread_desc_end == NULL) || (p_thread_desc == p_thread_desc_end))
409 {
410 /* No application threads were linked in. */
411 }
412 else
413 {
414 app_count = (size_t)(p_thread_desc_end - p_thread_desc);
415 }
416
417 if (app_count > (size_t)(UINT8_MAX - 2u))
418 {
419 core_assert(0, "OS_ERR_TOO_MANY_TASKS");
420 return;
421 }
422
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);
427
428 task_tcb_list = (task_tcb_t **)akos_memory_malloc(sizeof(task_tcb_t *) * task_tcb_list_len);
429 if (task_tcb_list == NULL)
430 {
431 core_assert(0, "OS_ERR_TASK_TCB_TABLE_ALLOC");
432 return;
433 }
434 memset(task_tcb_list, 0x00, sizeof(task_tcb_t *) * task_tcb_list_len);
435
436 for (; p_thread_desc < p_thread_desc_end; ++p_thread_desc)
437 {
438 if (p_thread_desc->id >= task_app_count)
439 {
440 core_assert(0, "OS_ERR_THREAD_ID_RESERVED");
441 continue;
442 }
443
444 (void)task_create(p_thread_desc->id,
445 p_thread_desc->pf_thread,
446 p_thread_desc->p_arg,
447 p_thread_desc->prio,
448 p_thread_desc->queue_size,
449 p_thread_desc->stack_size);
450 }
451
452 (void)task_create((thread_id_t)task_timer_id,
453 (thread_func_t)task_timer_func,
454 (void *)NULL,
455 (uint8_t)TASK_TIMER_PRI,
457 (size_t)TASK_TIMER_STK_SIZE);
458
459 (void)task_create((thread_id_t)task_idle_id,
460 (thread_func_t)task_idle_func,
461 (void *)NULL,
462 (uint8_t)TASK_IDLE_PRI,
463 (size_t)(0u),
465}
466
472{
473 uint8_t is_switch_needed = OS_FALSE;
474 task_tcb_t *p_tcb;
475 uint32_t item_value;
476
477 const uint32_t const_tick = tick_count + (uint32_t)1;
478
479 /* Increment the RTOS tick, switching the delayed and overflowed
480 * delayed lists if it wraps to 0. */
481 tick_count = const_tick;
482
483 if (const_tick == (uint32_t)0U) /* Overflowed, switch delaylist*/
484 {
485 task_switch_delay_lists();
486 }
487
488 if (const_tick >= next_tick_to_unblock)
489 {
490 for (;;)
491 {
492 if (list_is_empty(dly_task_list_ptr) == OS_TRUE)
493 {
494 next_tick_to_unblock = OS_CFG_DELAY_MAX;
495 break;
496 }
497 else
498 {
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)
502 {
503 /* Stop condition */
504 next_tick_to_unblock = item_value;
505 break;
506 }
507 akos_list_remove(&(p_tcb->state_list_item)); /*Remove from block state*/
508
509 /* Is the task waiting on an event also? If so remove
510 * it from the event list. */
511 if (list_item_get_list_contain(&(p_tcb->event_list_item)) != NULL)
512 {
513 akos_list_remove(&(p_tcb->event_list_item));
514 }
515 add_task_to_rdy_list(p_tcb);
516 if (p_tcb->prio < tcb_curr_ptr->prio)
517 {
518 tcb_high_rdy_ptr = p_tcb;
519 is_switch_needed = OS_TRUE;
520 }
521 }
522 }
523 }
524
525 uint8_t highest_prio = akos_priority_get_highest();
526 if (list_get_num_item(&(rdy_task_list[highest_prio])) > 1u)
527 {
528 tcb_high_rdy_ptr = akos_list_get_owner_of_next_item(&(rdy_task_list[highest_prio]));
529 is_switch_needed = OS_TRUE;
530 }
531 /*Save state*/
532 if(is_switch_needed == OS_TRUE) tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
533
534 return is_switch_needed;
535}
536
541void akos_thread_delay(const uint32_t tick_to_delay)
542{
543 if (tick_to_delay > (uint32_t)0U)
544 {
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();
549 }
550}
551
556{
557 tcb_high_rdy_ptr = list_get_owner_of_head_item(&(rdy_task_list[akos_priority_get_highest()]));
558 tcb_curr_ptr = tcb_high_rdy_ptr;
559 tick_count = 0u;
560 next_tick_to_unblock = OS_CFG_DELAY_MAX;
561 sched_is_running = OS_TRUE;
562}
563
571void akos_thread_post_msg_dynamic(uint8_t des_thread_id, int32_t sig, void *p_content, uint8_t msg_size)
572{
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))
575 {
576 core_assert(0, "OS_ERR_THREAD_ID_INVALID");
577 AKOS_CORE_EXIT_CRITICAL();
578 return;
579 }
580 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
581 {
582 // OSUniversalError = OS_ERR_THREAD_POST_MSG_TO_ITSELF;
583 core_assert(0, "OS_ERR_THREAD_POST_MSG_TO_ITSELF");
584 AKOS_CORE_EXIT_CRITICAL();
585 return;
586 }
587
588 switch (task_tcb_list[des_thread_id]->state)
589 {
591 akos_message_queue_put_dynamic(&(task_tcb_list[des_thread_id]->msg_queue),
592 sig,
593 p_content,
594 msg_size);
595
596 /* Is the thread waiting on an event ? If so remove
597 * it from the event list. */
598 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
599 {
600 akos_list_remove(&(task_tcb_list[des_thread_id]->event_list_item));
601 }
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)
604 {
605 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
606
607 /*Save state*/
608 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
609
610 port_trigger_PendSV();
611 }
612 AKOS_CORE_EXIT_CRITICAL();
613 break;
615 akos_message_queue_put_dynamic(&(task_tcb_list[des_thread_id]->msg_queue),
616 sig,
617 p_content,
618 msg_size);
619 /* Is the thread waiting on an event ? If so remove
620 * it from the event list. */
621 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
622 {
623 akos_list_remove(&(task_tcb_list[des_thread_id]->state_list_item));
624 }
625
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)
628 {
629 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
630
631 /*Save state*/
632 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
633
634 port_trigger_PendSV();
635 }
636 AKOS_CORE_EXIT_CRITICAL();
637 break;
638
639 default:
640 akos_message_queue_put_dynamic(&(task_tcb_list[des_thread_id]->msg_queue),
641 sig,
642 p_content,
643 msg_size);
644 AKOS_CORE_EXIT_CRITICAL();
645 break;
646 }
647}
648
654void akos_thread_post_msg_pure(uint8_t des_thread_id, int32_t sig)
655{
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))
658 {
659 core_assert(0, "OS_ERR_THREAD_ID_INVALID");
660 AKOS_CORE_EXIT_CRITICAL();
661 return;
662 }
663#if 0 /* Under testing */
664 if (task_tcb_list[des_thread_id] == tcb_curr_ptr)
665 {
666 // OSUniversalError = OS_ERR_THREAD_POST_MSG_TO_ITSELF;
667 core_assert(0, "OS_ERR_THREAD_POST_MSG_TO_ITSELF");
668 AKOS_CORE_EXIT_CRITICAL();
669 return;
670 }
671#endif
672 switch (task_tcb_list[des_thread_id]->state)
673 {
675 akos_message_queue_put_pure(&(task_tcb_list[des_thread_id]->msg_queue), sig);
676 /* Is the thread waiting on an event ? If so remove
677 * it from the event list. */
678 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
679 {
680 akos_list_remove(&(task_tcb_list[des_thread_id]->event_list_item));
681 }
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)
684 {
685 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
686
687 /*Save state*/
688 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
689
690 port_trigger_PendSV();
691 }
692 AKOS_CORE_EXIT_CRITICAL();
693 break;
695 akos_message_queue_put_pure(&(task_tcb_list[des_thread_id]->msg_queue), sig);
696 /* Is the thread waiting on an event ? If so remove
697 * it from the event list. */
698 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->state_list_item)) != NULL)
699 {
700 akos_list_remove(&(task_tcb_list[des_thread_id]->state_list_item));
701 }
702
703 /* Is the thread waiting on an event also? If so remove
704 * it from the event list. */
705 if (list_item_get_list_contain(&(task_tcb_list[des_thread_id]->event_list_item)) != NULL)
706 {
707 akos_list_remove(&(task_tcb_list[des_thread_id]->event_list_item));
708 }
709
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)
712 {
713 tcb_high_rdy_ptr = task_tcb_list[des_thread_id];
714
715 /*Save state*/
716 tcb_high_rdy_ptr->state = THREAD_STATE_RUNNING;
717
718 port_trigger_PendSV();
719 }
720 AKOS_CORE_EXIT_CRITICAL();
721 break;
722
723 default: /*DELAYED, SUSPEND, RUNNING*/
724 akos_message_queue_put_pure(&(task_tcb_list[des_thread_id]->msg_queue), sig);
725 AKOS_CORE_EXIT_CRITICAL();
726 break;
727 }
728}
729
735msg_t *akos_thread_wait_for_msg(uint32_t time_out)
736{
737 AKOS_CORE_ENTER_CRITICAL();
738 msg_t *p_msg = akos_message_queue_get(&(task_tcb_list[tcb_curr_ptr->id]->msg_queue));
739 if (time_out > (uint32_t)0U && p_msg == NULL)
740 {
741 add_curr_task_to_delay_list(time_out, OS_TRUE); // Can block indefinitely
742 if (time_out == OS_CFG_DELAY_MAX)
743 {
744 tcb_curr_ptr->state = THREAD_STATE_SUSPENDED_ON_MSG;
745 }
746 else
747 {
748 tcb_curr_ptr->state = THREAD_STATE_DELAYED_ON_MSG;
749 }
750 port_trigger_PendSV();
751 AKOS_CORE_EXIT_CRITICAL();
752
753 p_msg = akos_message_queue_get(&(task_tcb_list[tcb_curr_ptr->id]->msg_queue));
754 return p_msg;
755 }
756 else
757 {
758 AKOS_CORE_EXIT_CRITICAL();
759 return p_msg;
760 }
761}
#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_PRIO_MAX
Definition config.h:26
#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:67
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:139
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:735
uint8_t akos_thread_get_timer_thread_id(void)
Get the runtime thread ID assigned to the timer thread.
Definition thread.c:79
void akos_thread_register_static_threads(void)
Create all statically defined application tasks plus system tasks.
Definition thread.c:402
uint32_t akos_thread_get_tick(void)
Get current tick counter.
Definition thread.c:64
void akos_thread_start(void)
Start scheduler state variables.
Definition thread.c:555
uint8_t akos_thread_increment_tick(void)
Tick hook: unblock delayed tasks and select next runnable task.
Definition thread.c:471
uint8_t akos_thread_get_app_thread_count(void)
Get number of application threads defined via AKOS_THREAD_DEFINE.
Definition thread.c:69
void akos_thread_delay(const uint32_t tick_to_delay)
Delay current thread for a number of ticks.
Definition thread.c:541
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:571
uint8_t akos_thread_get_idle_thread_id(void)
Get the runtime thread ID assigned to the idle thread.
Definition thread.c:74
void akos_thread_post_msg_pure(uint8_t des_thread_id, int32_t sig)
Post pure signal message to another thread.
Definition thread.c:654
Thread scheduling and thread messaging APIs.
void(* thread_func_t)(void *p_arg)
Thread entry function signature.
Definition thread.h:59
thread_state_t
Runtime state of a thread control block.
Definition thread.h:42
@ THREAD_STATE_READY
Definition thread.h:44
@ THREAD_STATE_DELAYED
Definition thread.h:45
@ THREAD_STATE_RUNNING
Definition thread.h:43
@ THREAD_STATE_DELAYED_ON_MSG
Definition thread.h:48
@ THREAD_STATE_SUSPENDED
Definition thread.h:46
@ THREAD_STATE_SUSPENDED_ON_MSG
Definition thread.h:47
uint8_t thread_id_t
Numeric thread identifier type.
Definition thread.h:65
Software timer APIs.
void akos_timer_processing()
Timer thread processing loop.
Definition timer.c:247