From d7c9b97ff661aa3fff4c54dfa86f3bf8a20e54a8 Mon Sep 17 00:00:00 2001 From: Dario Pennisi Date: Tue, 1 Sep 2020 20:05:56 +0200 Subject: [PATCH 1/2] added subclassing and methods for thread synchronization --- Arduino_Threads.h | 99 ++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 65 deletions(-) diff --git a/Arduino_Threads.h b/Arduino_Threads.h index 6a69c2e..ff8c74a 100644 --- a/Arduino_Threads.h +++ b/Arduino_Threads.h @@ -33,78 +33,47 @@ class Shared // template definition #define INCF(F) INCF_(F) #define INCF_(F) #F -class ArduinoThreadClass { -public: - void add(rtos::Thread* me) { - if (controller == NULL) { - controller = new rtos::Thread(osPriorityHigh, 512); - controller->start(mbed::callback(this, &ArduinoThreadClass::loop)); - } - list[idx++] = me; - } - - void ping(rtos::Thread* me) { - for (int i=0; i < idx; i++) { - if (me == list[i]) { - timestamps[i] = millis(); - } - } - } +#define _macroToString(sequence) #sequence -private: - void loop() { - while (1) { - for (int i = 0; i < idx; i++) { - if (millis() - timestamps[i] > 5000) { - // list[i]->terminate(); - // TODO: reorder threads and make list[i] == NULL - // Serial.println(list[i]->get_name() + String(" killed ")); - } - } - delay(1000); +class ArduinoThreads { + private: + rtos::EventFlags *GlobalEvents; + rtos::EventFlags ThreadEvents; + virtual void setup(void) {}; + virtual void loop(void) {}; + void execute() { + setup(); + if (GlobalEvents!=NULL) GlobalEvents->wait_all(LoopStart); + while ( (GlobalEvents==NULL || !(GlobalEvents->get()&LoopStop) ) && + !(ThreadEvents.get()&LoopStop) ) { + loop(); + } + } + rtos::Thread t; + public: + typedef enum { + LoopStart= (1<<0), + LoopStop= (1<<1) + } Events; + void start(rtos::EventFlags *event = NULL) { + GlobalEvents = event; + t.start(mbed::callback(this, &ArduinoThreads::execute)); + } + void terminate() { + t.terminate(); + } + void stop() { + ThreadEvents.set(LoopStop); } - } - - rtos::Thread* controller = NULL; - rtos::Thread* list[10] = {NULL}; - uint32_t timestamps[10] = {0}; - int idx = 0; }; -ArduinoThreadClass ArduinoThread; - -#define _macroToString(sequence) #sequence - -#define THD_ENTER(tabname) class CONCAT(tabname, Class) { \ +#define THD_ENTER(tabname) class CONCAT(tabname, Class) : public ArduinoThreads { \ +private: -#define THD_DONE(tabname) private: \ - void execute() { \ - ArduinoThread.add(t); \ - setup(); \ - while (1) { \ - loop(); \ - ArduinoThread.ping(t); \ - } \ - } \ - rtos::Thread* t; \ - \ - public: \ - void start(int stacksize = 4096) { \ - t = new rtos::Thread(osPriorityNormal, stacksize, nullptr, _macroToString(tabname)); \ - t->start(mbed::callback(this, &CONCAT(tabname,Class)::execute)); \ - } \ - void begin() { \ - start(); \ - } \ -}; \ +#define THD_DONE(tabname) \ +}; \ CONCAT(tabname,Class) tabname; -/* -#define NEWTHREAD(tabname) THD_ENTER(tabname) \ - \#include CONCAT(tabname, .h) \ - THD_DONE(tabname) -*/ - #include "Wire.h" #include "SerialDispatcher.h" \ No newline at end of file From 50c30b65df010d89c4d7f00b8c76eef9720f072e Mon Sep 17 00:00:00 2001 From: Dario Pennisi Date: Thu, 3 Sep 2020 19:08:59 +0200 Subject: [PATCH 2/2] restored stack size and added better synchronization primitives --- Arduino_Threads.h | 70 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/Arduino_Threads.h b/Arduino_Threads.h index ff8c74a..1d5935c 100644 --- a/Arduino_Threads.h +++ b/Arduino_Threads.h @@ -38,36 +38,70 @@ class Shared // template definition class ArduinoThreads { private: - rtos::EventFlags *GlobalEvents; - rtos::EventFlags ThreadEvents; + static rtos::EventFlags globalEvents; + uint32_t startFlags; + uint32_t stopFlags; + uint32_t loopDelay; virtual void setup(void) {}; virtual void loop(void) {}; void execute() { setup(); - if (GlobalEvents!=NULL) GlobalEvents->wait_all(LoopStart); - while ( (GlobalEvents==NULL || !(GlobalEvents->get()&LoopStop) ) && - !(ThreadEvents.get()&LoopStop) ) { - loop(); - } + // if startFlags have been passed then wait until all the flags are set + // before starting the loop. this is used to synchronize loops from multiple + // sketches. + globalEvents.wait_all(startFlags); + // if stopFlags have been passed stop when all the flags are set + // otherwise loop forever + while ( 1 ) { + loop(); + // on exit clear the flags that have forced us to stop. + // note that if two groups of sketches stop on common flags + // the first group will clear them so the second group may never + // exit + if (stopFlags!=0) { + if ((globalEvents.get()&stopFlags)!=stopFlags) { + globalEvents.clear(stopFlags); + return; + } + if ((rtos::ThisThread::flags_get()&stopFlags)!=stopFlags) { + rtos::ThisThread::flags_clear(stopFlags); + return; + } + } + // sleep for the time we've been asked to insert between loops + rtos::ThisThread::sleep_for(loopDelay); + } } - rtos::Thread t; + rtos::Thread *t; public: - typedef enum { - LoopStart= (1<<0), - LoopStop= (1<<1) - } Events; - void start(rtos::EventFlags *event = NULL) { - GlobalEvents = event; - t.start(mbed::callback(this, &ArduinoThreads::execute)); + // start this sketch + void start(int stacksize = 4096, uint32_t startFlags=0, uint32_t stopFlags=0) { + this->startFlags = startFlags; + this->stopFlags = stopFlags; + loopDelay=0; + t = new rtos::Thread(osPriorityNormal, stacksize, nullptr, _macroToString(tabname)); + t->start(mbed::callback(this, &ArduinoThreads::execute)); } + // kill this sketch void terminate() { - t.terminate(); + t->terminate(); } - void stop() { - ThreadEvents.set(LoopStop); + // send an event to all sketches at the same time + static void broadcastEvent(uint32_t event) { + globalEvents.set(event); + } + // send an event only to this sketch + void sendEvent(uint32_t event) { + t->flags_set(event); + } + // set the rate at which loop function will be called + void setLoopDelay(uint32_t delay) { + loopDelay = delay; } }; +rtos::EventFlags ArduinoThreads::globalEvents; + #define THD_ENTER(tabname) class CONCAT(tabname, Class) : public ArduinoThreads { \ private: