218 lines
6.2 KiB
C
218 lines
6.2 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <execinfo.h>
|
|
#include <signal.h>
|
|
#include <pthread.h>
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "esp_log.h"
|
|
#include "utils/linux_port_utils.h"
|
|
|
|
#define BACKTRACE_PC_ARRAY_SIZE 20
|
|
#define FREERTOS_SIM_BACKTRACE_SIZE 16
|
|
#define ON_SEGFAULT_MESSAGE "ERROR: Segmentation Fault, here's your backtrace:\n"
|
|
#define ON_ABORT_MESSAGE "ERROR: Aborted\n"
|
|
|
|
static void linux_port_backtrace_handler(int sig)
|
|
{
|
|
/* All calls here must be async-signal-safe (no stdio, no malloc).
|
|
* write() and backtrace_symbols_fd() write directly to the fd. */
|
|
void *buffer[FREERTOS_SIM_BACKTRACE_SIZE];
|
|
int nptrs = backtrace(buffer, FREERTOS_SIM_BACKTRACE_SIZE);
|
|
|
|
const char *name = pcTaskGetName(NULL); /* simple pointer dereference, no lock */
|
|
ssize_t ignore __attribute__((unused));
|
|
ignore = write(STDERR_FILENO, "=== Backtrace for task: ", 24);
|
|
if (name) {
|
|
size_t len = 0;
|
|
while (name[len] != '\0') {
|
|
len++;
|
|
}
|
|
ignore = write(STDERR_FILENO, name, len);
|
|
}
|
|
ignore = write(STDERR_FILENO, " ===\n", 5);
|
|
backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
|
|
}
|
|
|
|
void linux_port_setup_backtrace_signal(void)
|
|
{
|
|
struct sigaction sa;
|
|
sa.sa_handler = linux_port_backtrace_handler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART;
|
|
sigaction(SIGUSR1, &sa, NULL);
|
|
}
|
|
|
|
void linux_port_print_backtrace(void)
|
|
{
|
|
pthread_kill(linux_port_get_scheduled_task_pthread(), SIGUSR1);
|
|
}
|
|
|
|
ESP_LOG_ATTR_TAG(LINUX_TAG, "port_idf_linux");
|
|
ESP_LOG_ATTR_TAG(MAIN_TAG, "main_task");
|
|
|
|
#if (defined(__APPLE__) && defined(__MACH__))
|
|
typedef sig_t sighandler_t;
|
|
#endif
|
|
|
|
static volatile UBaseType_t uxInterruptNesting = 0;
|
|
BaseType_t xPortCheckIfInISR(void)
|
|
{
|
|
return uxInterruptNesting;
|
|
}
|
|
|
|
#if CONFIG_COMPILER_OPTIMIZATION_DEBUG
|
|
#define BACKTRACE_PC_ARRAY_SIZE_DUMMY 1
|
|
static void load_libgcc(void)
|
|
{
|
|
void *array[BACKTRACE_PC_ARRAY_SIZE_DUMMY];
|
|
size_t size = backtrace(array, BACKTRACE_PC_ARRAY_SIZE_DUMMY);
|
|
assert(size == 1);
|
|
}
|
|
|
|
static void segfault_handler(int sig)
|
|
{
|
|
void *array[BACKTRACE_PC_ARRAY_SIZE];
|
|
size_t size = backtrace(array, BACKTRACE_PC_ARRAY_SIZE);
|
|
ssize_t ignore __attribute__((unused));
|
|
ignore = write(STDERR_FILENO, ON_SEGFAULT_MESSAGE, sizeof(ON_SEGFAULT_MESSAGE));
|
|
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
|
_exit(1);
|
|
}
|
|
|
|
static void abort_handler(int sig)
|
|
{
|
|
// we need a raw file write here because other functions are not async-signal-safe
|
|
ssize_t ignore __attribute__((unused));
|
|
ignore = write(STDERR_FILENO, ON_ABORT_MESSAGE, sizeof(ON_ABORT_MESSAGE));
|
|
_exit(1);
|
|
}
|
|
#endif // CONFIG_COMPILER_OPTIMIZATION_DEBUG
|
|
|
|
/*-----------------------------------------------------------
|
|
* Main FreeRTOS task
|
|
*-----------------------------------------------------------*/
|
|
extern void app_main(void);
|
|
static void main_task(void *args)
|
|
{
|
|
(void)args;
|
|
ESP_LOGI(MAIN_TAG, "Started on CPU%d", (int)xPortGetCoreID());
|
|
|
|
ESP_LOGI(MAIN_TAG, "Calling app_main()");
|
|
|
|
app_main();
|
|
|
|
ESP_LOGI(MAIN_TAG, "Returned from app_main()");
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
void esp_startup_start_app(void)
|
|
{
|
|
setvbuf(stdout, NULL, _IONBF, 0);
|
|
|
|
#if CONFIG_COMPILER_OPTIMIZATION_DEBUG
|
|
load_libgcc();
|
|
sighandler_t sig_res;
|
|
|
|
sig_res = signal(SIGSEGV, segfault_handler);
|
|
if (sig_res == SIG_ERR) {
|
|
abort();
|
|
}
|
|
|
|
sig_res = signal(SIGABRT, abort_handler);
|
|
if (sig_res == SIG_ERR) {
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
// Create main_task using FreeRTOS API
|
|
ESP_LOGI(LINUX_TAG, "Starting main task.");
|
|
assert(xTaskCreate(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL) == pdTRUE);
|
|
|
|
ESP_LOGI(LINUX_TAG, "Starting scheduler task.");
|
|
vTaskStartScheduler();
|
|
|
|
// Should never reach here
|
|
assert(false);
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
* idle and tick hooks
|
|
*-----------------------------------------------------------*/
|
|
#if (configUSE_IDLE_HOOK > 0)
|
|
void vApplicationIdleHook(void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#if (configUSE_TICK_HOOK > 0)
|
|
void vApplicationTickHook(void)
|
|
{
|
|
extern void esp_vApplicationTickHook(void);
|
|
esp_vApplicationTickHook();
|
|
}
|
|
#else
|
|
#endif
|
|
|
|
/*-----------------------------------------------------------
|
|
* Static allocation support
|
|
*-----------------------------------------------------------*/
|
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
|
|
|
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
|
|
StackType_t **ppxIdleTaskStackBuffer,
|
|
uint32_t *pulIdleTaskStackSize)
|
|
{
|
|
static StaticTask_t xIdleTaskTCB;
|
|
static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
|
|
|
|
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
|
|
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
|
|
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
|
|
}
|
|
|
|
#if (configUSE_TIMERS == 1)
|
|
StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
|
|
|
|
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
|
|
StackType_t **ppxTimerTaskStackBuffer,
|
|
uint32_t *pulTimerTaskStackSize)
|
|
{
|
|
static StaticTask_t xTimerTaskTCB;
|
|
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
|
|
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
|
|
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
|
|
}
|
|
#endif
|
|
|
|
#endif // configSUPPORT_STATIC_ALLOCATION
|
|
|
|
/*-----------------------------------------------------------
|
|
* Stack overflow hook
|
|
*-----------------------------------------------------------*/
|
|
void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
|
{
|
|
#define ERR_STR1 "***ERROR*** A stack overflow in task "
|
|
#define ERR_STR2 " has been detected."
|
|
const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2};
|
|
|
|
char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = {0};
|
|
|
|
char *dest = buf;
|
|
for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
|
|
dest = strcat(dest, str[i]);
|
|
}
|
|
printf("%s\n", buf);
|
|
abort();
|
|
}
|