Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of MicroBitDALImageRewrite by
MicroBitFiber.h
00001 /** 00002 * Definitions for the MicroBit Fiber scheduler. 00003 * 00004 * This lightweight, non-preemptive scheduler provides a simple threading mechanism for two main purposes: 00005 * 00006 * 1) To provide a clean abstraction for application languages to use when building async behaviour (callbacks). 00007 * 2) To provide ISR decoupling for Messagebus events generted in an ISR context. 00008 */ 00009 00010 #ifndef MICROBIT_FIBER_H 00011 #define MICROBIT_FIBER_H 00012 00013 #include "mbed.h" 00014 #include "MicroBitMessageBus.h" 00015 00016 // Typical stack size of each fiber. 00017 // A physical stack of anything less than 512 will likely hit overflow issues during ISR/mBed calls. 00018 // However, as we're running a co=operative fiber scheduler, the size of the stack at the point of 00019 // context switching is normally *very* small (circa 12 bytes!). Also, as we're likely to have many short lived threads 00020 // being used, be actually perform a stack duplication on context switch, which keeps the RAM footprint of a fiber 00021 // down to a minimum, without constraining what can be done insode a fiber context. 00022 // 00023 // TODO: Consider a split mode scheduler, that monitors used stack size, and maintains a dedicated, persistent 00024 // stack for any long lived fibers with large stacks. 00025 // 00026 #define FIBER_STACK_SIZE 512 00027 #define FIBER_TICK_PERIOD_MS 2 00028 #define CORTEX_M0_STACK_BASE (0x20004000 - 4) 00029 00030 /** 00031 * Thread Context for an ARM Cortex M0 core. 00032 * 00033 * This is probably overkill, but the ARMCC compiler uses a lot register optimisation 00034 * in its calling conventions, so better safe than sorry. :-) 00035 * 00036 * TODO: Check with ARM guys to see is they have suggestions to optimize this context block 00037 */ 00038 struct Cortex_M0_TCB 00039 { 00040 uint32_t R0; 00041 uint32_t R1; 00042 uint32_t R2; 00043 uint32_t R3; 00044 uint32_t R4; 00045 uint32_t R5; 00046 uint32_t R6; 00047 uint32_t R7; 00048 uint32_t R8; 00049 uint32_t R9; 00050 uint32_t R10; 00051 uint32_t R11; 00052 uint32_t R12; 00053 uint32_t SP; 00054 uint32_t LR; 00055 }; 00056 00057 /** 00058 * Representation of a single Fiber 00059 */ 00060 00061 struct Fiber 00062 { 00063 uint32_t stack_top, stack_bottom; // Address of this Fiber's stack. Stack is heap allocated, and full descending. 00064 Cortex_M0_TCB tcb; // Thread context when last scheduled out. 00065 uint32_t context; // Context specific information. 00066 Fiber **queue; // The queue this fiber is stored on. 00067 Fiber *next, *prev; // Position of this Fiber on the run queues. 00068 }; 00069 00070 00071 /** 00072 * Initialises the Fiber scheduler. 00073 * Creates a Fiber context around the calling thread, and adds it to the run queue as the current thread. 00074 * 00075 * This function must be called once only from the main thread, and before any other Fiber operation. 00076 */ 00077 void scheduler_init(); 00078 00079 /** 00080 * Creates a new Fiber, and launches it. 00081 * 00082 * @param entry_fn The function the new Fiber will begin execution in. 00083 * @return The new Fiber. 00084 */ 00085 Fiber *create_fiber(void (*entry_fn)(void)); 00086 00087 /** 00088 * Exit point for all fibers. 00089 * Any fiber reaching the end of its entry function will return here for recycling. 00090 */ 00091 void release_fiber(void); 00092 00093 00094 /** 00095 * Calls the Fiber scheduler. 00096 * The calling Fiber will likely be blocked, and control given to another waiting fiber. 00097 * Call this to yield control of the processor when you have nothing more to do. 00098 */ 00099 void schedule(); 00100 00101 /** 00102 * Blocks the calling thread for the given period of time. 00103 * The calling thread will be immediatley descheduled, and placed onto a 00104 * wait queue until the requested amount of time has elapsed. 00105 * 00106 * n.b. the fiber will not be be made runnable until after the elasped time, but there 00107 * are no guarantees precisely when the fiber will next be scheduled. 00108 * 00109 * @param t The period of time to sleep, in milliseconds. 00110 */ 00111 void fiber_sleep(unsigned long t); 00112 00113 /** 00114 * Timer callback. Called from interrupt context, once every FIBER_TICK_PERIOD_MS milliseconds. 00115 * Simply checks to determine if any fibers blocked on the sleep queue need to be woken up 00116 * and made runnable. 00117 */ 00118 void scheduler_tick(); 00119 00120 /** 00121 * Utility function to add the currenty running fiber to the given queue. 00122 * Perform a simple add at the head, to avoid complexity, 00123 * Queues are normally very short, so maintaining a doubly linked, sorted list typically outweighs the cost of 00124 * brute force searching. 00125 * 00126 * @param f The fiber to add to the queue 00127 * @param queue The run queue to add the fiber to. 00128 */ 00129 void queue_fiber(Fiber *f, Fiber **queue); 00130 00131 /** 00132 * Utility function to the given fiber from whichever queue it is currently stored on. 00133 * @param f the fiber to remove. 00134 */ 00135 void dequeue_fiber(Fiber *f); 00136 00137 /** 00138 * IDLE task. 00139 * Only scheduled for execution when the runqueue is empty. 00140 * Performs a procressor sleep operation, then returns to the scheduler - most likely after a timer interrupt. 00141 */ 00142 void idle_task(); 00143 00144 /** 00145 * Assembler Ccontext switch routing. 00146 * Defined in CortexContextSwitch.s 00147 */ 00148 extern "C" void swap_context(Cortex_M0_TCB *from, Cortex_M0_TCB *to, uint32_t from_stack, uint32_t to_stack); 00149 extern "C" void save_context(Cortex_M0_TCB *tcb, uint32_t stack); 00150 00151 /** 00152 * Time since power on. Measured in milliseconds. 00153 * When stored as an unsigned long, this gives us approx 50 days between rollover, which is ample. :-) 00154 */ 00155 extern unsigned long ticks; 00156 00157 #endif
Generated on Thu Jul 14 2022 13:31:29 by
