Kernel and buildscript improvements (#477)

* **New Features**
  * Centralized module management with global symbol resolution
  * Level-aware logging with colored prefixes and millisecond timestamps

* **Breaking Changes**
  * ModuleParent hierarchy and getModuleParent() removed
  * Logging API and adapter model replaced; LogLevel-driven log_generic signature changed

* **Improvements**
  * Unified, simplified module registration across build targets
  * Tests updated to reflect new module lifecycle and global symbol resolution
This commit is contained in:
Ken Van Hoeylandt
2026-02-03 08:35:29 +01:00
committed by GitHub
parent 1a61eac8e0
commit a935410f82
38 changed files with 432 additions and 665 deletions
@@ -11,7 +11,7 @@
#include <tactility/log.h>
#include <atomic>
#define TAG LOG_TAG(Dispatcher)
#define TAG "Dispatcher"
static constexpr EventBits_t BACKPRESSURE_WARNING_COUNT = 100U;
static constexpr EventBits_t WAIT_FLAG = 1U;
+1 -1
View File
@@ -11,7 +11,7 @@
#include <string>
static const size_t LOCAL_STORAGE_SELF_POINTER_INDEX = 0;
static const char* TAG = LOG_TAG(Thread);
static const char* TAG = "Thread";
struct Thread {
TaskHandle_t taskHandle = nullptr;
+1 -1
View File
@@ -2,7 +2,7 @@
#include <tactility/freertos/task.h>
#include <tactility/log.h>
static const auto* TAG = LOG_TAG(Kernel);
static const auto* TAG = "Kernel";
static void log_memory_info() {
#ifdef ESP_PLATFORM
+1 -1
View File
@@ -11,7 +11,7 @@
#include <sys/errno.h>
#include <vector>
#define TAG LOG_TAG(device)
#define TAG "device"
struct DevicePrivate {
std::vector<Device*> children;
+7 -15
View File
@@ -10,7 +10,7 @@
#include <tactility/error.h>
#include <tactility/log.h>
#define TAG LOG_TAG(driver)
#define TAG "driver"
struct DriverPrivate {
Mutex mutex { 0 };
@@ -30,21 +30,11 @@ struct DriverLedger {
std::vector<Driver*> drivers;
Mutex mutex { 0 };
DriverLedger() {
mutex_construct(&mutex);
}
DriverLedger() { mutex_construct(&mutex); }
~DriverLedger() { mutex_destruct(&mutex); }
~DriverLedger() {
mutex_destruct(&mutex);
}
void lock() {
mutex_lock(&mutex);
}
void unlock() {
mutex_unlock(&mutex);
}
void lock() { mutex_lock(&mutex); }
void unlock() { mutex_unlock(&mutex); }
};
static DriverLedger& get_ledger() {
@@ -99,6 +89,8 @@ error_t driver_add(Driver* driver) {
error_t driver_remove(Driver* driver) {
LOG_I(TAG, "remove %s", driver->name);
if (driver->owner == nullptr) return ERROR_NOT_ALLOWED;
ledger.lock();
const auto iterator = std::ranges::find(ledger.drivers, driver);
if (iterator == ledger.drivers.end()) {
+1 -2
View File
@@ -12,8 +12,7 @@ Driver root_driver = {
.stop_device = nullptr,
.api = nullptr,
.device_type = nullptr,
.owner = nullptr,
.driver_private = nullptr
.owner = nullptr
};
}
+22 -14
View File
@@ -5,12 +5,7 @@
extern "C" {
#endif
#define TAG LOG_TAG(kernel)
struct ModuleParent kernel_module_parent = {
"kernel",
nullptr
};
#define TAG "kernel"
static error_t init_kernel_drivers() {
extern Driver root_driver;
@@ -21,24 +16,37 @@ static error_t init_kernel_drivers() {
error_t kernel_init(struct Module* platform_module, struct Module* device_module, struct CompatibleDevice devicetree_devices[]) {
LOG_I(TAG, "init");
if (module_parent_construct(&kernel_module_parent) != ERROR_NONE) {
LOG_E(TAG, "init failed to create kernel module parent");
return ERROR_RESOURCE;
}
if (init_kernel_drivers() != ERROR_NONE) {
LOG_E(TAG, "init failed to init kernel drivers");
return ERROR_RESOURCE;
}
module_set_parent(platform_module, &kernel_module_parent);
if (module_construct(platform_module) != ERROR_NONE) {
LOG_E(TAG, "init failed to construct platform module");
return ERROR_RESOURCE;
}
if (module_add(platform_module) != ERROR_NONE) {
LOG_E(TAG, "init failed to add platform module");
return ERROR_RESOURCE;
}
if (module_start(platform_module) != ERROR_NONE) {
LOG_E(TAG, "init failed to start platform module");
return ERROR_RESOURCE;
}
if (device_module != nullptr) {
module_set_parent(device_module, &kernel_module_parent);
if (module_construct(device_module) != ERROR_NONE) {
LOG_E(TAG, "init failed to construct device module");
return ERROR_RESOURCE;
}
if (module_add(device_module) != ERROR_NONE) {
LOG_E(TAG, "init failed to add device module");
return ERROR_RESOURCE;
}
if (module_start(device_module) != ERROR_NONE) {
LOG_E(TAG, "init failed to start device module");
return ERROR_RESOURCE;
@@ -58,7 +66,7 @@ error_t kernel_init(struct Module* platform_module, struct Module* device_module
LOG_I(TAG, "init done");
return ERROR_NONE;
};
}
#ifdef __cplusplus
}
+57 -3
View File
@@ -4,17 +4,71 @@
#include <tactility/log.h>
#include <mutex>
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <sys/time.h>
static const char* get_log_color(LogLevel level) {
using enum LogLevel;
switch (level) {
case LOG_LEVEL_ERROR:
return "\033[1;31m";
case LOG_LEVEL_WARNING:
return "\033[1;33m";
case LOG_LEVEL_INFO:
return "\033[32m";
case LOG_LEVEL_DEBUG:
return "\033[36m";
case LOG_LEVEL_VERBOSE:
return "\033[37m";
default:
return "";
}
}
static inline char get_log_prefix(LogLevel level) {
using enum LogLevel;
switch (level) {
case LOG_LEVEL_ERROR:
return 'E';
case LOG_LEVEL_WARNING:
return 'W';
case LOG_LEVEL_INFO:
return 'I';
case LOG_LEVEL_DEBUG:
return 'D';
case LOG_LEVEL_VERBOSE:
return 'V';
default:
return '?';
}
}
static uint64_t get_log_timestamp() {
static uint64_t base = 0U;
static std::once_flag init_flag;
std::call_once(init_flag, []() {
timeval time {};
gettimeofday(&time, nullptr);
base = ((uint64_t)time.tv_sec * 1000U) + (time.tv_usec / 1000U);
});
timeval time {};
gettimeofday(&time, nullptr);
uint64_t now = ((uint64_t)time.tv_sec * 1000U) + (time.tv_usec / 1000U);
return now - base;
}
extern "C" {
void log_generic(const char* tag, const char* format, ...) {
void log_generic(enum LogLevel level, const char* tag, const char* format, ...) {
va_list args;
va_start(args, format);
printf("%s ", tag);
printf("%s %c (%" PRIu64 ") %s ", get_log_color(level), get_log_prefix(level), get_log_timestamp(), tag);
vprintf(format, args);
printf("\n");
printf("\033[0m\n");
va_end(args);
}
+32 -69
View File
@@ -4,88 +4,40 @@
#include <tactility/concurrent/mutex.h>
#include <tactility/module.h>
#define TAG LOG_TAG(module)
#define TAG "module"
struct ModuleParentPrivate {
struct ModuleLedger {
std::vector<struct Module*> modules;
struct Mutex mutex = { 0 };
ModuleLedger() { mutex_construct(&mutex); }
~ModuleLedger() { mutex_destruct(&mutex); }
};
static ModuleLedger ledger;
extern "C" {
#pragma region module_parent
error_t module_parent_construct(struct ModuleParent* parent) {
parent->module_parent_private = new (std::nothrow) ModuleParentPrivate();
if (!parent->module_parent_private) return ERROR_OUT_OF_MEMORY;
auto* data = static_cast<ModuleParentPrivate*>(parent->module_parent_private);
mutex_construct(&data->mutex);
error_t module_construct(struct Module* module) {
module->internal.started = false;
return ERROR_NONE;
}
error_t module_parent_destruct(struct ModuleParent* parent) {
auto* data = static_cast<ModuleParentPrivate*>(parent->module_parent_private);
if (data == nullptr) return ERROR_NONE;
mutex_lock(&data->mutex);
if (!data->modules.empty()) {
mutex_unlock(&data->mutex);
return ERROR_INVALID_STATE;
}
mutex_unlock(&data->mutex);
mutex_destruct(&data->mutex);
delete data;
parent->module_parent_private = nullptr;
error_t module_destruct(struct Module* module) {
return ERROR_NONE;
}
bool module_parent_resolve_symbol(ModuleParent* parent, const char* symbol_name, uintptr_t* symbol_address) {
auto* data = static_cast<ModuleParentPrivate*>(parent->module_parent_private);
mutex_lock(&data->mutex);
for (auto* module : data->modules) {
if (!module_is_started(module))
continue;
if (module_resolve_symbol(module, symbol_name, symbol_address)) {
mutex_unlock(&data->mutex);
return true;
}
}
mutex_unlock(&data->mutex);
return false;
error_t module_add(struct Module* module) {
mutex_lock(&ledger.mutex);
ledger.modules.push_back(module);
mutex_unlock(&ledger.mutex);
return ERROR_NONE;
}
#pragma endregion
#pragma region module
error_t module_set_parent(struct Module* module, struct ModuleParent* parent) {
if (module->internal.started) return ERROR_INVALID_STATE;
if (module->internal.parent == parent) return ERROR_NONE;
// Remove from old parent
if (module->internal.parent && module->internal.parent->module_parent_private) {
auto* old_data = static_cast<ModuleParentPrivate*>(module->internal.parent->module_parent_private);
mutex_lock(&old_data->mutex);
auto it = std::find(old_data->modules.begin(), old_data->modules.end(), module);
if (it != old_data->modules.end()) {
old_data->modules.erase(it);
}
mutex_unlock(&old_data->mutex);
}
module->internal.parent = parent;
// Add to new parent
if (parent && parent->module_parent_private) {
auto* new_data = static_cast<ModuleParentPrivate*>(parent->module_parent_private);
mutex_lock(&new_data->mutex);
new_data->modules.push_back(module);
mutex_unlock(&new_data->mutex);
}
error_t module_remove(struct Module* module) {
mutex_lock(&ledger.mutex);
ledger.modules.erase(std::remove(ledger.modules.begin(), ledger.modules.end(), module), ledger.modules.end());
mutex_unlock(&ledger.mutex);
return ERROR_NONE;
}
@@ -93,7 +45,6 @@ error_t module_start(struct Module* module) {
LOG_I(TAG, "start %s", module->name);
if (module->internal.started) return ERROR_NONE;
if (!module->internal.parent) return ERROR_INVALID_STATE;
error_t error = module->start();
module->internal.started = (error == ERROR_NONE);
@@ -132,7 +83,19 @@ bool module_resolve_symbol(Module* module, const char* symbol_name, uintptr_t* s
return false;
}
#pragma endregion
bool module_resolve_symbol_global(const char* symbol_name, uintptr_t* symbol_address) {
mutex_lock(&ledger.mutex);
for (auto* module : ledger.modules) {
if (!module_is_started(module))
continue;
if (module_resolve_symbol(module, symbol_name, symbol_address)) {
mutex_unlock(&ledger.mutex);
return true;
}
}
mutex_unlock(&ledger.mutex);
return false;
}
}