mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 09:39:10 -04:00
Merge branch 'feature/newlib_lock_retarget' into 'master'
newlib 3.3.0 _RETARGETABLE_LOCKING support Closes IDF-2129 See merge request espressif/esp-idf!9141
This commit is contained in:
commit
1760f47681
@ -76,11 +76,6 @@ menu "Driver configurations"
|
||||
config TWAI_ISR_IN_IRAM
|
||||
bool "Place TWAI ISR function into IRAM"
|
||||
default n
|
||||
select FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
# We need to enable FREERTOS_SUPPORT_STATIC_ALLOCATION because the
|
||||
# TWAI driver requires the use of FreeRTOS Queues and Semaphores from
|
||||
# the driver ISR. These Queues and Semaphores need to be placed in
|
||||
# DRAM thus FreeRTOS static allocation API is required.
|
||||
help
|
||||
Place the TWAI ISR in to IRAM. This will allow the ISR to avoid
|
||||
cache misses, and also be able to run whilst the cache is disabled
|
||||
|
@ -64,8 +64,6 @@ typedef enum {
|
||||
* buffer where this struct is of the exact size required to store a ring
|
||||
* buffer's control data structure.
|
||||
*
|
||||
* @note The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled for
|
||||
* this structure to be available.
|
||||
*/
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1)
|
||||
typedef struct xSTATIC_RINGBUFFER {
|
||||
@ -117,9 +115,6 @@ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum);
|
||||
* @param[in] pxStaticRingbuffer Pointed to a struct of type StaticRingbuffer_t
|
||||
* which will be used to hold the ring buffer's data structure
|
||||
*
|
||||
* @note The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled
|
||||
* for this to be available
|
||||
*
|
||||
* @note xBufferSize of no-split/allow-split buffers MUST be 32-bit aligned.
|
||||
*
|
||||
* @return A handle to the created ring buffer
|
||||
|
@ -17,3 +17,7 @@ __sf_fake_stderr = 0x3ff96458;
|
||||
__sf_fake_stdin = 0x3ff96498;
|
||||
__sf_fake_stdout = 0x3ff96478;
|
||||
__wctomb = 0x3ff96540;
|
||||
__sfp_lock = 0x3ffae0ac;
|
||||
__sinit_lock = 0x3ffae0a8;
|
||||
__env_lock_object = 0x3ffae0b8;
|
||||
__tz_lock_object = 0x3ffae080;
|
||||
|
@ -13,3 +13,5 @@ _PathLocale = 0x3ffffd80;
|
||||
__sf_fake_stderr = 0x3ffaf08c;
|
||||
__sf_fake_stdin = 0x3ffaf0cc;
|
||||
__sf_fake_stdout = 0x3ffaf0ac;
|
||||
__sfp_recursive_mutex = 0x3ffffd88;
|
||||
__sinit_recursive_mutex = 0x3ffffd84;
|
||||
|
@ -15,3 +15,5 @@ _PathLocale = 0x3fcefcd0;
|
||||
__sf_fake_stderr = 0x3ff0c524;
|
||||
__sf_fake_stdin = 0x3ff0c564;
|
||||
__sf_fake_stdout = 0x3ff0c544;
|
||||
__sinit_recursive_mutex = 0x3fcefcd4;
|
||||
__sfp_recursive_mutex = 0x3fcefcd8;
|
||||
|
@ -199,6 +199,7 @@ static void do_core_init(void)
|
||||
fail initializing it properly. */
|
||||
heap_caps_init();
|
||||
esp_setup_syscall_table();
|
||||
esp_newlib_locks_init();
|
||||
esp_newlib_time_init();
|
||||
|
||||
if (g_spiram_ok) {
|
||||
|
@ -290,7 +290,6 @@ TEST_CASE_MULTIPLE_STAGES("can set sleep wake stub", "[deepsleep][reset=DEEPSLEE
|
||||
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
|
||||
#if CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
|
||||
/* Version of prepare_wake_stub() that sets up the deep sleep call while running
|
||||
from RTC memory as stack, with a high frequency timer also writing RTC FAST
|
||||
@ -346,7 +345,6 @@ TEST_CASE_MULTIPLE_STAGES("can set sleep wake stub from stack in RTC RAM", "[dee
|
||||
prepare_wake_stub_from_rtc,
|
||||
check_wake_stub);
|
||||
|
||||
#endif // CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
#endif // CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
|
||||
|
||||
TEST_CASE("wake up using ext0 (13 high)", "[deepsleep][ignore]")
|
||||
|
@ -552,6 +552,7 @@ static int vfs_fat_fstat(void* ctx, int fd, struct stat * st)
|
||||
{
|
||||
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
|
||||
FIL* file = &fat_ctx->files[fd];
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_size = f_size(file);
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
|
||||
st->st_mtime = 0;
|
||||
|
@ -205,36 +205,14 @@ menu "FreeRTOS"
|
||||
For most uses, the default of 16 is OK.
|
||||
|
||||
config FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
bool "Enable FreeRTOS static allocation API"
|
||||
default n
|
||||
help
|
||||
FreeRTOS gives the application writer the ability to instead provide the memory
|
||||
themselves, allowing the following objects to optionally be created without any
|
||||
memory being allocated dynamically:
|
||||
|
||||
- Tasks
|
||||
- Software Timers (Daemon task is still dynamic. See documentation)
|
||||
- Queues
|
||||
- Event Groups
|
||||
- Binary Semaphores
|
||||
- Counting Semaphores
|
||||
- Recursive Semaphores
|
||||
- Mutexes
|
||||
|
||||
Whether it is preferable to use static or dynamic memory allocation is dependent on
|
||||
the application, and the preference of the application writer. Both methods have pros
|
||||
and cons, and both methods can be used within the same RTOS application.
|
||||
|
||||
Creating RTOS objects using statically allocated RAM has the benefit of providing the application writer
|
||||
with more control: RTOS objects can be placed at specific memory locations. The maximum RAM footprint can
|
||||
be determined at link time, rather than run time. The application writer does not need to concern
|
||||
themselves with graceful handling of memory allocation failures. It allows the RTOS to be used in
|
||||
applications that simply don't allow any dynamic memory allocation (although FreeRTOS includes allocation
|
||||
schemes that can overcome most objections).
|
||||
# Always enabled.
|
||||
# Kconfig option preserved for compatibility with code
|
||||
# which checked for CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION.
|
||||
bool
|
||||
default y
|
||||
|
||||
config FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP
|
||||
bool "Enable static task clean up hook"
|
||||
depends on FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
default n
|
||||
help
|
||||
Enable this option to make FreeRTOS call the static task clean up hook when a task is deleted.
|
||||
|
@ -239,7 +239,7 @@
|
||||
kept at 1. */
|
||||
#define configKERNEL_INTERRUPT_PRIORITY 1
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configSUPPORT_STATIC_ALLOCATION CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#if CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP
|
||||
|
@ -291,7 +291,7 @@ int xt_clock_freq(void) __attribute__((deprecated));
|
||||
#define configUSE_NEWLIB_REENTRANT 1
|
||||
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configSUPPORT_STATIC_ALLOCATION CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#if CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP
|
||||
|
@ -1,7 +1,6 @@
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP
|
||||
CONFIG_TIMER_TASK_PRIORITY CONFIG_FREERTOS_TIMER_TASK_PRIORITY
|
||||
CONFIG_TIMER_TASK_STACK_DEPTH CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifdef CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
/* ---------------------Test 1: Backported Timer functions-----------------------
|
||||
* Test xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
|
||||
*
|
||||
@ -201,7 +200,6 @@ TEST_CASE("Test FreeRTOS backported eventgroup functions", "[freertos]")
|
||||
//Cleanup static event
|
||||
vEventGroupDelete(eg_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* --------Test backported thread local storage pointer and deletion cb feature----------
|
||||
* vTaskSetThreadLocalStoragePointerAndDelCallback()
|
||||
|
@ -69,7 +69,6 @@ TEST_CASE("Recurring FreeRTOS timers", "[freertos]")
|
||||
TEST_ASSERT( xTimerDelete(recurring, 1) );
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
TEST_CASE("Static timer creation", "[freertos]")
|
||||
{
|
||||
StaticTimer_t static_timer;
|
||||
@ -84,4 +83,3 @@ TEST_CASE("Static timer creation", "[freertos]")
|
||||
|
||||
TEST_ASSERT_NOT_NULL(created_timer);
|
||||
}
|
||||
#endif
|
||||
|
@ -30,9 +30,8 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE c m gcc "$<TARGET_FILE:${newlib
|
||||
|
||||
set_source_files_properties(heap.c PROPERTIES COMPILE_FLAGS -fno-builtin)
|
||||
|
||||
# Forces the linker to include locks, heap, and syscalls from this component,
|
||||
# Forces the linker to include heap, syscalls, and pthread from this component,
|
||||
# instead of the implementations provided by newlib.
|
||||
set(EXTRA_LINK_FLAGS "-u newlib_include_locks_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_heap_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_syscalls_impl")
|
||||
list(APPEND EXTRA_LINK_FLAGS "-u newlib_include_pthread_impl")
|
||||
|
@ -15,9 +15,8 @@ endif
|
||||
COMPONENT_PRIV_INCLUDEDIRS := priv_include
|
||||
COMPONENT_SRCDIRS := . port
|
||||
|
||||
# Forces the linker to include locks, heap, and syscalls from this component,
|
||||
# Forces the linker to include heap, syscalls, and pthread from this component,
|
||||
# instead of the implementations provided by newlib.
|
||||
COMPONENT_ADD_LDFLAGS += -u newlib_include_locks_impl
|
||||
COMPONENT_ADD_LDFLAGS += -u newlib_include_heap_impl
|
||||
COMPONENT_ADD_LDFLAGS += -u newlib_include_syscalls_impl
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/portable.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
/* Notes on our newlib lock implementation:
|
||||
*
|
||||
@ -119,7 +118,6 @@ void _lock_close_recursive(_lock_t *lock) __attribute__((alias("_lock_close")));
|
||||
*/
|
||||
static int IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type) {
|
||||
xSemaphoreHandle h = (xSemaphoreHandle)(*lock);
|
||||
|
||||
if (!h) {
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return 0; /* locking is a no-op before scheduler is up, so this "succeeds" */
|
||||
@ -212,9 +210,208 @@ void IRAM_ATTR _lock_release_recursive(_lock_t *lock) {
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
/* No-op function, used to force linking this file,
|
||||
instead of the dummy locks implementation from newlib.
|
||||
#ifdef _RETARGETABLE_LOCKING
|
||||
/* To ease the transition to newlib 3.3.0, this part is kept under an ifdef.
|
||||
* After the toolchain with newlib 3.3.0 is released and merged, the ifdefs
|
||||
* can be removed.
|
||||
*
|
||||
* Also the retargetable locking functions still rely on the previous
|
||||
* implementation. Once support for !_RETARGETABLE_LOCKING is removed,
|
||||
* the code can be simplified, removing support for lazy initialization of
|
||||
* locks. At the same time, IDF code which relies on _lock_acquire/_lock_release
|
||||
* will have to be updated to not depend on lazy initialization.
|
||||
*
|
||||
* Explanation of the different lock types:
|
||||
*
|
||||
* Newlib 2.2.0 and 3.0.0:
|
||||
* _lock_t is defined as int, stores SemaphoreHandle_t.
|
||||
*
|
||||
* Newlib 3.3.0:
|
||||
* struct __lock is (or contains) StaticSemaphore_t
|
||||
* _LOCK_T is a pointer to struct __lock, equivalent to SemaphoreHandle_t.
|
||||
* It has the same meaning as _lock_t in the previous implementation.
|
||||
*
|
||||
*/
|
||||
void newlib_include_locks_impl(void)
|
||||
|
||||
/* This ensures the platform-specific definition in lock.h is correct.
|
||||
* We use "greater or equal" since the size of StaticSemaphore_t may
|
||||
* vary by 2 words, depending on whether configUSE_TRACE_FACILITY is enabled.
|
||||
*/
|
||||
_Static_assert(sizeof(struct __lock) >= sizeof(StaticSemaphore_t),
|
||||
"Incorrect size of struct __lock");
|
||||
|
||||
/* FreeRTOS configuration check */
|
||||
_Static_assert(configSUPPORT_STATIC_ALLOCATION,
|
||||
"FreeRTOS should be configured with static allocation support");
|
||||
|
||||
/* These 2 locks are used instead of 9 distinct newlib static locks,
|
||||
* as most of the locks are required for lesser-used features, so
|
||||
* the chance of performance degradation due to lock contention is low.
|
||||
*/
|
||||
static StaticSemaphore_t s_common_mutex;
|
||||
static StaticSemaphore_t s_common_recursive_mutex;
|
||||
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
/* C3 ROM is built without Newlib static lock symbols exported, and
|
||||
* with an extra level of _LOCK_T indirection in mind.
|
||||
* The following is a workaround for this:
|
||||
* - on startup, we call esp_rom_newlib_init_common_mutexes to set
|
||||
* the two mutex pointers to magic values.
|
||||
* - if in __retarget_lock_acquire*, we check if the argument dereferences
|
||||
* to the magic value. If yes, we lock the correct mutex defined in the app,
|
||||
* instead.
|
||||
* Casts from &StaticSemaphore_t to _LOCK_T are okay because _LOCK_T
|
||||
* (which is SemaphoreHandle_t) is a pointer to the corresponding
|
||||
* StaticSemaphore_t structure. This is ensured by asserts below.
|
||||
*/
|
||||
|
||||
#define ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#ifdef ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#define ROM_MUTEX_MAGIC 0xbb10c433
|
||||
/* This is a macro, since we are overwriting the argument */
|
||||
#define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead) \
|
||||
if (*(int*)_lock == ROM_MUTEX_MAGIC) { \
|
||||
(_lock) = (_LOCK_T) (_lock_to_use_instead); \
|
||||
}
|
||||
#else // ROM_NEEDS_MUTEX_OVERRIDE
|
||||
#define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead)
|
||||
#endif // ROM_NEEDS_MUTEX_OVERRIDE
|
||||
|
||||
|
||||
void IRAM_ATTR __retarget_lock_init(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_init_recursive(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_close(_LOCK_T lock)
|
||||
{
|
||||
_lock_close(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_close_recursive(_LOCK_T lock)
|
||||
{
|
||||
_lock_close_recursive(&lock);
|
||||
}
|
||||
|
||||
/* Separate function, to prevent generating multiple assert strings */
|
||||
static void IRAM_ATTR check_lock_nonzero(_LOCK_T lock)
|
||||
{
|
||||
assert(lock != NULL && "Uninitialized lock used");
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
_lock_acquire(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
_lock_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
int IRAM_ATTR __retarget_lock_try_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
return _lock_try_acquire(&lock);
|
||||
}
|
||||
|
||||
int IRAM_ATTR __retarget_lock_try_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
return _lock_try_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_release(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release(&lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __retarget_lock_release_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release_recursive(&lock);
|
||||
}
|
||||
|
||||
/* When _RETARGETABLE_LOCKING is enabled, newlib expects the following locks to be provided: */
|
||||
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___sinit_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___malloc_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___env_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___sfp_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_recursive_mutex"))) __lock___atexit_recursive_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___at_quick_exit_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___tz_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___dd_hash_mutex;
|
||||
extern StaticSemaphore_t __attribute__((alias("s_common_mutex"))) __lock___arc4random_mutex;
|
||||
|
||||
void esp_newlib_locks_init(void)
|
||||
{
|
||||
/* Initialize the two mutexes used for the locks above.
|
||||
* Asserts below check our assumption that SemaphoreHandle_t will always
|
||||
* point to the corresponding StaticSemaphore_t structure.
|
||||
*/
|
||||
SemaphoreHandle_t handle;
|
||||
handle = xSemaphoreCreateMutexStatic(&s_common_mutex);
|
||||
assert(handle == (SemaphoreHandle_t) &s_common_mutex);
|
||||
handle = xSemaphoreCreateRecursiveMutexStatic(&s_common_recursive_mutex);
|
||||
assert(handle == (SemaphoreHandle_t) &s_common_recursive_mutex);
|
||||
(void) handle;
|
||||
|
||||
/* Chip ROMs are built with older versions of newlib, and rely on different lock variables.
|
||||
* Initialize these locks to the same values.
|
||||
*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
/* Newlib 2.2.0 is used in ROM, the following lock symbols are defined: */
|
||||
extern _lock_t __sfp_lock;
|
||||
__sfp_lock = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __sinit_lock;
|
||||
__sinit_lock = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __env_lock_object;
|
||||
__env_lock_object = (_lock_t) &s_common_mutex;
|
||||
extern _lock_t __tz_lock_object;
|
||||
__tz_lock_object = (_lock_t) &s_common_recursive_mutex;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
/* Newlib 3.0.0 is used in ROM, the following lock symbols are defined: */
|
||||
extern _lock_t __sinit_recursive_mutex;
|
||||
__sinit_recursive_mutex = (_lock_t) &s_common_recursive_mutex;
|
||||
extern _lock_t __sfp_recursive_mutex;
|
||||
__sfp_recursive_mutex = (_lock_t) &s_common_recursive_mutex;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
/* Newlib 3.3.0 is used in ROM, built with _RETARGETABLE_LOCKING.
|
||||
* No access to lock variables for the purpose of ECO forward compatibility,
|
||||
* however we have an API to initialize lock variables used in the ROM.
|
||||
*/
|
||||
extern void esp_rom_newlib_init_common_mutexes(_LOCK_T, _LOCK_T);
|
||||
/* See notes about ROM_NEEDS_MUTEX_OVERRIDE above */
|
||||
int magic_val = ROM_MUTEX_MAGIC;
|
||||
_LOCK_T magic_mutex = (_LOCK_T) &magic_val;
|
||||
esp_rom_newlib_init_common_mutexes(magic_mutex, magic_mutex);
|
||||
#else // other target
|
||||
#error Unsupported target
|
||||
#endif
|
||||
}
|
||||
|
||||
#else // _RETARGETABLE_LOCKING
|
||||
|
||||
void esp_newlib_locks_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // _RETARGETABLE_LOCKING
|
||||
|
@ -53,4 +53,9 @@ void esp_set_time_from_rtc(void);
|
||||
*/
|
||||
void esp_sync_counters_rtc_and_frc(void);
|
||||
|
||||
/**
|
||||
* Initialize newlib static locks
|
||||
*/
|
||||
void esp_newlib_locks_init(void);
|
||||
|
||||
#endif //__ESP_NEWLIB_H__
|
||||
|
41
components/newlib/platform_include/sys/lock.h
Normal file
41
components/newlib/platform_include/sys/lock.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include_next <sys/lock.h>
|
||||
|
||||
#ifdef _RETARGETABLE_LOCKING
|
||||
|
||||
/* Actual platfrom-specific definition of struct __lock.
|
||||
* The size here should be sufficient for a FreeRTOS mutex.
|
||||
* This is checked by a static assertion in locks.c
|
||||
*
|
||||
* Note 1: this might need to be made dependent on whether FreeRTOS
|
||||
* is included in the build.
|
||||
*
|
||||
* Note 2: the size is made sufficient for the case when
|
||||
* configUSE_TRACE_FACILITY is enabled. If it is disabled,
|
||||
* this definition wastes 8 bytes.
|
||||
*/
|
||||
struct __lock {
|
||||
int reserved[23];
|
||||
};
|
||||
|
||||
/* Compatibility definitions for the legacy ESP-specific locking implementation.
|
||||
* These used to be provided by libc/sys/xtensa/sys/lock.h in newlib.
|
||||
* Newer versions of newlib don't have this ESP-specific lock.h header, and are
|
||||
* built with _RETARGETABLE_LOCKING enabled, instead.
|
||||
*/
|
||||
|
||||
typedef _LOCK_T _lock_t;
|
||||
|
||||
void _lock_init(_lock_t *plock);
|
||||
void _lock_init_recursive(_lock_t *plock);
|
||||
void _lock_close(_lock_t *plock);
|
||||
void _lock_close_recursive(_lock_t *plock);
|
||||
void _lock_acquire(_lock_t *plock);
|
||||
void _lock_acquire_recursive(_lock_t *plock);
|
||||
int _lock_try_acquire(_lock_t *plock);
|
||||
int _lock_try_acquire_recursive(_lock_t *plock);
|
||||
void _lock_release(_lock_t *plock);
|
||||
void _lock_release_recursive(_lock_t *plock);
|
||||
|
||||
#endif // _RETARGETABLE_LOCKING
|
109
components/newlib/test/test_locks.c
Normal file
109
components/newlib/test/test_locks.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/lock.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#if defined(_RETARGETABLE_LOCKING)
|
||||
|
||||
static void locking_task(void* arg)
|
||||
{
|
||||
_LOCK_T lock = (_LOCK_T) arg;
|
||||
__lock_acquire(lock);
|
||||
__lock_release(lock);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
static void recursive_locking_task(void* arg)
|
||||
{
|
||||
_LOCK_T lock = (_LOCK_T) arg;
|
||||
__lock_acquire_recursive(lock);
|
||||
__lock_release_recursive(lock);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
static void test_inner_normal(_LOCK_T lock)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
__lock_acquire(lock);
|
||||
|
||||
/* Create another task to try acquire same lock */
|
||||
TaskHandle_t task_hdl;
|
||||
TEST_ASSERT(xTaskCreate(&locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
|
||||
vTaskDelay(2);
|
||||
/* It should get blocked */
|
||||
TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
|
||||
|
||||
/* Once we release the lock, the task should succeed and suspend itself */
|
||||
__lock_release(lock);
|
||||
vTaskDelay(2);
|
||||
TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
|
||||
vTaskDelete(task_hdl);
|
||||
|
||||
/* Can not recursively acquire the lock from same task */
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire(lock));
|
||||
TEST_ASSERT_EQUAL(-1, __lock_try_acquire(lock));
|
||||
__lock_release(lock);
|
||||
}
|
||||
|
||||
static void test_inner_recursive(_LOCK_T lock)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
__lock_acquire_recursive(lock);
|
||||
|
||||
/* Create another task to try acquire same lock */
|
||||
TaskHandle_t task_hdl;
|
||||
TEST_ASSERT(xTaskCreate(&recursive_locking_task, "locking_task", 2048, lock, UNITY_FREERTOS_PRIORITY, &task_hdl));
|
||||
vTaskDelay(2);
|
||||
/* It should get blocked */
|
||||
TEST_ASSERT_EQUAL(eBlocked, eTaskGetState(task_hdl));
|
||||
|
||||
/* Once we release the lock, the task should succeed and suspend itself */
|
||||
__lock_release_recursive(lock);
|
||||
vTaskDelay(2);
|
||||
TEST_ASSERT_EQUAL(eSuspended, eTaskGetState(task_hdl));
|
||||
vTaskDelete(task_hdl);
|
||||
|
||||
/* Try recursively acquiring the lock */
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
|
||||
TEST_ASSERT_EQUAL(0, __lock_try_acquire_recursive(lock));
|
||||
__lock_release_recursive(lock);
|
||||
__lock_release_recursive(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable static locks", "[newlib_locks]")
|
||||
{
|
||||
StaticSemaphore_t semaphore;
|
||||
_LOCK_T lock = (_LOCK_T) xSemaphoreCreateMutexStatic(&semaphore);
|
||||
test_inner_normal(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable static recursive locks", "[newlib_locks]")
|
||||
{
|
||||
StaticSemaphore_t semaphore;
|
||||
_LOCK_T lock = (_LOCK_T) xSemaphoreCreateRecursiveMutexStatic(&semaphore);
|
||||
test_inner_recursive(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable dynamic locks", "[newlib_locks]")
|
||||
{
|
||||
_LOCK_T lock;
|
||||
__lock_init(lock);
|
||||
test_inner_normal(lock);
|
||||
__lock_close(lock);
|
||||
}
|
||||
|
||||
TEST_CASE("Retargetable dynamic recursive locks", "[newlib_locks]")
|
||||
{
|
||||
_LOCK_T lock;
|
||||
__lock_init_recursive(lock);
|
||||
test_inner_recursive(lock);
|
||||
__lock_close_recursive(lock);
|
||||
}
|
||||
|
||||
#endif // _RETARGETABLE_LOCKING
|
@ -104,7 +104,6 @@ menu "SPI Flash driver"
|
||||
# The bus lock on SPI1 is meaningless when the legacy implementation is used, or the SPI
|
||||
# driver does not support SPI1.
|
||||
depends on !SPI_FLASH_USE_LEGACY_IMPL && !IDF_TARGET_ESP32S2
|
||||
select FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
help
|
||||
Each SPI bus needs a lock for arbitration among devices. This allows multiple
|
||||
devices on a same bus, but may reduce the speed of esp_flash driver access to the
|
||||
|
@ -536,6 +536,7 @@ static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
|
||||
SPIFFS_clearerr(efs->fs);
|
||||
return -1;
|
||||
}
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_size = s.size;
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
|
||||
st->st_mtime = vfs_spiffs_get_mtime(&s);
|
||||
@ -558,7 +559,7 @@ static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st)
|
||||
SPIFFS_clearerr(efs->fs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_size = s.size;
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG;
|
||||
|
@ -4,7 +4,6 @@ menu "TinyUSB"
|
||||
bool "Enable TinyUSB driver"
|
||||
default n
|
||||
depends on IDF_TARGET_ESP32S2
|
||||
select FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
select FREERTOS_USE_AUTHENTIC_INCLUDE_PATHS
|
||||
help
|
||||
Adds support for TinyUSB
|
||||
|
@ -207,6 +207,7 @@ static ssize_t tusb_read(int fd, void *data, size_t size)
|
||||
static int tusb_fstat(int fd, struct stat *st)
|
||||
{
|
||||
FD_CHECK(fd, -1);
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ static int cdcacm_open(const char *path, int flags, int mode)
|
||||
static int cdcacm_fstat(int fd, struct stat *st)
|
||||
{
|
||||
assert(fd == 0);
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ static ssize_t uart_read(int fd, void* data, size_t size)
|
||||
static int uart_fstat(int fd, struct stat * st)
|
||||
{
|
||||
assert(fd >=0 && fd < 3);
|
||||
st->st_blksize = BUFSIZ;
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
@ -438,9 +438,6 @@ ESP-IDF FreeRTOS configurations, see :doc:`FreeRTOS <../api-reference/kconfig>`
|
||||
will be modified. For more details regarding the effects of running ESP-IDF FreeRTOS
|
||||
on a single core, search for occurences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components.
|
||||
|
||||
:ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` will enable the
|
||||
functionality of :cpp:func:`xTaskCreateStaticPinnedToCore` in ESP-IDF FreeRTOS
|
||||
|
||||
:ref:`CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION` will trigger a halt in
|
||||
particular functions in ESP-IDF FreeRTOS which have not been fully tested
|
||||
in an SMP context.
|
||||
|
@ -412,9 +412,6 @@ The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with
|
||||
|
||||
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
|
||||
|
||||
.. note::
|
||||
The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available.
|
||||
|
||||
.. note::
|
||||
When deleting a ring buffer created via :cpp:func:`xRingbufferCreateStatic`,
|
||||
the function :cpp:func:`vRingbufferDelete` will not free any of the memory blocks. This must be done manually by the user after :cpp:func:`vRingbufferDelete` is called.
|
||||
|
@ -14,7 +14,6 @@ CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY=y
|
||||
CONFIG_BLE_MESH_MEM_ALLOC_MODE_IRAM_8BIT=y
|
||||
CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC=y
|
||||
|
@ -102,9 +102,11 @@ static void IRAM_ATTR test_int_wdt_cache_disabled(void)
|
||||
|
||||
static void test_stack_overflow(void)
|
||||
{
|
||||
volatile uint8_t stuff[CONFIG_ESP_MAIN_TASK_STACK_SIZE + 1000];
|
||||
for (int i = 0; i < sizeof(stuff); ++i) {
|
||||
stuff[i] = rand();
|
||||
register uint32_t* sp asm("sp");
|
||||
uint32_t *end = sp - CONFIG_ESP_MAIN_TASK_STACK_SIZE;
|
||||
// offset - 20 bytes from SP in order to not corrupt the current frame.
|
||||
for (uint32_t* ptr = sp - 5; ptr != end; --ptr) {
|
||||
*ptr = rand();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=n
|
||||
CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE=y
|
||||
CONFIG_FREERTOS_LEGACY_HOOKS=y
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP=y
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=10
|
||||
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
|
@ -12,7 +12,6 @@ CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=n
|
||||
CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE=y
|
||||
CONFIG_FREERTOS_LEGACY_HOOKS=y
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP=y
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=10
|
||||
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
|
@ -17,7 +17,6 @@ CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS=y
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=7
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
|
||||
CONFIG_COMPILER_STACK_CHECK=y
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_ESP_TIMER_PROFILING=y
|
||||
CONFIG_ADC_DISABLE_DAC=n
|
||||
CONFIG_COMPILER_WARN_WRITE_STRINGS=y
|
||||
|
Loading…
x
Reference in New Issue
Block a user