From e8c5aff84d4e7a526d06fa2d8b11321370baab6e Mon Sep 17 00:00:00 2001 From: Kevin Hester <kevinh@geeksville.com> Date: Sat, 10 Oct 2020 15:32:31 +0800 Subject: [PATCH 1/5] add runOrDelay() for power efficient sleeping --- Thread.cpp | 15 +++++++++++---- Thread.h | 7 ++++++- ThreadController.cpp | 37 +++++++++++++++++++++++++++++++++++++ ThreadController.h | 6 ++++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Thread.cpp b/Thread.cpp index cd29d98..25b276b 100644 --- a/Thread.cpp +++ b/Thread.cpp @@ -31,12 +31,19 @@ void Thread::setInterval(unsigned long _interval){ _cached_next_run = last_run + interval; } -bool Thread::shouldRun(unsigned long time){ - // If the "sign" bit is set the signed difference would be negative - bool time_remaining = (time - _cached_next_run) & 0x80000000; +long Thread::tillRun(unsigned long time){ + if(!enabled) + return LONG_MAX; + else { + long time_remaining = (long) (_cached_next_run - time); + + return time_remaining; + } +} +bool Thread::shouldRun(unsigned long time){ // Exceeded the time limit, AND is enabled? Then should run... - return !time_remaining && enabled; + return tillRun(time) <= 0; } void Thread::onRun(void (*callback)(void)){ diff --git a/Thread.h b/Thread.h index 0e580a9..fec4242 100644 --- a/Thread.h +++ b/Thread.h @@ -74,11 +74,16 @@ class Thread{ virtual void setInterval(unsigned long _interval); // Return if the Thread should be runned or not - virtual bool shouldRun(unsigned long time); + // Note: no longer virtual - instead override tillRun + bool shouldRun(unsigned long time); // Default is to check whether it should run "now" bool shouldRun() { return shouldRun(millis()); } + // Return # of msecs till this thread will run again (or MAXINT if it is disabled). + // If it is overdue the value will be negative + virtual long tillRun(unsigned long time); + // Callback set void onRun(void (*callback)(void)); diff --git a/ThreadController.cpp b/ThreadController.cpp index 7d8e41c..58c7c08 100644 --- a/ThreadController.cpp +++ b/ThreadController.cpp @@ -38,6 +38,43 @@ void ThreadController::run(){ runned(); } +// Try to run our threads, return how long we can sleep before next needed +long ThreadController::runOrDelay(){ + // Run this thread before + if(_onRun != NULL) + _onRun(); + + unsigned long time = millis(); + int checks = 0; + long tillNext = LONG_MAX; + nextThread = NULL; + for(int i = 0; i < MAX_THREADS && checks < cached_size; i++){ + // Object exists? Is enabled? Timeout exceeded? + Thread *t = thread[i]; + if(t){ + checks++; + + long threadNext = t->tillRun(time); + if(threadNext <= 0){ // This thread is ready to run right now + t->run(); + // threadNext = t->tillRun(time); // Check when the current thread's new deadline + + tillNext = 0; // we ran something this tick, therefore tell caller it should skip the delay this time + nextThread = t; + } + else if(threadNext < tillNext) { + tillNext = threadNext; + nextThread = t; + } + } + } + + // ThreadController extends Thread, so we should flag as runned thread + runned(); + + return tillNext; +} + /* List controller (boring part) diff --git a/ThreadController.h b/ThreadController.h index 8e2888c..84022f5 100644 --- a/ThreadController.h +++ b/ThreadController.h @@ -31,6 +31,9 @@ class ThreadController: public Thread{ // run() Method is overrided void run(); + // Try to run our threads, return how long we can sleep before next needed. + long runOrDelay(); + // Adds a thread in the first available slot (remove first) // Returns if the Thread could be added or not bool add(Thread* _thread); @@ -48,6 +51,9 @@ class ThreadController: public Thread{ // Return the I Thread on the array // Returns NULL if none found Thread* get(int index); + + // For debugging it is useful to know the next child thread we want to execute + Thread* nextThread = NULL; }; #endif From 992fafcfd476494203146e87c489642e5745102f Mon Sep 17 00:00:00 2001 From: Kevin Hester <kevinh@geeksville.com> Date: Sun, 11 Oct 2020 08:13:56 +0800 Subject: [PATCH 2/5] add canSleep for threads that shouldn't wake the scheduler --- Thread.h | 3 +++ ThreadController.cpp | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Thread.h b/Thread.h index fec4242..7571010 100644 --- a/Thread.h +++ b/Thread.h @@ -60,6 +60,9 @@ class Thread{ // If the current Thread is enabled or not bool enabled; + // If true this thread wanting to run will not be used to prevent sleeping in runWithDelay + bool canSleep = false; + // ID of the Thread (initialized from memory adr.) int ThreadID; diff --git a/ThreadController.cpp b/ThreadController.cpp index 58c7c08..4875234 100644 --- a/ThreadController.cpp +++ b/ThreadController.cpp @@ -59,10 +59,12 @@ long ThreadController::runOrDelay(){ t->run(); // threadNext = t->tillRun(time); // Check when the current thread's new deadline - tillNext = 0; // we ran something this tick, therefore tell caller it should skip the delay this time - nextThread = t; + if(!t->canSleep) { + tillNext = 0; // we ran something this tick, therefore tell caller it should skip the delay this time + nextThread = t; + } } - else if(threadNext < tillNext) { + else if(threadNext < tillNext && !t->canSleep) { tillNext = threadNext; nextThread = t; } From 6dd2272a5a6f4aeab09a23066d774382864b41f6 Mon Sep 17 00:00:00 2001 From: Kevin Hester <kevinh@geeksville.com> Date: Sun, 11 Oct 2020 08:51:42 +0800 Subject: [PATCH 3/5] Use ANSI name for LONG_MAX - fix build for nrf52 --- Thread.cpp | 2 +- ThreadController.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Thread.cpp b/Thread.cpp index 25b276b..ac0e6bd 100644 --- a/Thread.cpp +++ b/Thread.cpp @@ -33,7 +33,7 @@ void Thread::setInterval(unsigned long _interval){ long Thread::tillRun(unsigned long time){ if(!enabled) - return LONG_MAX; + return __LONG_MAX__; else { long time_remaining = (long) (_cached_next_run - time); diff --git a/ThreadController.cpp b/ThreadController.cpp index 4875234..82a5363 100644 --- a/ThreadController.cpp +++ b/ThreadController.cpp @@ -46,7 +46,7 @@ long ThreadController::runOrDelay(){ unsigned long time = millis(); int checks = 0; - long tillNext = LONG_MAX; + long tillNext = __LONG_MAX__; nextThread = NULL; for(int i = 0; i < MAX_THREADS && checks < cached_size; i++){ // Object exists? Is enabled? Timeout exceeded? From 333ffd09b596977c217ba25da4258f588b462ac6 Mon Sep 17 00:00:00 2001 From: Kevin Hester <kevinh@geeksville.com> Date: Sun, 11 Oct 2020 09:13:56 +0800 Subject: [PATCH 4/5] fix thread id to also work on 64 bit OSes --- Thread.cpp | 2 +- Thread.h | 2 +- ThreadController.cpp | 2 +- ThreadController.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Thread.cpp b/Thread.cpp index ac0e6bd..b5c3dc3 100644 --- a/Thread.cpp +++ b/Thread.cpp @@ -6,7 +6,7 @@ Thread::Thread(void (*callback)(void), unsigned long _interval){ _cached_next_run = 0; last_run = millis(); - ThreadID = (int)this; + ThreadID = (size_t)this; #ifdef USE_THREAD_NAMES ThreadName = "Thread "; ThreadName = ThreadName + ThreadID; diff --git a/Thread.h b/Thread.h index 7571010..9fde34a 100644 --- a/Thread.h +++ b/Thread.h @@ -64,7 +64,7 @@ class Thread{ bool canSleep = false; // ID of the Thread (initialized from memory adr.) - int ThreadID; + size_t ThreadID; #ifdef USE_THREAD_NAMES // Thread Name (used for better UI). diff --git a/ThreadController.cpp b/ThreadController.cpp index 82a5363..68ea202 100644 --- a/ThreadController.cpp +++ b/ThreadController.cpp @@ -102,7 +102,7 @@ bool ThreadController::add(Thread* _thread){ return false; } -void ThreadController::remove(int id){ +void ThreadController::remove(size_t id){ // Find Threads with the id, and removes for(int i = 0; i < MAX_THREADS; i++){ if(thread[i]->ThreadID == id){ diff --git a/ThreadController.h b/ThreadController.h index 84022f5..cb8bef9 100644 --- a/ThreadController.h +++ b/ThreadController.h @@ -39,7 +39,7 @@ class ThreadController: public Thread{ bool add(Thread* _thread); // remove the thread (given the Thread* or ThreadID) - void remove(int _id); + void remove(size_t _id); void remove(Thread* _thread); // Removes all threads From 72921ac222eed6f526ba1682023cee290d9aa1b3 Mon Sep 17 00:00:00 2001 From: Kevin Hester <kevinh@geeksville.com> Date: Sun, 14 Feb 2021 15:03:50 +0800 Subject: [PATCH 5/5] Increase max threads to 32 --- ThreadController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ThreadController.h b/ThreadController.h index cb8bef9..2ed46a3 100644 --- a/ThreadController.h +++ b/ThreadController.h @@ -19,7 +19,7 @@ #include "Thread.h" #include "inttypes.h" -#define MAX_THREADS 15 +#define MAX_THREADS 32 class ThreadController: public Thread{ protected: