PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

425 lines
12KB

  1. /*
  2. * Threads.h - Library for threading on the Teensy.
  3. *
  4. *******************
  5. *
  6. * Copyright 2017 by Fernando Trias.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  9. * and associated documentation files (the "Software"), to deal in the Software without restriction,
  10. * including without limitation the rights to use, copy, modify, merge, publish, distribute,
  11. * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all copies or
  15. * substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
  18. * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  20. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. *
  23. *******************
  24. *
  25. * Multithreading library for Teensy board.
  26. * See Threads.cpp for explanation of internal functions.
  27. *
  28. * A global variable "threads" of type Threads will be created
  29. * to provide all threading functions. See example below:
  30. *
  31. * #include <Threads.h>
  32. *
  33. * volatile int count = 0;
  34. *
  35. * void thread_func(int data){
  36. * while(1) count++;
  37. * }
  38. *
  39. * void setup() {
  40. * threads.addThread(thread_func, 0);
  41. * }
  42. *
  43. * void loop() {
  44. * Serial.print(count);
  45. * }
  46. *
  47. * Alternatively, you can use the std::threads class defined
  48. * by C++11
  49. *
  50. * #include <Threads.h>
  51. *
  52. * volatile int count = 0;
  53. *
  54. * void thread_func(){
  55. * while(1) count++;
  56. * }
  57. *
  58. * void setup() {
  59. * std::thead th1(thread_func);
  60. * th1.detach();
  61. * }
  62. *
  63. * void loop() {
  64. * Serial.print(count);
  65. * }
  66. *
  67. */
  68. #ifndef _THREADS_H
  69. #define _THREADS_H
  70. #include <stdint.h>
  71. /* Enabling debugging information allows access to:
  72. * getCyclesUsed()
  73. */
  74. // #define DEBUG
  75. extern "C" {
  76. void context_switch(void);
  77. void context_switch_direct(void);
  78. void context_switch_pit_isr(void);
  79. void loadNextThread();
  80. void stack_overflow_isr(void);
  81. void threads_svcall_isr(void);
  82. void threads_systick_isr(void);
  83. }
  84. // The stack frame saved by the interrupt
  85. typedef struct {
  86. uint32_t r0;
  87. uint32_t r1;
  88. uint32_t r2;
  89. uint32_t r3;
  90. uint32_t r12;
  91. uint32_t lr;
  92. uint32_t pc;
  93. uint32_t xpsr;
  94. } interrupt_stack_t;
  95. // The stack frame saved by the context switch
  96. typedef struct {
  97. uint32_t r4;
  98. uint32_t r5;
  99. uint32_t r6;
  100. uint32_t r7;
  101. uint32_t r8;
  102. uint32_t r9;
  103. uint32_t r10;
  104. uint32_t r11;
  105. uint32_t lr;
  106. #ifdef __ARM_PCS_VFP
  107. uint32_t s0;
  108. uint32_t s1;
  109. uint32_t s2;
  110. uint32_t s3;
  111. uint32_t s4;
  112. uint32_t s5;
  113. uint32_t s6;
  114. uint32_t s7;
  115. uint32_t s8;
  116. uint32_t s9;
  117. uint32_t s10;
  118. uint32_t s11;
  119. uint32_t s12;
  120. uint32_t s13;
  121. uint32_t s14;
  122. uint32_t s15;
  123. uint32_t s16;
  124. uint32_t s17;
  125. uint32_t s18;
  126. uint32_t s19;
  127. uint32_t s20;
  128. uint32_t s21;
  129. uint32_t s22;
  130. uint32_t s23;
  131. uint32_t s24;
  132. uint32_t s25;
  133. uint32_t s26;
  134. uint32_t s27;
  135. uint32_t s28;
  136. uint32_t s29;
  137. uint32_t s30;
  138. uint32_t s31;
  139. uint32_t fpscr;
  140. #endif
  141. } software_stack_t;
  142. // The state of each thread (including thread 0)
  143. class ThreadInfo {
  144. public:
  145. int stack_size;
  146. uint8_t *stack=0;
  147. int my_stack = 0;
  148. software_stack_t save;
  149. volatile int flags = 0;
  150. void *sp;
  151. int ticks;
  152. #ifdef DEBUG
  153. unsigned long cyclesStart; // On T_4 the CycCnt is always active - on T_3.x it currently is not - unless Audio starts it AFAIK
  154. unsigned long cyclesAccum;
  155. #endif
  156. };
  157. extern "C" void unused_isr(void);
  158. typedef void (*ThreadFunction)(void*);
  159. typedef void (*ThreadFunctionInt)(int);
  160. typedef void (*ThreadFunctionNone)();
  161. typedef void (*IsrFunction)();
  162. /*
  163. * Threads handles all the threading interaction with users. It gets
  164. * instantiated in a global variable "threads".
  165. */
  166. class Threads {
  167. public:
  168. // The maximum number of threads is hard-coded to simplify
  169. // the implementation. See notes of ThreadInfo.
  170. static const int MAX_THREADS = 8;
  171. int DEFAULT_STACK_SIZE = 1024;
  172. const int DEFAULT_STACK0_SIZE = 10240; // estimate for thread 0?
  173. int DEFAULT_TICKS = 10;
  174. static const int DEFAULT_TICK_MICROSECONDS = 100;
  175. // State of threading system
  176. static const int STARTED = 1;
  177. static const int STOPPED = 2;
  178. static const int FIRST_RUN = 3;
  179. // State of individual threads
  180. static const int EMPTY = 0;
  181. static const int RUNNING = 1;
  182. static const int ENDED = 2;
  183. static const int ENDING = 3;
  184. static const int SUSPENDED = 4;
  185. static const int SVC_NUMBER = 0x21;
  186. static const int SVC_NUMBER_ACTIVE = 0x22;
  187. protected:
  188. int current_thread;
  189. int thread_count;
  190. int thread_error;
  191. /*
  192. * The maximum number of threads is hard-coded. Alternatively, we could implement
  193. * a linked list which would mean using up less memory for a small number of
  194. * threads while allowing an unlimited number of possible threads. This would
  195. * probably not slow down thread switching too much, but it would introduce
  196. * complexity and possibly bugs. So to simplifiy for now, we use an array.
  197. * But in the future, a linked list might be more appropriate.
  198. */
  199. ThreadInfo *threadp[MAX_THREADS];
  200. // This used to be allocated statically, as below. Kept for reference in case of bugs.
  201. // ThreadInfo thread[MAX_THREADS];
  202. public: // public for debugging
  203. static IsrFunction save_systick_isr;
  204. static IsrFunction save_svcall_isr;
  205. public:
  206. Threads();
  207. // Create a new thread for function "p", passing argument "arg". If stack is 0,
  208. // stack allocated on heap. Function "p" has form "void p(void *)".
  209. int addThread(ThreadFunction p, void * arg=0, int stack_size=-1, void *stack=0);
  210. // For: void f(int)
  211. int addThread(ThreadFunctionInt p, int arg=0, int stack_size=-1, void *stack=0) {
  212. return addThread((ThreadFunction)p, (void*)arg, stack_size, stack);
  213. }
  214. // For: void f()
  215. int addThread(ThreadFunctionNone p, int arg=0, int stack_size=-1, void *stack=0) {
  216. return addThread((ThreadFunction)p, (void*)arg, stack_size, stack);
  217. }
  218. // Get the state; see class constants. Can be EMPTY, RUNNING, etc.
  219. int getState(int id);
  220. // Explicityly set a state. See getState(). Call with care.
  221. int setState(int id, int state);
  222. // Wait until thread returns up to timeout_ms milliseconds. If ms is 0, wait
  223. // indefinitely.
  224. int wait(int id, unsigned int timeout_ms = 0);
  225. // Permanently stop a running thread. Thread will end on the next thread slice tick.
  226. int kill(int id);
  227. // Suspend a thread (on the next slice tick). Can be restarted with restart().
  228. int suspend(int id);
  229. // Restart a suspended thread.
  230. int restart(int id);
  231. // Set the slice length time in ticks for a thread (1 tick = 1 millisecond, unless using MicroTimer)
  232. void setTimeSlice(int id, unsigned int ticks);
  233. // Set the slice length time in ticks for all new threads (1 tick = 1 millisecond, unless using MicroTimer)
  234. void setDefaultTimeSlice(unsigned int ticks);
  235. // Set the stack size for new threads in bytes
  236. void setDefaultStackSize(unsigned int bytes_size);
  237. // Use the microsecond timer provided by IntervalTimer & PIT; instead of 1 tick = 1 millisecond,
  238. // 1 tick will be the number of microseconds provided (default is 100 microseconds)
  239. int setMicroTimer(int tick_microseconds = DEFAULT_TICK_MICROSECONDS);
  240. // Simple function to set each time slice to be 'milliseconds' long
  241. int setSliceMillis(int milliseconds);
  242. // Set each time slice to be 'microseconds' long
  243. int setSliceMicros(int microseconds);
  244. // Get the id of the currently running thread
  245. int id();
  246. int getStackUsed(int id);
  247. int getStackRemaining(int id);
  248. #ifdef DEBUG
  249. unsigned long getCyclesUsed(int id);
  250. #endif
  251. // Yield current thread's remaining time slice to the next thread, causing immediate
  252. // context switch
  253. void yield();
  254. // Wait for milliseconds using yield(), giving other slices your wait time
  255. void delay(int millisecond);
  256. // Start/restart threading system; returns previous state: STARTED, STOPPED, FIRST_RUN
  257. // can pass the previous state to restore
  258. int start(int old_state = -1);
  259. // Stop threading system; returns previous state: STARTED, STOPPED, FIRST_RUN
  260. int stop();
  261. // Allow these static functions and classes to access our members
  262. friend void context_switch(void);
  263. friend void context_switch_direct(void);
  264. friend void context_pit_isr(void);
  265. friend void threads_systick_isr(void);
  266. friend void threads_svcall_isr(void);
  267. friend void loadNextThread();
  268. friend class ThreadLock;
  269. protected:
  270. void getNextThread();
  271. void *loadstack(ThreadFunction p, void * arg, void *stackaddr, int stack_size);
  272. static void force_switch_isr();
  273. private:
  274. static void del_process(void);
  275. void yield_and_start();
  276. public:
  277. class Mutex {
  278. private:
  279. volatile int state = 0;
  280. volatile int waitthread = -1;
  281. volatile int waitcount = 0;
  282. public:
  283. int getState(); // get the lock state; 1=locked; 0=unlocked
  284. int lock(unsigned int timeout_ms = 0); // lock, optionally waiting up to timeout_ms milliseconds
  285. int try_lock(); // if lock available, get it and return 1; otherwise return 0
  286. int unlock(); // unlock if locked
  287. };
  288. class Scope {
  289. private:
  290. Mutex *r;
  291. public:
  292. Scope(Mutex& m) { r = &m; r->lock(); }
  293. ~Scope() { r->unlock(); }
  294. };
  295. class Suspend {
  296. private:
  297. int save_state;
  298. public:
  299. Suspend(); // Stop threads and save thread state
  300. ~Suspend(); // Restore saved state
  301. };
  302. template <class C> class GrabTemp {
  303. private:
  304. Mutex *lkp;
  305. public:
  306. C *me;
  307. GrabTemp(C *obj, Mutex *lk) { me = obj; lkp=lk; lkp->lock(); }
  308. ~GrabTemp() { lkp->unlock(); }
  309. C &get() { return *me; }
  310. };
  311. template <class T> class Grab {
  312. private:
  313. Mutex lk;
  314. T *me;
  315. public:
  316. Grab(T &t) { me = &t; }
  317. GrabTemp<T> grab() { return GrabTemp<T>(me, &lk); }
  318. operator T&() { return grab().get(); }
  319. T *operator->() { return grab().me; }
  320. Mutex &getLock() { return lk; }
  321. };
  322. #define ThreadWrap(OLDOBJ, NEWOBJ) Threads::Grab<decltype(OLDOBJ)> NEWOBJ(OLDOBJ);
  323. #define ThreadClone(NEWOBJ) (NEWOBJ.grab().get())
  324. };
  325. extern Threads threads;
  326. /*
  327. * Rudimentary compliance to C++11 class
  328. *
  329. * See http://www.cplusplus.com/reference/thread/thread/
  330. *
  331. * Example:
  332. * int x;
  333. * void thread_func() { x++; }
  334. * int main() {
  335. * std::thread(thread_func);
  336. * }
  337. *
  338. */
  339. namespace std {
  340. class thread {
  341. private:
  342. int id; // internal thread id
  343. int destroy; // flag to kill thread on instance destruction
  344. public:
  345. // By casting all (args...) to (void*), if there are more than one args, the compiler
  346. // will fail to find a matching function. This fancy template just allows any kind of
  347. // function to match.
  348. template <class F, class ...Args> explicit thread(F&& f, Args&&... args) {
  349. id = threads.addThread((ThreadFunction)f, (void*)args...);
  350. destroy = 1;
  351. }
  352. // If thread has not been detached when destructor called, then thread must end
  353. ~thread() {
  354. if (destroy) threads.kill(id);
  355. }
  356. // Threads are joinable until detached per definition, but in this implementation
  357. // that's not so. We emulate expected behavior anyway.
  358. bool joinable() { return destroy==1; }
  359. // Once detach() is called, thread runs until it terminates; otherwise it terminates
  360. // when destructor called.
  361. void detach() { destroy = 0; }
  362. // In theory, the thread merges with the running thread; if we just wait until
  363. // termination, it's basically the same thing except it's slower because
  364. // there are two threads running instead of one. Close enough.
  365. void join() { threads.wait(id); }
  366. // Get the unique thread id.
  367. int get_id() { return id; }
  368. };
  369. class mutex {
  370. private:
  371. Threads::Mutex mx;
  372. public:
  373. void lock() { mx.lock(); }
  374. bool try_lock() { return mx.try_lock(); }
  375. void unlock() { mx.unlock(); }
  376. };
  377. template <class cMutex> class lock_guard {
  378. private:
  379. cMutex *r;
  380. public:
  381. explicit lock_guard(cMutex& m) { r = &m; r->lock(); }
  382. ~lock_guard() { r->unlock(); }
  383. };
  384. }
  385. #endif