YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
task.cpp
1// ---------------------------------------------
2// This file is part of
3// _ _ __ _ _ __ __
4// ( \/ ) /__\ ( )_( ) /__\ ( )
5// \ / /(__)\ ) _ ( /(__)\ )(__
6// (__)(__)(__)(_) (_)(__)(__)(____)
7//
8// Yet Another HW Abstraction Library
9// Copyright (C) Andreas Terstegge
10// BSD Licensed (see file LICENSE)
11//
12// ---------------------------------------------
13
14#include "task.h"
15#include <cstring>
16#include <utility>
17#include <cassert>
18#include <cstdlib>
19
20// Definition of static members
22uint64_t task::_up_ticks[NUMBER_OF_CORES] {0};
23task * task::_run_ptr [NUMBER_OF_CORES] {nullptr};
24task * task::_run_next[NUMBER_OF_CORES] {nullptr};
25circular_list<task> task::_list [NUMBER_OF_CORES];
26
27// CTOR and DTOR
29task::task(std::function<void()> f, const char *n, uint16_t stack_size)
30 : task(n, stack_size) {
31 _f = std::move(f);
32}
33
34task::~task() {
35 stop();
36 delete [] _stack_base;
37 _stack_base = nullptr;
38}
39
40task::task(const char * n, uint16_t stack_size)
41{
42 // Initialize task attributes
43 strncpy(_name, n, 15);
44 _name[15] = '\0';
45 _state = state_t::SUSPENDED;
46 _lock = nullptr;
47
48 // Allocate the stack
49 _stack_size = stack_size;
50 _stack_base = new uint8_t[_stack_size];
51 assert(_stack_base);
52 _stack_ptr = nullptr;
53
54 // Initialize circular list attributes
55 _linked_in = false;
56 _next = nullptr;
57 _prev = nullptr;
58}
59
60// public task methods
62void task::sign_up(core_t c, uint16_t priority, bool priv) {
63 assert((priority > 0) && !_linked_in);
64
65 // If no core is specified, use the current one
66 _core = (c == core_t::CURRENT_CORE) ? get_core() : (int8_t)c;
67
68 // Initialize the stack with a magic number
69 for(uint16_t i=0; i < _stack_size; ++i) {
70 _stack_base[i] = STACK_MAGIC;
71 }
72
73 // Setup HW specific stack stuff
74 _setup_stack(priv);
75
76 // Set remaining Task data members
77 _priority = priority;
78 _state = state_t::READY;
79 _ticks = 0;
80 _last_ticks = 0;
81 _sleep_until = 0;
82 _lock = nullptr;
83
84 // Finally link in the Task
85 enterCritical();
86 _list[_core].push_back(this);
87 leaveCritical();
88}
89
90void task::stop() {
91 if (_linked_in) {
92 // Link out the Task, so it will not
93 // consume any further runtime ...
94 enterCritical();
95 _list[_core].remove(this);
96 leaveCritical();
97 // and switch to another task
98 yield();
99 }
100}
101
102void task::sleep_ms(uint32_t ms) {
103 //assert(!task::is_irq_context());
104 // Calculate the target time
105 uint64_t until = millis() + ms;
106 if (multitasking_running()) {
107 // Get current task
108 task * t = task::currentTask();
109 assert(t);
110 // Update TCB and hand over control to another task
111 t->_sleep_until = until;
112 t->_state = state_t::SLEEPING;
113 yield();
114 } else {
115 // Active waiting until time has elapsed
116 while(millis() < until) ;
117 }
118}
119
120void task::suspend() {
121 _state = state_t::SUSPENDED;
122}
123
124void task::resume() {
125 _state = state_t::READY;
126}
127
128void task::block(lock_base_interface * lbi) {
129 _lock = lbi;
130 _state = state_t::BLOCKED;
131}
132
133void task::join() const {
134 while ( _linked_in ) yield();
135}
136
137uint16_t task::getUsedStack() {
138 uint16_t i;
139 for (i=0; i < _stack_size; ++i) {
140 if (_stack_base[i] != STACK_MAGIC) break;
141 }
142 return _stack_size - i;
143}
144
145uint32_t task::getDeltaTicks() {
146 uint32_t now = _ticks;
147 uint32_t ret = now - _last_ticks;
148 _last_ticks = now;
149 return ret;
150}
151
152// private methods
154void task::_run() {
155 run();
156 stop();
157 // in case a task is run without the scheduler
158 exit(0);
159}
160
161// methods which will be called by IRQ handlers
163void task::_scheduler() {
164 int8_t c = get_core();
165 task * cur_ptr = _run_ptr[c]->_next;
166 task * next_ptr = nullptr;
167 uint16_t max_prio = 0;
168
169 for(int i=0; i < _list[c].getSize(); ++i) {
170 state_t & state = cur_ptr->_state;
171 uint16_t prio = cur_ptr->_priority;
172
173 // Handle sleeping Tasks
174 if (state == state_t::SLEEPING) {
175 if (millis() >= cur_ptr->_sleep_until) {
176 state = state_t::READY;
177 }
178 }
179 // Handle blocked Tasks
180 if (state == state_t::BLOCKED) {
181 if (!cur_ptr->_lock->is_locked()) {
182 state = state_t::READY;
183 }
184 }
185 // Look for potential new Tasks to run
186 if ((state == state_t::READY) && (prio > max_prio)) {
187 max_prio = prio;
188 next_ptr = cur_ptr;
189 #ifdef SIMPLE_ROUND_ROBIN
190 break;
191 #endif
192 }
193 cur_ptr = cur_ptr->_next;
194 }
195
196 assert(next_ptr);
197
198 // Check if we need a context switch
199 if (next_ptr != _run_ptr[c]) {
200 _run_next[c] = next_ptr;
201 _context_switch();
202 }
203}
204
205void task::_tick_handler() {
206 // Get the core
207 int8_t c = get_core();
208 // Increment the global tick counter (might be used for the millis()
209 // method in case the MCU does not have an independent timer)
210 ++(_up_ticks[c]);
211 // Find new task to execute, in case
212 // multitasking is running
213 if (_run_ptr[c]) {
214 // Increment ticks of the running task...
215 ++(_run_ptr[c]->_ticks);
216 // ... and let the scheduler check for a task switch
217 _scheduler();
218 }
219}
220
Definition task.h:39