coroutines: wip compiles but does not link

This commit is contained in:
Kevin Hester
2020-10-09 14:16:51 +08:00
parent 10f64590a9
commit 2044427e97
23 changed files with 132 additions and 299 deletions

View File

@@ -1,37 +1,45 @@
#pragma once
#include "WorkerThread.h"
#include "OSThread.h"
namespace concurrency {
namespace concurrency
{
/**
* @brief A worker thread that waits on a freertos notification
*/
class NotifiedWorkerThread : public WorkerThread
class NotifiedWorkerThread : public OSThread
{
public:
NotifiedWorkerThread(const char *name) : OSThread(name) {}
/**
* Notify this thread so it can run
*/
virtual void notify(uint32_t v = 0, eNotifyAction action = eNoAction) = 0;
void notify(uint32_t v, bool overwrite);
/**
* Notify from an ISR
*
* This must be inline or IRAM_ATTR on ESP32
*/
virtual void notifyFromISR(BaseType_t *highPriWoken, uint32_t v = 0, eNotifyAction action = eNoAction) { notify(v, action); }
protected:
/**
* The notification that was most recently used to wake the thread. Read from loop()
*/
uint32_t notification = 0;
void notifyFromISR(BaseType_t *highPriWoken, uint32_t v, bool overwrite) { notify(v, overwrite); }
/**
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
* Schedule a notification to fire in delay msecs
*/
virtual void block() = 0;
void notifyLater(uint32_t delay, uint32_t v, bool overwrite);
protected:
virtual void onNotify(uint32_t notification) = 0;
virtual uint32_t runOnce();
private:
/**
* The notification that was most recently used to wake the thread. Read from runOnce()
*/
uint32_t notification = 0;
};
} // namespace concurrency

View File

@@ -4,11 +4,13 @@
#include <stdint.h>
#include "Thread.h"
#include "freertosinc.h"
#include "ThreadController.h"
namespace concurrency
{
extern ThreadController mainController, timerController;
/**
* @brief Base threading
*
@@ -17,23 +19,32 @@ namespace concurrency
* sleeping the correct amount of time in main
* NotifiedWorkerThread set/clears enabled
*
* notifyLater should start now - not relative to last start time
* clear notification before calling handler
*
* stopping sleep instantly as soon as an event occurs.
* use global functions delayTillWakeEvent(time), doWakeEvent(isInISR) - use freertos mutex or somesuch
*
* have router thread block on its message queue in runOnce
*
* remove lock/lockguard
*/
class OSThread
class OSThread : public Thread
{
public:
virtual ~OSThread() {}
ThreadController *controller;
// uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); }
public:
OSThread(const char *name, uint32_t period = 0, ThreadController *controller = &mainController);
virtual ~OSThread();
protected:
/**
* The method that will be called each time our thread gets a chance to run
*
* Returns desired period for next invocation (or 0 for no change)
*/
virtual void runOnce() = 0;
virtual uint32_t runOnce() = 0;
};
} // namespace concurrency

View File

@@ -1,26 +1,24 @@
#pragma once
#include "PeriodicTask.h"
#include "concurrency/OSThread.h"
namespace concurrency {
namespace concurrency
{
/**
* @brief Periodically invoke a callback. This just provides C-style callback conventions
* @brief Periodically invoke a callback. This just provides C-style callback conventions
* rather than a virtual function - FIXME, remove?
*/
class Periodic : public PeriodicTask
class Periodic : public OSThread
{
uint32_t (*callback)();
public:
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
Periodic(uint32_t (*_callback)()) : callback(_callback) {}
Periodic(const char *name, uint32_t (*_callback)()) : OSThread(name), callback(_callback) {}
protected:
void doTask() {
uint32_t p = callback();
setPeriod(p);
}
uint32_t runOnce() { return callback(); }
};
} // namespace concurrency

View File

@@ -1,16 +0,0 @@
#include "PeriodicTask.h"
#include "Periodic.h"
#include "LockGuard.h"
namespace concurrency {
PeriodicScheduler periodicScheduler;
PeriodicTask::PeriodicTask(uint32_t initialPeriod) : period(initialPeriod) {}
void PeriodicTask::setup()
{
periodicScheduler.schedule(this);
}
} // namespace concurrency

View File

@@ -1,54 +0,0 @@
#pragma once
#include <Arduino.h>
#include "PeriodicScheduler.h"
namespace concurrency {
/**
* @brief A base class for tasks that want their doTask() method invoked periodically
*
* @todo currently just syntatic sugar for polling in loop (you must call .loop), but eventually
* generalize with the freertos scheduler so we can save lots of power by having everything either in
* something like this or triggered off of an irq.
*/
class PeriodicTask
{
uint32_t lastMsec = 0;
uint32_t period = 1; // call soon after creation
public:
virtual ~PeriodicTask() { periodicScheduler.unschedule(this); }
/**
* Constructor (will schedule with the global PeriodicScheduler)
*/
PeriodicTask(uint32_t initialPeriod = 1);
/**
* MUST be be called once at startup (but after threading is running - i.e. not from a constructor)
*/
void setup();
/**
* Set a new period in msecs (can be called from doTask or elsewhere and the scheduler will cope)
* While zero this task is disabled and will not run
*/
void setPeriod(uint32_t p)
{
lastMsec = millis(); // reset starting from now
period = p;
}
uint32_t getPeriod() const { return period; }
/**
* Syntatic sugar for suspending tasks
*/
void disable();
protected:
virtual void doTask() = 0;
};
} // namespace concurrency

View File

@@ -1,31 +0,0 @@
#include "WorkerThread.h"
namespace concurrency {
void WorkerThread::doRun()
{
startWatchdog();
while (!wantExit) {
stopWatchdog();
block();
startWatchdog();
// no need - startWatchdog is guaranteed to give us one full watchdog interval
// serviceWatchdog(); // Let our loop worker have one full watchdog interval (at least) to run
#ifdef DEBUG_STACK
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 10 * 1000L) {
lastPrint = millis();
meshtastic::printThreadInfo("net");
}
#endif
loop();
}
stopWatchdog();
}
} // namespace concurrency

View File

@@ -1,25 +0,0 @@
#pragma once
#include "OSThread.h"
namespace concurrency
{
/**
* @brief This wraps threading (FreeRTOS for now) with a blocking API intended for efficiently converting
* old-school arduino loop() code. Use as a mixin base class for the classes you want to convert.
*
* @link https://www.freertos.org/RTOS_Task_Notification_As_Mailbox.html
*/
class WorkerThread : public OSThread
{
protected:
/**
* Return true if this thread is ready to run - either waiting ona queue/mutex or a "task notification"
*/
virtual bool shouldRun() = 0;
virtual void loop() = 0;
};
} // namespace concurrency