Skip to content

Commit 66eb061

Browse files
Major multicore fixes Newlib and FreeRTOS (earlephilhower#640)
Instead of wrapping the memory functions in the link stage, rebuild Newlib and enable retargetable locks. Override the weak definitions in the libc.a with our own, SDK based ones. The wrapping utilized before catches app-level memory allocations but misses allocations inside Newlib libc (like printf/etc.). Each core needs its own _impure_ptr or else crashes like the one seen in parallel printf_floats can happen. Enable it in the toolchain build and implement a simple swapper here. FreeRTOS SMP doesn't support Newlib's dynamic reent which is needed to allow save MT support. Minor patch to FreeRTOS and update the FreeRTOS variant.cpp and setup to support it.
1 parent af8f544 commit 66eb061

File tree

8 files changed

+280
-157
lines changed

8 files changed

+280
-157
lines changed

cores/rp2040/RP2040USB.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ static uint8_t *GetDescHIDReport(int *len) {
130130
return __hid_report;
131131
}
132132

133-
static void __SetupDescHIDReport() {
133+
void __SetupDescHIDReport() {
134134
if (__USBInstallKeyboard && __USBInstallMouse) {
135135
uint8_t desc_hid_report[] = {
136136
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)),
@@ -179,7 +179,7 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
179179
return usbd_desc_cfg;
180180
}
181181

182-
static void __SetupUSBDescriptor() {
182+
void __SetupUSBDescriptor() {
183183
if (!usbd_desc_cfg) {
184184
bool hasHID = __USBInstallKeyboard || __USBInstallMouse;
185185

cores/rp2040/lock.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
Newlib retargetable lock class using RP2040 SDK
3+
4+
Overrides weak functions in Newlib for locking to safely support
5+
multi-core operation. Does not need any --wrap for memory allocators.
6+
7+
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
8+
9+
This library is free software; you can redistribute it and/or
10+
modify it under the terms of the GNU Lesser General Public
11+
License as published by the Free Software Foundation; either
12+
version 2.1 of the License, or (at your option) any later version.
13+
14+
This library is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
Lesser General Public License for more details.
18+
19+
You should have received a copy of the GNU Lesser General Public
20+
License along with this library; if not, write to the Free Software
21+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22+
*/
23+
24+
25+
#include <pico/mutex.h>
26+
#include <sys/lock.h>
27+
28+
recursive_mutex_t __lock___sinit_recursive_mutex;
29+
recursive_mutex_t __lock___sfp_recursive_mutex;
30+
recursive_mutex_t __lock___atexit_recursive_mutex;
31+
mutex_t __lock___at_quick_exit_mutex;
32+
recursive_mutex_t __lock___malloc_recursive_mutex;
33+
recursive_mutex_t __lock___env_recursive_mutex;
34+
mutex_t __lock___tz_mutex;
35+
mutex_t __lock___dd_hash_mutex;
36+
mutex_t __lock___arc4random_mutex;
37+
38+
39+
__attribute__((constructor)) void __init_all_newlib_mutexes() {
40+
recursive_mutex_init(&__lock___sinit_recursive_mutex);
41+
recursive_mutex_init(&__lock___sfp_recursive_mutex);
42+
recursive_mutex_init(&__lock___atexit_recursive_mutex);
43+
mutex_init(&__lock___at_quick_exit_mutex);
44+
recursive_mutex_init(&__lock___malloc_recursive_mutex);
45+
recursive_mutex_init(&__lock___env_recursive_mutex);
46+
mutex_init(&__lock___tz_mutex);
47+
mutex_init(&__lock___dd_hash_mutex);
48+
mutex_init(&__lock___arc4random_mutex);
49+
}
50+
51+
void __retarget_lock_init(_LOCK_T *lock) {
52+
mutex_init((mutex_t*) lock);
53+
}
54+
55+
void __retarget_lock_init_recursive(_LOCK_T *lock) {
56+
recursive_mutex_init((recursive_mutex_t*) lock);
57+
}
58+
59+
void __retarget_lock_close(_LOCK_T lock) {
60+
(void) lock;
61+
}
62+
63+
void __retarget_lock_close_recursive(_LOCK_T lock) {
64+
(void) lock;
65+
}
66+
67+
void __retarget_lock_acquire(_LOCK_T lock) {
68+
mutex_enter_blocking((mutex_t*)lock);
69+
}
70+
71+
void __retarget_lock_acquire_recursive(_LOCK_T lock) {
72+
recursive_mutex_enter_blocking((recursive_mutex_t*)lock);
73+
}
74+
75+
int __retarget_lock_try_acquire(_LOCK_T lock) {
76+
return mutex_try_enter((mutex_t *)lock, NULL);
77+
}
78+
79+
int __retarget_lock_try_acquire_recursive(_LOCK_T lock) {
80+
return recursive_mutex_try_enter((recursive_mutex_t*)lock, NULL);
81+
}
82+
83+
void __retarget_lock_release(_LOCK_T lock) {
84+
mutex_exit((mutex_t*)lock);
85+
}
86+
87+
void __retarget_lock_release_recursive(_LOCK_T lock) {
88+
recursive_mutex_exit((recursive_mutex_t*)lock);
89+
}

cores/rp2040/main.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "RP2040USB.h"
2323
#include <pico/stdlib.h>
2424
#include <pico/multicore.h>
25+
#include <reent.h>
2526

2627
RP2040 rp2040;
2728
extern "C" {
@@ -72,6 +73,7 @@ extern void __loop() {
7273
arduino::serialEvent2Run();
7374
}
7475
}
76+
static struct _reent *_impure_ptr1 = nullptr;
7577

7678
extern "C" int main() {
7779
#if F_CPU != 125000000
@@ -81,6 +83,12 @@ extern "C" int main() {
8183
// Let rest of core know if we're using FreeRTOS
8284
__isFreeRTOS = initFreeRTOS ? true : false;
8385

86+
// Allocate impure_ptr (newlib temps) if there is a 2nd core running
87+
if (!__isFreeRTOS && (setup1 || loop1)) {
88+
_impure_ptr1 = (struct _reent*)calloc(sizeof(struct _reent), 1);
89+
_REENT_INIT_PTR(_impure_ptr1);
90+
}
91+
8492
mutex_init(&_pioMutex);
8593

8694
rp2040.begin();
@@ -142,3 +150,21 @@ extern "C" int main() {
142150
extern "C" unsigned long ulMainGetRunTimeCounterValue() {
143151
return rp2040.getCycleCount64();
144152
}
153+
154+
extern "C" void __register_impure_ptr(struct _reent *p) {
155+
if (get_core_num() == 0) {
156+
_impure_ptr = p;
157+
} else {
158+
_impure_ptr1 = p;
159+
}
160+
}
161+
162+
163+
// TODO: FreeRTOS should implement this based on thread ID (and each thread should have its own struct _reent
164+
extern "C" struct _reent *__wrap___getreent() {
165+
if (get_core_num() == 0) {
166+
return _impure_ptr;
167+
} else {
168+
return _impure_ptr1;
169+
}
170+
}

lib/platform_wrap.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@
7171
-Wl,--wrap=atanf
7272
-Wl,--wrap=atanh
7373
-Wl,--wrap=atanhf
74-
-Wl,--wrap=calloc
7574
-Wl,--wrap=cbrt
7675
-Wl,--wrap=cbrtf
7776
-Wl,--wrap=ceil
@@ -105,7 +104,6 @@
105104
-Wl,--wrap=fmaf
106105
-Wl,--wrap=fmod
107106
-Wl,--wrap=fmodf
108-
-Wl,--wrap=free
109107
-Wl,--wrap=hypot
110108
-Wl,--wrap=hypotf
111109
-Wl,--wrap=ldexp
@@ -118,7 +116,6 @@
118116
-Wl,--wrap=log2
119117
-Wl,--wrap=log2f
120118
-Wl,--wrap=logf
121-
-Wl,--wrap=malloc
122119
-Wl,--wrap=memcpy
123120
-Wl,--wrap=memset
124121
-Wl,--wrap=__popcountdi2
@@ -127,7 +124,6 @@
127124
-Wl,--wrap=powf
128125
-Wl,--wrap=powint
129126
-Wl,--wrap=powintf
130-
-Wl,--wrap=realloc
131127
-Wl,--wrap=remainder
132128
-Wl,--wrap=remainderf
133129
-Wl,--wrap=remquo
@@ -148,3 +144,4 @@
148144
-Wl,--wrap=tanhf
149145
-Wl,--wrap=trunc
150146
-Wl,--wrap=truncf
147+
-Wl,--wrap=__getreent

libraries/FreeRTOS/src/FreeRTOSConfig.h

100755100644
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
#define configSUPPORT_STATIC_ALLOCATION 0
2828
#define configSTACK_DEPTH_TYPE uint32_t
2929

30+
#define configUSE_NEWLIB_REENTRANT 1
31+
#include <reent.h>
32+
extern void __register_impure_ptr(struct _reent *p);
33+
#define portSET_IMPURE_PTR(x) __register_impure_ptr(x)
34+
3035
/* Run time stats related definitions. */
3136
void vMainConfigureTimerForRunTimeStats( void );
3237
unsigned long ulMainGetRunTimeCounterValue( void );

libraries/FreeRTOS/src/variantHooks.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,16 @@ static void __usb(void *param)
409409
}
410410
}
411411

412+
extern void __SetupDescHIDReport();
413+
extern void __SetupUSBDescriptor();
412414

413415
void __USBStart()
414416
{
415417
mutex_init(&__usb_mutex);
418+
419+
__SetupDescHIDReport();
420+
__SetupUSBDescriptor();
421+
416422
// Make highest prio and locked to core 0
417423
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 1, &__usbTask);
418424
vTaskCoreAffinitySet( __usbTask, 1 << 0 );

0 commit comments

Comments
 (0)