1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
#include "db_task.hpp"
#include <functional>
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"
#include "freertos/queue.h"
#include "freertos/task.h"
namespace database {
static const std::size_t kDbStackSize = 256 * 1024;
static StaticTask_t sDbStaticTask;
static StackType_t* sDbStack = nullptr;
static std::atomic<bool> sTaskRunning(false);
static QueueHandle_t sWorkQueue;
struct WorkItem {
std::function<void(void)>* fn;
bool quit;
};
auto SendToDbTask(std::function<void(void)> fn) -> void {
WorkItem item{
.fn = new std::function<void(void)>(fn),
.quit = false,
};
xQueueSend(sWorkQueue, &item, portMAX_DELAY);
}
template <>
auto RunOnDbTask(std::function<void(void)> fn) -> std::future<void> {
std::shared_ptr<std::promise<void>> promise =
std::make_shared<std::promise<void>>();
SendToDbTask([=]() {
std::invoke(fn);
promise->set_value();
});
return promise->get_future();
}
void DatabaseTaskMain(void* args) {
while (true) {
WorkItem item;
if (xQueueReceive(sWorkQueue, &item, portMAX_DELAY)) {
if (item.quit) {
break;
}
if (item.fn != nullptr) {
std::invoke(*item.fn);
delete item.fn;
}
}
}
vQueueDelete(sWorkQueue);
sTaskRunning.store(false);
vTaskDelete(NULL);
}
auto StartDbTask() -> bool {
if (sTaskRunning.exchange(true)) {
return false;
}
if (sDbStack == nullptr) {
sDbStack = reinterpret_cast<StackType_t*>(
heap_caps_malloc(kDbStackSize, MALLOC_CAP_SPIRAM));
}
sWorkQueue = xQueueCreate(8, sizeof(std::function<void(void)>*));
xTaskCreateStatic(&DatabaseTaskMain, "DB", kDbStackSize, NULL, 1, sDbStack,
&sDbStaticTask);
return true;
}
auto QuitDbTask() -> void {
if (!sTaskRunning.load()) {
return;
}
WorkItem item{
.fn = nullptr,
.quit = true,
};
xQueueSend(sWorkQueue, &item, portMAX_DELAY);
while (sTaskRunning.load()) {
vTaskDelay(pdMS_TO_TICKS(1));
}
}
} // namespace database
|