Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FL-3885] Put errno into TCB #3893

Merged
merged 6 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions applications/debug/unit_tests/tests/furi/furi_errno_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <furi.h>
#include <errno.h>
#include "../test.h" // IWYU pragma: keep

#define TAG "ErrnoTest"
#define THREAD_CNT 16
#define ITER_CNT 1000

static int32_t errno_fuzzer(void* context) {
int start_value = (int)context;
int32_t fails = 0;

for(int i = start_value; i < start_value + ITER_CNT; i++) {
errno = i;
furi_thread_yield();
if(errno != i) fails++;
}

for(int i = 0; i < ITER_CNT; i++) {
errno = 0;
furi_thread_yield();
UNUSED(strtol("123456", NULL, 10)); // -V530
furi_thread_yield();
if(errno != 0) fails++;

errno = 0;
furi_thread_yield();
UNUSED(strtol("123456123456123456123456123456123456123456123456", NULL, 10)); // -V530
furi_thread_yield();
if(errno != ERANGE) fails++;
}

return fails;
}

void test_errno_saving(void) {
FuriThread* threads[THREAD_CNT];

for(int i = 0; i < THREAD_CNT; i++) {
int start_value = i * ITER_CNT;
threads[i] = furi_thread_alloc_ex("ErrnoFuzzer", 1024, errno_fuzzer, (void*)start_value);
furi_thread_set_priority(threads[i], FuriThreadPriorityNormal);
furi_thread_start(threads[i]);
}

for(int i = 0; i < THREAD_CNT; i++) {
furi_thread_join(threads[i]);
mu_assert_int_eq(0, furi_thread_get_return_code(threads[i]));
furi_thread_free(threads[i]);
}
}
6 changes: 6 additions & 0 deletions applications/debug/unit_tests/tests/furi/furi_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ void test_furi_concurrent_access(void);
void test_furi_pubsub(void);
void test_furi_memmgr(void);
void test_furi_event_loop(void);
void test_errno_saving(void);

static int foo = 0;

Expand Down Expand Up @@ -42,6 +43,10 @@ MU_TEST(mu_test_furi_event_loop) {
test_furi_event_loop();
}

MU_TEST(mu_test_errno_saving) {
test_errno_saving();
}

MU_TEST_SUITE(test_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
MU_RUN_TEST(test_check);
Expand All @@ -51,6 +56,7 @@ MU_TEST_SUITE(test_suite) {
MU_RUN_TEST(mu_test_furi_pubsub);
MU_RUN_TEST(mu_test_furi_memmgr);
MU_RUN_TEST(mu_test_furi_event_loop);
MU_RUN_TEST(mu_test_errno_saving);
}

int run_minunit_test_furi(void) {
Expand Down
13 changes: 10 additions & 3 deletions targets/f7/inc/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
#include <errno.h>
#pragma GCC diagnostic ignored "-Wredundant-decls"
#endif

Expand All @@ -26,6 +27,7 @@
#define configUSE_16_BIT_TICKS 0
#define configMAX_PRIORITIES (32)
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configUSE_POSIX_ERRNO 1

/* Heap size determined automatically by linker */
// #define configTOTAL_HEAP_SIZE ((size_t)0)
Expand Down Expand Up @@ -146,9 +148,14 @@ standard names. */
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION \
1 /* required only for Keil but does not hurt otherwise */

#define traceTASK_SWITCHED_IN() \
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack)
#define traceTASK_SWITCHED_IN() \
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack); \
errno = pxCurrentTCB->iTaskErrno
// ^^^^^ acquire errno directly from TCB because FreeRTOS assigns its `FreeRTOS_errno' _after_ our hook is called

// referencing `FreeRTOS_errno' here vvvvv because FreeRTOS calls our hook _before_ copying the value into the TCB, hence a manual write to the TCB would get overwritten
#define traceTASK_SWITCHED_OUT() FreeRTOS_errno = errno

#define portCLEAN_UP_TCB(pxTCB) \
extern void furi_thread_cleanup_tcb_event(TaskHandle_t task); \
Expand Down
Loading