1 | #ifndef armv6_m__tl_h
|
2 | #define armv6_m__tl_h
|
3 |
|
4 | /*
|
5 | armv6-m/tl.h
|
6 | Copyright 2014 Marc Prager
|
7 |
|
8 | This file is part of the c-lpc8 library.
|
9 | c-lpc8 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
10 | as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
11 |
|
12 | c-lpc8 is published in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
13 | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
14 |
|
15 | You should have received a copy of the GNU General Public License along with c-lpc8.
|
16 | If not see <http://www.gnu.org/licenses/>
|
17 | */
|
18 |
|
19 | /** @file
|
20 | * @brief Thread loops - a simple context switcher between a thread in a loop and a second context.
|
21 | *
|
22 | * This module tl is intended for use in interrupt service routines to synchronized a sequential control flow and the
|
23 | * interrupt. It's based on cooperative multitasking. Focus is on simplicity.
|
24 | * tl works with infinite loops only - all threads loops have to continue working indefinitely. Any number of thread
|
25 | * loops is possible. Scheduling has to be done explicitely. The intended usage is as follows: main() inititializes
|
26 | * the TlContext structures (stack and nonterminating loop function) and calls tlCreate() for ever thread loop. That
|
27 | * 'starts' all threads and they run - one after the other - until the first tlYield() in every loop. Upon tlYield()
|
28 | * control is transferred back to main(). It is then the responsibility of main() (or an ISR!) to wake up the needed
|
29 | * thread loops by invoking tlCall() for the respective TlContext structure.
|
30 | * A simple round robin scheduler can be implemented by invoking tlCall() for each thread loop inside the main loop.
|
31 | */
|
32 |
|
33 | /** This data structure is shared between the two contexts an contains all information that is required for context
|
34 | * switching.
|
35 | */
|
36 | typedef struct {
|
37 | void* spThread; ///< has to be initialized to a valid (thread) stack pointer.
|
38 | void* spCaller; ///< set/re-set by tlCreate/tlCall.
|
39 | } TlContext;
|
40 |
|
41 | // #define NORETURN __attribute__((noreturn,nothrow));
|
42 | #define NORETURN // line above doesn't work, unfortunately
|
43 |
|
44 | /** A thread loop must be of this type. The function MUST NOT return, it has to be a loop.
|
45 | */
|
46 | typedef void TlLoop (TlContext *ctx) NORETURN;
|
47 |
|
48 | /** Creates a new thread loop. This function is typically called from the main thread. Currently it does not return
|
49 | * until the first tlYield() is executed inside the new thread.
|
50 | * @param ctx the context switch information storage
|
51 | * @param loop the thread function (not returning).
|
52 | */
|
53 | void tlCreate (TlContext *ctx, TlLoop *loop);
|
54 |
|
55 | /** This function yields control from the thread to the caller.
|
56 | * @param ctx the context switch information storage
|
57 | */
|
58 | void tlYield (TlContext *ctx);
|
59 |
|
60 | /** This function continues the thread at the latest yield() call. It will return on the next tlYield() in the thread.
|
61 | * @param ctx the context switch information storage
|
62 | */
|
63 | void tlCall (TlContext *ctx);
|
64 |
|
65 | #endif
|