From bd216c37cb78fb9aef61796c5f57185ef0f8b980 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Sat, 21 May 2016 14:46:56 -0500 Subject: [PATCH 1/3] Make the IAR standard library thread safe Add the locks and flags necessary to make the IAR standard library thread safe. These changes consist of: -Add compiler flag "--guard_calls" to ensure C++ function-static variables with dynamic initializers are initialized in a thread safe manner -Add the linker flag "--threaded_lib" so the thread safe version of the standard library is used -Implement mutex functions required for IAR thread safety -Create a set of stub functions in retarget.c for when the rtos is not present --- hal/common/retarget.cpp | 12 +++++ rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 75 ++++++++++++++++++++++++++- workspace_tools/toolchains/iar.py | 6 +-- 3 files changed, 88 insertions(+), 5 deletions(-) diff --git a/hal/common/retarget.cpp b/hal/common/retarget.cpp index 21c6a7023b..a60acf0186 100644 --- a/hal/common/retarget.cpp +++ b/hal/common/retarget.cpp @@ -565,4 +565,16 @@ char* mbed_gets(char*s, int size, FILE *_file){ #endif } +#if defined (__ICCARM__) +// Stub out locks when an rtos is not present +extern "C" WEAK void __iar_system_Mtxinit(__iar_Rmtx *mutex) {} +extern "C" WEAK void __iar_system_Mtxdst(__iar_Rmtx *mutex) {} +extern "C" WEAK void __iar_system_Mtxlock(__iar_Rmtx *mutex) {} +extern "C" WEAK void __iar_system_Mtxunlock(__iar_Rmtx *mutex) {} +extern "C" WEAK void __iar_file_Mtxinit(__iar_Rmtx *mutex) {} +extern "C" WEAK void __iar_file_Mtxdst(__iar_Rmtx *mutex) {} +extern "C" WEAK void __iar_file_Mtxlock(__iar_Rmtx *mutex) {} +extern "C" WEAK void __iar_file_Mtxunlock(__iar_Rmtx *mutex) {} +#endif + } // namespace mbed diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h index f642ff43c1..736f08ebc7 100755 --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -54,13 +54,13 @@ #define OS_TCB_SIZE 52 #define OS_TMR_SIZE 8 -#if defined (__CC_ARM) && !defined (__MICROLIB) - typedef void *OS_ID; typedef uint32_t OS_TID; typedef uint32_t OS_MUT[4]; typedef uint32_t OS_RESULT; +#if defined (__CC_ARM) && !defined (__MICROLIB) + #define runtask_id() rt_tsk_self() #define mutex_init(m) rt_mut_init(m) #define mutex_wait(m) os_mut_wait(m,0xFFFFU) @@ -190,6 +190,77 @@ uint16_t const mp_tmr_size = 0U; extern void *__libspace_start; #endif +#if defined (__ICCARM__) +static osMutexId std_mutex_id_sys[_MAX_LOCK] = {0}; +static OS_MUT std_mutex_sys[_MAX_LOCK] = {0}; +#define _FOPEN_MAX 10 +static osMutexId std_mutex_id_file[_FOPEN_MAX] = {0}; +static OS_MUT std_mutex_file[_FOPEN_MAX] = {0}; +void __iar_system_Mtxinit(__iar_Rmtx *mutex) /* Initialize a system lock */ +{ + osMutexDef_t def; + uint32_t index; + for (index = 0; index < _MAX_LOCK; index++) { + if (0 == std_mutex_id_sys[index]) { + def.mutex = &std_mutex_sys[index]; + std_mutex_id_sys[index] = osMutexCreate(&def); + *mutex = (__iar_Rmtx*)&std_mutex_id_sys[index]; + return; + } + } + // This should never happen + error("Not enough mutexes\n"); +} + +void __iar_system_Mtxdst(__iar_Rmtx *mutex)/*Destroy a system lock */ +{ + osMutexDelete(*(osMutexId*)*mutex); + *mutex = 0; +} + +void __iar_system_Mtxlock(__iar_Rmtx *mutex) /* Lock a system lock */ +{ + osMutexWait(*(osMutexId*)*mutex, osWaitForever); +} + +void __iar_system_Mtxunlock(__iar_Rmtx *mutex) /* Unlock a system lock */ +{ + osMutexRelease(*(osMutexId*)*mutex); +} + +void __iar_file_Mtxinit(__iar_Rmtx *mutex)/*Initialize a file lock */ +{ + osMutexDef_t def; + uint32_t index; + for (index = 0; index < _FOPEN_MAX; index++) { + if (0 == std_mutex_id_file[index]) { + def.mutex = &std_mutex_file[index]; + std_mutex_id_file[index] = osMutexCreate(&def); + *mutex = (__iar_Rmtx*)&std_mutex_id_file[index]; + return; + } + } + // The variable _FOPEN_MAX needs to be increased + error("Not enough mutexes\n"); +} + +void __iar_file_Mtxdst(__iar_Rmtx *mutex) /* Destroy a file lock */ +{ + osMutexDelete(*(osMutexId*)*mutex); + *mutex = 0; +} + +void __iar_file_Mtxlock(__iar_Rmtx *mutex) /* Lock a file lock */ +{ + osMutexWait(*(osMutexId*)*mutex, osWaitForever); +} + +void __iar_file_Mtxunlock(__iar_Rmtx *mutex) /* Unlock a file lock */ +{ + osMutexRelease(*(osMutexId*)*mutex); +} + +#endif /*---------------------------------------------------------------------------- * RTX Optimizations (empty functions) diff --git a/workspace_tools/toolchains/iar.py b/workspace_tools/toolchains/iar.py index 391b09d6a0..aba1dd7f71 100644 --- a/workspace_tools/toolchains/iar.py +++ b/workspace_tools/toolchains/iar.py @@ -66,10 +66,10 @@ class IAR(mbedToolchain): self.asm = [join(IAR_BIN, "iasmarm")] + ["--cpu", cpuchoice] if not "analyze" in self.options: self.cc = [main_cc] + c_flags - self.cppc = [main_cc, "--c++", "--no_rtti", "--no_exceptions"] + c_flags + self.cppc = [main_cc, "--c++", "--no_rtti", "--no_exceptions", "--guard_calls"] + c_flags else: self.cc = [join(GOANNA_PATH, "goannacc"), '--with-cc="%s"' % main_cc.replace('\\', '/'), "--dialect=iar-arm", '--output-format="%s"' % self.GOANNA_FORMAT] + c_flags - self.cppc = [join(GOANNA_PATH, "goannac++"), '--with-cxx="%s"' % main_cc.replace('\\', '/'), "--dialect=iar-arm", '--output-format="%s"' % self.GOANNA_FORMAT] + ["--c++", "--no_rtti", "--no_exceptions"] + c_flags + self.cppc = [join(GOANNA_PATH, "goannac++"), '--with-cxx="%s"' % main_cc.replace('\\', '/'), "--dialect=iar-arm", '--output-format="%s"' % self.GOANNA_FORMAT] + ["--c++", "--no_rtti", "--no_exceptions", "--guard_calls"] + c_flags self.ld = join(IAR_BIN, "ilinkarm") self.ar = join(IAR_BIN, "iarchive") self.elf2bin = join(IAR_BIN, "ielftool") @@ -114,7 +114,7 @@ class IAR(mbedToolchain): self.default_cmd([self.ar, lib_path] + objects) def link(self, output, objects, libraries, lib_dirs, mem_map): - args = [self.ld, "-o", output, "--config", mem_map, "--skip_dynamic_initialization"] + args = [self.ld, "-o", output, "--config", mem_map, "--skip_dynamic_initialization", "--threaded_lib"] self.default_cmd(self.hook.get_cmdline_linker(args + objects + libraries)) @hook_tool From 793f9c566a7a08eeee69e4e03e49ad1b84499747 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Mon, 23 May 2016 20:59:02 -0500 Subject: [PATCH 2/3] Add partial thread safety to GCC Add lock functions so that malloc and environment variable access are thread safe. Add the compiler option "-o thread-safe" to use the full version of newlib which is thread safe. Note that this patch does NOT make file access thread safe. --- rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 30 +++++++++++++++++++++++++++ workspace_tools/toolchains/gcc.py | 3 ++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h index 736f08ebc7..698a7ce455 100755 --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -624,11 +624,18 @@ __asm void __rt_entry (void) { #elif defined (__GNUC__) +osMutexDef(malloc_mutex); +static osMutexId malloc_mutex_id; +osMutexDef(env_mutex); +static osMutexId env_mutex_id; + extern void __libc_fini_array(void); extern void __libc_init_array (void); extern int main(int argc, char **argv); void pre_main(void) { + malloc_mutex_id = osMutexCreate(osMutex(malloc_mutex)); + env_mutex_id = osMutexCreate(osMutex(env_mutex)); atexit(__libc_fini_array); __libc_init_array(); main(0, NULL); @@ -651,6 +658,29 @@ __attribute__((naked)) void software_init_hook (void) { ); } +// Opaque declaration of _reent structure +struct _reent; + +void __malloc_lock( struct _reent *_r ) +{ + osMutexWait(malloc_mutex_id, osWaitForever); +} + +void __malloc_unlock( struct _reent *_r ) +{ + osMutexRelease(malloc_mutex_id); +} + +void __env_lock( struct _reent *_r ) +{ + osMutexWait(env_mutex_id, osWaitForever); +} + +void __env_unlock( struct _reent *_r ) +{ + osMutexRelease(env_mutex_id); +} + #elif defined (__ICCARM__) extern void* __vector_table; diff --git a/workspace_tools/toolchains/gcc.py b/workspace_tools/toolchains/gcc.py index 7693652930..a6cb063335 100644 --- a/workspace_tools/toolchains/gcc.py +++ b/workspace_tools/toolchains/gcc.py @@ -183,7 +183,8 @@ class GCC_ARM(GCC): GCC.__init__(self, target, options, notify, macros, silent, GCC_ARM_PATH, extra_verbose=extra_verbose) # Use latest gcc nanolib - self.ld.append("--specs=nano.specs") + if "thread-safe" not in self.options: + self.ld.append("--specs=nano.specs") if target.name in ["LPC1768", "LPC4088", "LPC4088_DM", "LPC4330", "UBLOX_C027", "LPC2368"]: self.ld.extend(["-u _printf_float", "-u _scanf_float"]) elif target.name in ["RZ_A1H", "VK_RZ_A1H", "ARCH_MAX", "DISCO_F407VG", "DISCO_F429ZI", "DISCO_F469NI", "NUCLEO_F401RE", "NUCLEO_F410RB", "NUCLEO_F411RE", "NUCLEO_F446RE", "ELMO_F411RE", "MTS_MDOT_F411RE", "MTS_DRAGONFLY_F411RE", "DISCO_F746NG"]: From 5b23d9b2686301ebf70f02b6b43c4c3dc3d25205 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Tue, 24 May 2016 21:17:08 -0500 Subject: [PATCH 3/3] Remove assembler directives Remove the assembler directives from the inline assembly in RTX_CM_lib.h since these can have unintended side effects in the surrounding C code. --- rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h index 698a7ce455..1316072ff1 100755 --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -643,8 +643,6 @@ void pre_main(void) { __attribute__((naked)) void software_init_hook (void) { __asm ( - ".syntax unified\n" - ".thumb\n" "bl osKernelInitialize\n" #ifdef __MBED_CMSIS_RTOS_CM "bl set_main_stack\n"