mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-09 06:32:06 +00:00
refactored threading-related classes, code broken
This commit is contained in:
parent
64da384fc1
commit
0a6059ba13
9
.gitignore
vendored
9
.gitignore
vendored
@ -8,3 +8,12 @@ main/credentials.h
|
|||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.autotools
|
||||||
|
.built
|
||||||
|
.context
|
||||||
|
.cproject
|
||||||
|
.idea/*
|
||||||
|
.vagrant
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
#include "WorkerThread.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#ifdef configUSE_PREEMPTION
|
|
||||||
|
|
||||||
void Thread::start(const char *name, size_t stackSize, uint32_t priority)
|
|
||||||
{
|
|
||||||
auto r = xTaskCreate(callRun, name, stackSize, this, priority, &taskHandle);
|
|
||||||
assert(r == pdPASS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::callRun(void *_this)
|
|
||||||
{
|
|
||||||
((Thread *)_this)->doRun();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorkerThread::doRun()
|
|
||||||
{
|
|
||||||
while (!wantExit) {
|
|
||||||
block();
|
|
||||||
|
|
||||||
#ifdef DEBUG_STACK
|
|
||||||
static uint32_t lastPrint = 0;
|
|
||||||
if (millis() - lastPrint > 10 * 1000L) {
|
|
||||||
lastPrint = millis();
|
|
||||||
meshtastic::printThreadInfo("net");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
loop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify this thread so it can run
|
|
||||||
*/
|
|
||||||
void NotifiedWorkerThread::notify(uint32_t v, eNotifyAction action)
|
|
||||||
{
|
|
||||||
xTaskNotify(taskHandle, v, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifiedWorkerThread::block()
|
|
||||||
{
|
|
||||||
xTaskNotifyWait(0, // don't clear notification on entry
|
|
||||||
clearOnRead, ¬ification, portMAX_DELAY); // Wait forever
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,96 +0,0 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include "freertosinc.h"
|
|
||||||
|
|
||||||
#ifdef HAS_FREE_RTOS
|
|
||||||
|
|
||||||
class Thread
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
TaskHandle_t taskHandle = NULL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set this to true to ask thread to cleanly exit asap
|
|
||||||
*/
|
|
||||||
volatile bool wantExit = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void start(const char *name, size_t stackSize = 1024, uint32_t priority = tskIDLE_PRIORITY);
|
|
||||||
|
|
||||||
virtual ~Thread() { vTaskDelete(taskHandle); }
|
|
||||||
|
|
||||||
uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* The method that will be called when start is called.
|
|
||||||
*/
|
|
||||||
virtual void doRun() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void callRun(void *_this);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This wraps threading (FreeRTOS for now) with a blocking API intended for efficiently converting onlyschool arduino loop() code.
|
|
||||||
*
|
|
||||||
* Use as a mixin base class for the classes you want to convert.
|
|
||||||
*
|
|
||||||
* https://www.freertos.org/RTOS_Task_Notification_As_Mailbox.html
|
|
||||||
*/
|
|
||||||
class WorkerThread : public Thread
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
|
|
||||||
*/
|
|
||||||
virtual void block() = 0;
|
|
||||||
|
|
||||||
virtual void loop() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The method that will be called when start is called.
|
|
||||||
*/
|
|
||||||
virtual void doRun();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A worker thread that waits on a freertos notification
|
|
||||||
*/
|
|
||||||
class NotifiedWorkerThread : public WorkerThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Notify this thread so it can run
|
|
||||||
*/
|
|
||||||
void notify(uint32_t v = 0, eNotifyAction action = eNoAction);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify from an ISR
|
|
||||||
*
|
|
||||||
* This must be inline or IRAM_ATTR on ESP32
|
|
||||||
*/
|
|
||||||
inline void notifyFromISR(BaseType_t *highPriWoken, uint32_t v = 0, eNotifyAction action = eNoAction)
|
|
||||||
{
|
|
||||||
xTaskNotifyFromISR(taskHandle, v, action, highPriWoken);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* The notification that was most recently used to wake the thread. Read from loop()
|
|
||||||
*/
|
|
||||||
uint32_t notification = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* What notification bits should be cleared just after we read and return them in notification?
|
|
||||||
*
|
|
||||||
* Defaults to clear all of them.
|
|
||||||
*/
|
|
||||||
uint32_t clearOnRead = UINT32_MAX;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
|
|
||||||
*/
|
|
||||||
virtual void block();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
23
src/concurrency/Lock.cpp
Normal file
23
src/concurrency/Lock.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "Lock.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
Lock::Lock()
|
||||||
|
{
|
||||||
|
handle = xSemaphoreCreateBinary();
|
||||||
|
assert(handle);
|
||||||
|
assert(xSemaphoreGive(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lock::lock()
|
||||||
|
{
|
||||||
|
assert(xSemaphoreTake(handle, portMAX_DELAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lock::unlock()
|
||||||
|
{
|
||||||
|
assert(xSemaphoreGive(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace concurrency
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#include "freertosinc.h"
|
#include "freertosinc.h"
|
||||||
|
|
||||||
namespace meshtastic
|
namespace concurrency {
|
||||||
{
|
|
||||||
|
|
||||||
// Simple wrapper around FreeRTOS API for implementing a mutex lock.
|
// Simple wrapper around FreeRTOS API for implementing a mutex lock.
|
||||||
class Lock
|
class Lock
|
||||||
@ -25,23 +24,8 @@ class Lock
|
|||||||
void unlock();
|
void unlock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef configUSE_PREEMPTION
|
|
||||||
SemaphoreHandle_t handle;
|
SemaphoreHandle_t handle;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// RAII lock guard.
|
} // namespace concurrency
|
||||||
class LockGuard
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LockGuard(Lock *lock);
|
|
||||||
~LockGuard();
|
|
||||||
|
|
||||||
LockGuard(const LockGuard &) = delete;
|
|
||||||
LockGuard &operator=(const LockGuard &) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Lock *lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace meshtastic
|
|
15
src/concurrency/LockGuard.cpp
Normal file
15
src/concurrency/LockGuard.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "LockGuard.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
LockGuard::LockGuard(Lock *lock) : lock(lock)
|
||||||
|
{
|
||||||
|
lock->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
LockGuard::~LockGuard()
|
||||||
|
{
|
||||||
|
lock->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace concurrency
|
21
src/concurrency/LockGuard.h
Normal file
21
src/concurrency/LockGuard.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Lock.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
// RAII lock guard.
|
||||||
|
class LockGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LockGuard(Lock *lock);
|
||||||
|
~LockGuard();
|
||||||
|
|
||||||
|
LockGuard(const LockGuard &) = delete;
|
||||||
|
LockGuard &operator=(const LockGuard &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Lock *lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace concurrency
|
19
src/concurrency/NotifiedWorkerThread.cpp
Normal file
19
src/concurrency/NotifiedWorkerThread.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "NotifiedWorkerThread.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify this thread so it can run
|
||||||
|
*/
|
||||||
|
void NotifiedWorkerThread::notify(uint32_t v, eNotifyAction action)
|
||||||
|
{
|
||||||
|
xTaskNotify(taskHandle, v, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotifiedWorkerThread::block()
|
||||||
|
{
|
||||||
|
xTaskNotifyWait(0, // don't clear notification on entry
|
||||||
|
clearOnRead, ¬ification, portMAX_DELAY); // Wait forever
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace concurrency
|
47
src/concurrency/NotifiedWorkerThread.h
Normal file
47
src/concurrency/NotifiedWorkerThread.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WorkerThread.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A worker thread that waits on a freertos notification
|
||||||
|
*/
|
||||||
|
class NotifiedWorkerThread : public WorkerThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Notify this thread so it can run
|
||||||
|
*/
|
||||||
|
void notify(uint32_t v = 0, eNotifyAction action = eNoAction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify from an ISR
|
||||||
|
*
|
||||||
|
* This must be inline or IRAM_ATTR on ESP32
|
||||||
|
*/
|
||||||
|
inline void notifyFromISR(BaseType_t *highPriWoken, uint32_t v = 0, eNotifyAction action = eNoAction)
|
||||||
|
{
|
||||||
|
xTaskNotifyFromISR(taskHandle, v, action, highPriWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* The notification that was most recently used to wake the thread. Read from loop()
|
||||||
|
*/
|
||||||
|
uint32_t notification = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What notification bits should be cleared just after we read and return them in notification?
|
||||||
|
*
|
||||||
|
* Defaults to clear all of them.
|
||||||
|
*/
|
||||||
|
uint32_t clearOnRead = UINT32_MAX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
|
||||||
|
*/
|
||||||
|
virtual void block();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace concurrency
|
16
src/concurrency/Thread.cpp
Normal file
16
src/concurrency/Thread.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include "Thread.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
void Thread::start(const char *name, size_t stackSize, uint32_t priority)
|
||||||
|
{
|
||||||
|
auto r = xTaskCreate(callRun, name, stackSize, this, priority, &taskHandle);
|
||||||
|
assert(r == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::callRun(void *_this)
|
||||||
|
{
|
||||||
|
((Thread *)_this)->doRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace concurrency
|
34
src/concurrency/Thread.h
Normal file
34
src/concurrency/Thread.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "freertosinc.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
class Thread
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
TaskHandle_t taskHandle = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set this to true to ask thread to cleanly exit asap
|
||||||
|
*/
|
||||||
|
volatile bool wantExit = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void start(const char *name, size_t stackSize = 1024, uint32_t priority = tskIDLE_PRIORITY);
|
||||||
|
|
||||||
|
virtual ~Thread() { vTaskDelete(taskHandle); }
|
||||||
|
|
||||||
|
uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* The method that will be called when start is called.
|
||||||
|
*/
|
||||||
|
virtual void doRun() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void callRun(void *_this);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace concurrency
|
25
src/concurrency/WorkerThread.cpp
Normal file
25
src/concurrency/WorkerThread.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "WorkerThread.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
void WorkerThread::doRun()
|
||||||
|
{
|
||||||
|
while (!wantExit) {
|
||||||
|
block();
|
||||||
|
|
||||||
|
#ifdef DEBUG_STACK
|
||||||
|
static uint32_t lastPrint = 0;
|
||||||
|
if (millis() - lastPrint > 10 * 1000L) {
|
||||||
|
lastPrint = millis();
|
||||||
|
uint32_t taskHandle = reinterpret_cast<uint32_t>(xTaskGetCurrentTaskHandle());
|
||||||
|
DEBUG_MSG("printThreadInfo(%s) task: %" PRIx32 " core id: %u min free stack: %u\n", "thread", taskHandle, xPortGetCoreID(),
|
||||||
|
uxTaskGetStackHighWaterMark(nullptr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace concurrency
|
30
src/concurrency/WorkerThread.h
Normal file
30
src/concurrency/WorkerThread.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Thread.h"
|
||||||
|
|
||||||
|
namespace concurrency {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This wraps threading (FreeRTOS for now) with a blocking API intended for efficiently converting onlyschool arduino loop() code.
|
||||||
|
*
|
||||||
|
* Use as a mixin base class for the classes you want to convert.
|
||||||
|
*
|
||||||
|
* https://www.freertos.org/RTOS_Task_Notification_As_Mailbox.html
|
||||||
|
*/
|
||||||
|
class WorkerThread : public Thread
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
|
||||||
|
*/
|
||||||
|
virtual void block() = 0;
|
||||||
|
|
||||||
|
virtual void loop() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method that will be called when start is called.
|
||||||
|
*/
|
||||||
|
virtual void doRun();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace concurrency
|
@ -1,20 +0,0 @@
|
|||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include "freertosinc.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
namespace meshtastic
|
|
||||||
{
|
|
||||||
|
|
||||||
void printThreadInfo(const char *extra)
|
|
||||||
{
|
|
||||||
#ifndef NO_ESP32
|
|
||||||
uint32_t taskHandle = reinterpret_cast<uint32_t>(xTaskGetCurrentTaskHandle());
|
|
||||||
DEBUG_MSG("printThreadInfo(%s) task: %" PRIx32 " core id: %u min free stack: %u\n", extra, taskHandle, xPortGetCoreID(),
|
|
||||||
uxTaskGetStackHighWaterMark(nullptr));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace meshtastic
|
|
10
src/debug.h
10
src/debug.h
@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace meshtastic
|
|
||||||
{
|
|
||||||
|
|
||||||
/// Dumps out which core we are running on, and min level of remaining stack
|
|
||||||
/// seen.
|
|
||||||
void printThreadInfo(const char *extra);
|
|
||||||
|
|
||||||
} // namespace meshtastic
|
|
50
src/lock.cpp
50
src/lock.cpp
@ -1,50 +0,0 @@
|
|||||||
#include "lock.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace meshtastic
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifdef configUSE_PREEMPTION
|
|
||||||
Lock::Lock()
|
|
||||||
{
|
|
||||||
handle = xSemaphoreCreateBinary();
|
|
||||||
assert(handle);
|
|
||||||
assert(xSemaphoreGive(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock::lock()
|
|
||||||
{
|
|
||||||
assert(xSemaphoreTake(handle, portMAX_DELAY));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock::unlock()
|
|
||||||
{
|
|
||||||
assert(xSemaphoreGive(handle));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
Lock::Lock()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock::lock()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock::unlock()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
LockGuard::LockGuard(Lock *lock) : lock(lock)
|
|
||||||
{
|
|
||||||
lock->lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
LockGuard::~LockGuard()
|
|
||||||
{
|
|
||||||
lock->unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace meshtastic
|
|
Loading…
Reference in New Issue
Block a user