@@ -24,6 +24,39 @@ extern void REAL_FUNC(free)(void *mem);
2424
2525extern char __StackLimit ; /* Set by linker. */
2626
27+ #if !PICO_USE_MALLOC_MUTEX
28+ #define MALLOC_ENTER (outer ) ((void)0);
29+ #define MALLOC_EXIT (outer ) ((void)0);
30+ #elif !__PICOLIBC__
31+ #define MALLOC_ENTER (outer ) mutex_enter_blocking(&malloc_mutex);
32+ #define MALLOC_EXIT (outer ) mutex_exit(&malloc_mutex);
33+ #else
34+ static uint8_t mutex_exception_level_plus_one [NUM_CORES ];
35+ // PICOLIBC implementations of calloc and realloc may call malloc and free,
36+ // so we need to cope with re-entrant calls. We don't want to use a recursive
37+ // mutex as that won't catch usage within an ISR; instead we record the exception
38+ // nesting as of acquiring the mutex
39+ #define MALLOC_ENTER (outer ) \
40+ uint exception = __get_current_exception(); \
41+ uint core_num = get_core_num(); \
42+ /* we skip the locking on outer == false if we are in the same irq nesting */ \
43+ /* note: the `+ 1` is to distinguish no malloc nesting vs no-exception/irq level */ \
44+ bool do_lock = outer || exception + 1 != mutex_exception_level_plus_one [core_num ]; \
45+ if (do_lock ) { \
46+ mutex_enter_blocking (& malloc_mutex ); \
47+ if (outer ) mutex_exception_level_plus_one [core_num ] = (uint8_t )(exception + 1 ); \
48+ }
49+
50+ #define MALLOC_EXIT (outer ) \
51+ if (outer) { \
52+ mutex_exception_level_plus_one[core_num] = 0; \
53+ } \
54+ if (do_lock) { \
55+ mutex_exit(&malloc_mutex); \
56+ }
57+
58+ #endif
59+
2760static inline void check_alloc (__unused void * mem , __unused uint size ) {
2861#if PICO_MALLOC_PANIC
2962 if (!mem || (((char * )mem ) + size ) > & __StackLimit ) {
@@ -33,13 +66,9 @@ static inline void check_alloc(__unused void *mem, __unused uint size) {
3366}
3467
3568void * WRAPPER_FUNC (malloc )(size_t size ) {
36- #if PICO_USE_MALLOC_MUTEX
37- mutex_enter_blocking (& malloc_mutex );
38- #endif
69+ MALLOC_ENTER (false )
3970 void * rc = REAL_FUNC (malloc )(size );
40- #if PICO_USE_MALLOC_MUTEX
41- mutex_exit (& malloc_mutex );
42- #endif
71+ MALLOC_EXIT (false )
4372#if PICO_DEBUG_MALLOC
4473 if (!rc ) {
4574 printf ("malloc %d failed to allocate memory\n" , (uint ) size );
@@ -52,13 +81,9 @@ void *WRAPPER_FUNC(malloc)(size_t size) {
5281}
5382
5483void * WRAPPER_FUNC (calloc )(size_t count , size_t size ) {
55- #if PICO_USE_MALLOC_MUTEX
56- mutex_enter_blocking (& malloc_mutex );
57- #endif
84+ MALLOC_ENTER (true )
5885 void * rc = REAL_FUNC (calloc )(count , size );
59- #if PICO_USE_MALLOC_MUTEX
60- mutex_exit (& malloc_mutex );
61- #endif
86+ MALLOC_EXIT (true )
6287#if PICO_DEBUG_MALLOC
6388 if (!rc ) {
6489 printf ("calloc %d failed to allocate memory\n" , (uint ) (count * size ));
@@ -71,13 +96,9 @@ void *WRAPPER_FUNC(calloc)(size_t count, size_t size) {
7196}
7297
7398void * WRAPPER_FUNC (realloc )(void * mem , size_t size ) {
74- #if PICO_USE_MALLOC_MUTEX
75- mutex_enter_blocking (& malloc_mutex );
76- #endif
99+ MALLOC_ENTER (true )
77100 void * rc = REAL_FUNC (realloc )(mem , size );
78- #if PICO_USE_MALLOC_MUTEX
79- mutex_exit (& malloc_mutex );
80- #endif
101+ MALLOC_EXIT (true )
81102#if PICO_DEBUG_MALLOC
82103 if (!rc ) {
83104 printf ("realloc %d failed to allocate memory\n" , (uint ) size );
@@ -90,11 +111,7 @@ void *WRAPPER_FUNC(realloc)(void *mem, size_t size) {
90111}
91112
92113void WRAPPER_FUNC (free )(void * mem ) {
93- #if PICO_USE_MALLOC_MUTEX
94- mutex_enter_blocking (& malloc_mutex );
95- #endif
114+ MALLOC_ENTER (false )
96115 REAL_FUNC (free )(mem );
97- #if PICO_USE_MALLOC_MUTEX
98- mutex_exit (& malloc_mutex );
99- #endif
116+ MALLOC_EXIT (false )
100117}
0 commit comments