YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
task.h
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// This a abstract base class for the YAHAL multitasking
15// functionality. It is generic for all HW platforms.
16// The user code, which is run by the task, is located
17// inside the abstract method run(), which has to be
18// implemented by a derived class.
19// The platform-specific part is implemented in some
20// static functions, which can be found at the end of
21// this file.
22
23#ifndef _TASK_H_
24#define _TASK_H_
25
26#include <cstdint>
27#include <functional>
28#include "yahal_config.h"
29#include "circular_list.h"
30#include "lock_base_interface.h"
31
32enum class core_t {
33 CURRENT_CORE = -1,
34 CORE_0 = 0,
35 CORE_1 = 1,
36 CORE_2 = 2,
37 CORE_3 = 3 };
38
39class task {
40public:
41 // Public CTOR to create a task based on some std::function.
42 // f can be a function, a lambda expression, a function object ...
43 task(std::function<void()> f,
44 const char * n, uint16_t stack_size=DEFAULT_STACK_SIZE);
45 virtual ~task();
46
47 // No copy, no assignment
48 task (const task &) = delete;
49 task & operator= (const task &) = delete;
50
51protected:
52 // Protected CTOR which will be called by a derived class.
53 // The run()-Method has to be implemented in the derived class!
54 explicit task(const char * n, uint16_t stack_size=DEFAULT_STACK_SIZE);
55
56 // The method containing the task code
57 virtual void run() { _f(); }
58
59public:
60 // enum type for the different task states and
61 // helper method to convert a state to a string.
62 // The enum and methods are public and the methods
63 // static, so they can be used also in non-derived
64 // classes and other code without a task object.
65 enum state_t : uint8_t {
66 READY = 0, // task is ready to run
67 SLEEPING = 1, // sleep() was called on task
68 SUSPENDED = 2, // suspend() was called on task
69 BLOCKED = 3, // block() was called on task
70 };
71
72 static inline const char * state_to_str(state_t state) {
73 static const char * names[] =
74 { "READY", "SLEEPING", "SUSPENDED", "BLOCKED" };
75 return names[state];
76 }
77
78 // Sign up a thread. This means that the stack space of
79 // the task is set up, and the task is linked into the
80 // circular list of tasks, which is used by the scheduler.
81 // The third parameter offers the possibility to start
82 // this thread as a privileged task, if this is supported
83 // by the HW platform.
84 void sign_up(core_t = core_t::CURRENT_CORE,
85 uint16_t priority = DEFAULT_PRIORITY,
86 bool priv = false);
87
88 // Stop a task. This means that the task is immediately
89 // linked out of the circular list of tasks, and will
90 // not get any further processing time. This method is
91 // called automatically when the run() method of a task
92 // ends. Calling this method manually is dangerous,
93 // because the task could still own some resources, which
94 // would never be given back after stop().
95 void stop();
96
97 // Let the current task (the task entering this method)
98 // sleep for a certain amount of time. Time is specified
99 // in milliseconds. yield() will be called so that execution
100 // proceeds with the next ready task.
101 static void sleep_ms(uint32_t ms);
102
103 // Suspend a task execution. The task will only come
104 // back to life if resume() is called from another
105 // task or an interrupt handler. If suspend() is called
106 // on the currently running task, a yield() might be
107 // necessary to stop the current task and proceed with
108 // the next ready task.
109 void suspend();
110
111 // Resume a task, which was suspended before. If the
112 // resumed task should run immediately, a consecutive
113 // yield() might be necessary.
114 void resume();
115
116 // Block a task on a lock. As long as the lock is locked,
117 // the task will not be executed by the scheduler. block()
118 // will never call yield(), so if block() is called on the
119 // currently running task, a yield() could follow block()
120 // so that execution proceeds with the next ready task.
121 // block() is e.g. used in mutexes.
122 void block(lock_base_interface * lbi);
123
124 // Join a task. This means that the caller of this method
125 // waits until the called thread has ended its execution
126 // (returns from the run() method).
127 void join() const;
128
129 // getters and setters for some attributes
130 inline const char * getName() const { return _name; }
131 inline uint16_t getPriority() const { return _priority; }
132 inline void setPriority(uint16_t p) { _priority = p; }
133 inline state_t getState() const { return _state; }
134 inline uint32_t getMillisRun() const { return (_ticks * 1000) / TICK_FREQUENCY; }
135 inline uint16_t getStackSize() const { return _stack_size; }
136 inline bool isLinkedIn() const { return _linked_in; }
137
138 // method to report the number of used bytes in the stack
139 uint16_t getUsedStack();
140
141 // Special getter to get the ticks of this task since the last call to this method
142 uint32_t getDeltaTicks();
143
144private:
145 char _name[16] {0}; // name of the task
146 int8_t _core {0}; // core this task is running on
147 uint16_t _priority {0}; // task priority
148 state_t _state; // state of this task
149 uint32_t _ticks {0}; // consumed tick_count
150 uint32_t _last_ticks {0}; // _ticks at last call to getDeltaTicks()
151 uint64_t _sleep_until {0}; // system time in millis when sleep ends
152 lock_base_interface * _lock; // pointer to lock if thread is blocked
153
154 // stack-pointer related attributes
155 uint8_t * _stack_base; // stack base address
156 uint16_t _stack_size; // stack size in bytes
157 uint8_t * _stack_ptr; // saved stack pointer of this task
158
159 // static members for global ticks and current task
160 static task * _run_ptr [NUMBER_OF_CORES]; // Pointer to running Task
161 static task * _run_next[NUMBER_OF_CORES]; // Pointer to next running Task
162 static uint64_t _up_ticks[NUMBER_OF_CORES]; // global tick count from start
163
164 // tasks are organized as a circular list, so
165 // here are the related private members
166 friend class circular_list<task>;
167 friend class task_monitor;
168 static circular_list<task> _list[NUMBER_OF_CORES];
169 bool _linked_in; // is this task in the list?
170 task * _next; // pointer to next task
171 task * _prev; // pointer to previous task
172
173 // Helper method for calling the virtual run() method
174 void _run();
175 // Function to execute if provided in CTOR
176 std::function<void(void)> _f;
177
179 // CPU-specific interface, which needs to be //
180 // implemented by all different CPU cores. //
182 void _setup_stack (bool priv);
183 static void _context_switch();
184
185public:
186 static void start_scheduler();
187 static void yield();
188 static void cpu_sleep();
189 static void enterCritical();
190 static void leaveCritical();
191 static uint64_t millis();
192 static bool is_irq_context();
193 static bool multitasking_running();
194 static int8_t get_core();
195
196 bool isPrivileged() const;
197 bool isUsingFloat() const;
198
200 // Methods which will be called by a concrete //
201 // task implementation (IRQ handlers). Therefore, //
202 // these methods need to be public and static. //
204 static void _scheduler();
205 static void _tick_handler ();
206
207 static task * currentTask() {
208 int c = get_core();
209 return _run_ptr[c];
210 }
211 static void _switchToHead() {
212 int c = get_core();
213 _run_ptr[c] = _list[c].getHead();
214 }
215 static inline void _switchToNext() {
216 int c = get_core();
217 _run_ptr[c] = _run_next[c];
218 }
219 static inline uint8_t * _getStackBase() {
220 int c = get_core();
221 return _run_ptr[c]->_stack_base;
222 }
223 static inline uint8_t * _getStackPtr() {
224 int c = get_core();
225 return _run_ptr[c]->_stack_ptr;
226 }
227 static inline void _setStackPtr(uint8_t *s) {
228 int c = get_core();
229 _run_ptr[c]->_stack_ptr = s;
230 }
231};
232
233#endif // _TASK_H_
Definition task.h:39