Microbug / MicroBitDAL_SB2_TEST

Fork of MicroBitDALImageRewrite by Joe Finney

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBitFiber.h Source File

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