From 9ccdd25e9f2937f43447e771a68492305c2bcbb6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 19 Sep 2015 11:45:45 +0100 Subject: [PATCH] microbit: Allow to run the idle task within the current fiber's stack. If there is only 1 main fiber (plus the idle fiber) then enabling this new feature for the main fiber (using fiber_allow_run_idle_within()) will mean that no heap is needed to swap the stack out. --- inc/MicroBitFiber.h | 7 +++++++ source/MicroBitFiber.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/inc/MicroBitFiber.h b/inc/MicroBitFiber.h index 8e31f99..b560663 100644 --- a/inc/MicroBitFiber.h +++ b/inc/MicroBitFiber.h @@ -24,6 +24,7 @@ #define MICROBIT_FIBER_FLAG_FOB 0x01 #define MICROBIT_FIBER_FLAG_PARENT 0x02 #define MICROBIT_FIBER_FLAG_CHILD 0x04 +#define MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN 0x08 /** * Thread Context for an ARM Cortex M0 core. @@ -118,6 +119,12 @@ Fiber *create_fiber(void (*entry_fn)(void), void (*completion_fn)(void) = releas */ Fiber *create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)(void *) = release_fiber); +/** + * Allow the idle thread to run within the current thread's stack frame. + * This is useful to prevent paging of the thread's stack to the heap. + */ +void fiber_allow_run_idle_within(); + /** diff --git a/source/MicroBitFiber.cpp b/source/MicroBitFiber.cpp index 636f485..080206c 100644 --- a/source/MicroBitFiber.cpp +++ b/source/MicroBitFiber.cpp @@ -226,6 +226,15 @@ void scheduler_event(MicroBitEvent evt) } } +/** + * Allow the idle thread to run within the current thread's stack frame. + * This is useful to prevent paging of the thread's stack to the heap. + */ +void fiber_allow_run_idle_within() +{ + currentFiber->flags |= MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN; +} + /** * Blocks the calling thread for the given period of time. @@ -622,6 +631,29 @@ void schedule() // Otherwise, just pick the head of the run queue. currentFiber = runQueue; + if (currentFiber == idle && oldFiber->flags & MICROBIT_FIBER_FLAG_RUN_IDLE_WITHIN) + { + // Run the idle task right here using the old fiber's stack. + // Keep idling while the runqueue is empty, or there is data to process. + do + { + uBit.systemTasks(); + + if(scheduler_runqueue_empty()) + { + if (uBit.ble) + uBit.ble->waitForEvent(); + else + __WFI(); + } + } + while (runQueue == NULL || fiber_flags & MICROBIT_FLAG_DATA_READY); + + // Switch to a non-idle fiber. + // If this fiber is the same as the old one then there'll be no switching at all. + currentFiber = runQueue; + } + // Swap to the context of the chosen fiber, and we're done. // Don't bother with the overhead of switching if there's only one fiber on the runqueue! if (currentFiber != oldFiber)