M CMakeLists.txt => CMakeLists.txt +2 -0
@@ 38,6 38,8 @@ string(TOLOWER "${PROJECT_TARGET_NAME}" PROJECT_TARGET_NAME)
message("Project target name: ${PROJECT_TARGET_NAME}")
if (NOT ${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
set(ENABLE_TESTS ON)
+else()
+ add_compile_options(-include ${CMAKE_SOURCE_DIR}/board/rt1051/gthr.h)
endif()
if (${ENABLE_TESTS})
M Target_RT1051.cmake => Target_RT1051.cmake +2 -0
@@ 35,6 35,8 @@ add_compile_definitions(
_HAVE_SQLITE_CONFIG_H
CPP_FREERTOS_NO_EXCEPTIONS
_GLIBCXX_HAVE_DIRENT_H
+ __GTHREADS
+ _GLIBCXX_GCC_GTHR_SINGLE_H
)
add_compile_options(
M board/rt1051/CMakeLists.txt => board/rt1051/CMakeLists.txt +1 -0
@@ 17,6 17,7 @@ target_sources(board
memwrap.c
newlib/fs_dir.cc
newlib/io_syscalls.cpp
+ newlib/cxx_guards.cpp
xip/evkbimxrt1050_flexspi_nor_config.c
xip/evkbimxrt1050_sdram_ini_dcd.c
xip/fsl_flexspi_nor_boot.c
A board/rt1051/gthr.h => board/rt1051/gthr.h +298 -0
@@ 0,0 1,298 @@
+/* Threads compatibility routines for libgcc2 and libobjc. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1997-2020 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#if !defined(_GLIBCXX_GCC_GTHR_MUDITA_H) && !defined(__ASSEMBLER__)
+#define _GLIBCXX_GCC_GTHR_MUDITA_H
+
+/* Just provide compatibility for mutex handling. */
+
+typedef int __gthread_key_t;
+typedef int __gthread_once_t;
+typedef int __gthread_mutex_t;
+typedef int __gthread_recursive_mutex_t;
+
+#define __GTHREAD_ONCE_INIT 0
+#define __GTHREAD_MUTEX_INIT 0
+#define __GTHREAD_MUTEX_INIT_FUNCTION(mx) do {} while (0)
+#define __GTHREAD_RECURSIVE_MUTEX_INIT 0
+
+#define _GLIBCXX_UNUSED __attribute__((__unused__))
+
+#ifdef _LIBOBJC
+
+/* Thread local storage for a single thread */
+static void *thread_local_storage = NULL;
+
+/* Backend initialization functions */
+
+/* Initialize the threads subsystem. */
+static inline int
+__gthread_objc_init_thread_system (void)
+{
+ /* No thread support available */
+ return -1;
+}
+
+/* Close the threads subsystem. */
+static inline int
+__gthread_objc_close_thread_system (void)
+{
+ /* No thread support available */
+ return -1;
+}
+
+/* Backend thread functions */
+
+/* Create a new thread of execution. */
+static inline objc_thread_t
+__gthread_objc_thread_detach (void (* func)(void *), void * arg _GLIBCXX_UNUSED)
+{
+ /* No thread support available */
+ return NULL;
+}
+
+/* Set the current thread's priority. */
+static inline int
+__gthread_objc_thread_set_priority (int priority _GLIBCXX_UNUSED)
+{
+ /* No thread support available */
+ return -1;
+}
+
+/* Return the current thread's priority. */
+static inline int
+__gthread_objc_thread_get_priority (void)
+{
+ return OBJC_THREAD_INTERACTIVE_PRIORITY;
+}
+
+/* Yield our process time to another thread. */
+static inline void
+__gthread_objc_thread_yield (void)
+{
+ return;
+}
+
+/* Terminate the current thread. */
+static inline int
+__gthread_objc_thread_exit (void)
+{
+ /* No thread support available */
+ /* Should we really exit the program */
+ /* exit (&__objc_thread_exit_status); */
+ return -1;
+}
+
+/* Returns an integer value which uniquely describes a thread. */
+static inline objc_thread_t
+__gthread_objc_thread_id (void)
+{
+ /* No thread support, use 1. */
+ return (objc_thread_t) 1;
+}
+
+/* Sets the thread's local storage pointer. */
+static inline int
+__gthread_objc_thread_set_data (void *value)
+{
+ thread_local_storage = value;
+ return 0;
+}
+
+/* Returns the thread's local storage pointer. */
+static inline void *
+__gthread_objc_thread_get_data (void)
+{
+ return thread_local_storage;
+}
+
+/* Backend mutex functions */
+
+/* Allocate a mutex. */
+static inline int
+__gthread_objc_mutex_allocate (objc_mutex_t mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+/* Deallocate a mutex. */
+static inline int
+__gthread_objc_mutex_deallocate (objc_mutex_t mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+/* Grab a lock on a mutex. */
+static inline int
+__gthread_objc_mutex_lock (objc_mutex_t mutex _GLIBCXX_UNUSED)
+{
+ /* There can only be one thread, so we always get the lock */
+ return 0;
+}
+
+/* Try to grab a lock on a mutex. */
+static inline int
+__gthread_objc_mutex_trylock (objc_mutex_t mutex _GLIBCXX_UNUSED)
+{
+ /* There can only be one thread, so we always get the lock */
+ return 0;
+}
+
+/* Unlock the mutex */
+static inline int
+__gthread_objc_mutex_unlock (objc_mutex_t mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+/* Backend condition mutex functions */
+
+/* Allocate a condition. */
+static inline int
+__gthread_objc_condition_allocate (objc_condition_t condition _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+/* Deallocate a condition. */
+static inline int
+__gthread_objc_condition_deallocate (objc_condition_t condition _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+/* Wait on the condition */
+static inline int
+__gthread_objc_condition_wait (objc_condition_t condition _GLIBCXX_UNUSED,
+ objc_mutex_t mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+/* Wake up all threads waiting on this condition. */
+static inline int
+__gthread_objc_condition_broadcast (objc_condition_t condition _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+/* Wake up one thread waiting on this condition. */
+static inline int
+__gthread_objc_condition_signal (objc_condition_t condition _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+#else /* _LIBOBJC */
+
+static inline int
+__gthread_active_p (void)
+{
+ return 1;
+}
+
+static inline int
+__gthread_once (__gthread_once_t *__once _GLIBCXX_UNUSED, void (*__func) (void) _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline int _GLIBCXX_UNUSED
+__gthread_key_create (__gthread_key_t *__key _GLIBCXX_UNUSED, void (*__func) (void *) _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static int _GLIBCXX_UNUSED
+__gthread_key_delete (__gthread_key_t __key _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline void *
+__gthread_getspecific (__gthread_key_t __key _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline int
+__gthread_setspecific (__gthread_key_t __key _GLIBCXX_UNUSED, const void *__v _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline int
+__gthread_mutex_destroy (__gthread_mutex_t *__mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline int
+__gthread_mutex_lock (__gthread_mutex_t *__mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline int
+__gthread_mutex_trylock (__gthread_mutex_t *__mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline int
+__gthread_mutex_unlock (__gthread_mutex_t *__mutex _GLIBCXX_UNUSED)
+{
+ return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
+{
+ return __gthread_mutex_lock (__mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
+{
+ return __gthread_mutex_trylock (__mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
+{
+ return __gthread_mutex_unlock (__mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
+{
+ return __gthread_mutex_destroy (__mutex);
+}
+
+#endif /* _LIBOBJC */
+
+#undef _GLIBCXX_UNUSED
+
+#endif /* ! _GLIBCXX_GCC_GTHR_MUDITA_H */
A board/rt1051/newlib/cxx_guards.cpp => board/rt1051/newlib/cxx_guards.cpp +218 -0
@@ 0,0 1,218 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <cxxabi.h>
+#include <stdint.h>
+#include <limits.h>
+#include <algorithm>
+#include <sys/lock.h>
+#include "FreeRTOS.h"
+#include "semphr.h"
+#include "task.h"
+
+using __cxxabiv1::__guard;
+
+static SemaphoreHandle_t s_static_init_mutex = NULL; //!< lock used for the critical section
+static SemaphoreHandle_t s_static_init_wait_sem = NULL; //!< counting semaphore used by the waiting tasks
+static size_t s_static_init_waiting_count = 0; //!< number of tasks which are waiting for static init guards
+#ifndef _NDEBUG
+static size_t s_static_init_max_waiting_count = 0; //!< maximum ever value of the above; can be inspected using GDB for debugging purposes
+#endif
+
+extern "C" int __cxa_guard_acquire(__guard* pg);
+extern "C" void __cxa_guard_release(__guard* pg);
+extern "C" void __cxa_guard_abort(__guard* pg);
+extern "C" void __cxa_guard_dummy(void);
+
+/**
+ * Layout of the guard object (defined by the ABI).
+ *
+ * Compiler will check lower byte before calling guard functions.
+ */
+typedef struct {
+ uint8_t ready; //!< nonzero if initialization is done
+ uint8_t pending; //!< nonzero if initialization is in progress
+} guard_t;
+
+static void static_init_prepare()
+{
+ portENTER_CRITICAL();
+ if (s_static_init_mutex == NULL) {
+ s_static_init_mutex = xSemaphoreCreateMutex();
+ s_static_init_wait_sem = xSemaphoreCreateCounting(INT_MAX, 0);
+ if (s_static_init_mutex == NULL || s_static_init_wait_sem == NULL) {
+ // no way to bail out of static initialization without these
+ abort();
+ }
+ }
+ portEXIT_CRITICAL();
+}
+
+/**
+ * Use s_static_init_wait_sem to wait until guard->pending == 0.
+ * Preconditions:
+ * - s_static_init_mutex taken
+ * - guard.pending == 1
+ * Postconditions:
+ * - s_static_init_mutex taken
+ * - guard.pending == 0
+ */
+static void wait_for_guard_obj(guard_t* g)
+{
+ s_static_init_waiting_count++;
+#ifndef _NDEBUG
+ s_static_init_max_waiting_count = std::max(s_static_init_waiting_count,
+ s_static_init_max_waiting_count);
+#endif
+
+ do {
+ auto result = xSemaphoreGive(s_static_init_mutex);
+ assert(result);
+ static_cast<void>(result);
+ /* Task may be preempted here, but this isn't a problem,
+ * as the semaphore will be given exactly the s_static_init_waiting_count
+ * number of times; eventually the current task will execute next statement,
+ * which will immediately succeed.
+ */
+ result = xSemaphoreTake(s_static_init_wait_sem, portMAX_DELAY);
+ assert(result);
+ /* At this point the semaphore was given, so all waiting tasks have woken up.
+ * We take s_static_init_mutex before accessing the state of the guard
+ * object again.
+ */
+ result = xSemaphoreTake(s_static_init_mutex, portMAX_DELAY);
+ assert(result);
+ /* Semaphore may have been given because some other guard object became ready.
+ * Check the guard object we need and wait again if it is still pending.
+ */
+ } while(g->pending);
+ s_static_init_waiting_count--;
+}
+
+/**
+ * Unblock tasks waiting for static initialization to complete.
+ * Preconditions:
+ * - s_static_init_mutex taken
+ * Postconditions:
+ * - s_static_init_mutex taken
+ */
+static void signal_waiting_tasks()
+{
+ auto count = s_static_init_waiting_count;
+ while (count--) {
+ xSemaphoreGive(s_static_init_wait_sem);
+ }
+}
+
+extern "C" int __cxa_guard_acquire(__guard* pg)
+{
+ guard_t* g = reinterpret_cast<guard_t*>(pg);
+ const auto scheduler_started = xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED;
+ if (!scheduler_started) {
+ if (g->pending) {
+ /* Before the scheduler has started, there we don't support simultaneous
+ * static initialization. This may be implemented using a spinlock and a
+ * s32c1i instruction, though.
+ */
+ abort();
+ }
+ } else {
+ if (s_static_init_mutex == NULL) {
+ static_init_prepare();
+ }
+
+ /* We don't need to use double-checked locking pattern here, as the compiler
+ * must generate code to check if the first byte of *pg is non-zero, before
+ * calling __cxa_guard_acquire.
+ */
+ auto result = xSemaphoreTake(s_static_init_mutex, portMAX_DELAY);
+ assert(result);
+ static_cast<void>(result);
+ if (g->pending) {
+ /* Another task is doing initialization at the moment; wait until it calls
+ * __cxa_guard_release or __cxa_guard_abort
+ */
+ wait_for_guard_obj(g);
+ /* At this point there are two scenarios:
+ * - the task which was doing static initialization has called __cxa_guard_release,
+ * which means that g->ready is set. We need to return 0.
+ * - the task which was doing static initialization has called __cxa_guard_abort,
+ * which means that g->ready is not set; we should acquire the guard and return 1,
+ * same as for the case if we didn't have to wait.
+ * Note: actually the second scenario is unlikely to occur in the current
+ * configuration because exception support is disabled.
+ */
+ }
+ }
+ int ret;
+ if (g->ready) {
+ /* Static initialization has been done by another task; nothing to do here */
+ ret = 0;
+ } else {
+ /* Current task can start doing static initialization */
+ g->pending = 1;
+ ret = 1;
+ }
+ if (scheduler_started) {
+ auto result = xSemaphoreGive(s_static_init_mutex);
+ assert(result);
+ static_cast<void>(result);
+ }
+ return ret;
+}
+
+extern "C" void __cxa_guard_release(__guard* pg)
+{
+ guard_t* g = reinterpret_cast<guard_t*>(pg);
+ const auto scheduler_started = xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED;
+ if (scheduler_started) {
+ auto result = xSemaphoreTake(s_static_init_mutex, portMAX_DELAY);
+ assert(result);
+ static_cast<void>(result);
+ }
+ assert(g->pending && "tried to release a guard which wasn't acquired");
+ g->pending = 0;
+ /* Initialization was successful */
+ g->ready = 1;
+ if (scheduler_started) {
+ /* Unblock the tasks waiting for static initialization to complete */
+ signal_waiting_tasks();
+ auto result = xSemaphoreGive(s_static_init_mutex);
+ assert(result);
+ static_cast<void>(result);
+ }
+}
+
+extern "C" void __cxa_guard_abort(__guard* pg)
+{
+ guard_t* g = reinterpret_cast<guard_t*>(pg);
+ const auto scheduler_started = xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED;
+ if (scheduler_started) {
+ auto result = xSemaphoreTake(s_static_init_mutex, portMAX_DELAY);
+ assert(result);
+ static_cast<void>(result);
+ }
+ assert(!g->ready && "tried to abort a guard which is ready");
+ assert(g->pending && "tried to release a guard which is not acquired");
+ g->pending = 0;
+ if (scheduler_started) {
+ /* Unblock the tasks waiting for static initialization to complete */
+ signal_waiting_tasks();
+ auto result = xSemaphoreGive(s_static_init_mutex);
+ assert(result);
+ static_cast<void>(result);
+ }
+}
+
+/**
+ * Dummy function used to force linking this file instead of the same one in libstdc++.
+ * This works via -u __cxa_guard_dummy flag in component.mk
+ */
+extern "C" void __cxa_guard_dummy(void)
+{
+}
D board/rt1051/newlib/include/ext/atomicity.h => board/rt1051/newlib/include/ext/atomicity.h +0 -98
@@ 1,98 0,0 @@
-// Support for atomic operations -*- C++ -*-
-
-// Copyright (C) 2004-2020 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library. This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-/** @file ext/atomicity.h
- * This file is a GNU extension to the Standard C++ Library.
- */
-
-#ifndef _GLIBCXX_ATOMICITY_H
-#define _GLIBCXX_ATOMICITY_H 1
-
-#pragma GCC system_header
-
-#include <bits/c++config.h>
-#include <bits/gthr.h>
-#include <bits/atomic_word.h>
-
-namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
-{
- _GLIBCXX_BEGIN_NAMESPACE_VERSION
-
- // Functions for portable atomic access.
- // To abstract locking primitives across all thread policies, use:
- // __exchange_and_add_dispatch
- // __atomic_add_dispatch
-#ifdef _GLIBCXX_ATOMIC_BUILTINS
- static inline _Atomic_word __attribute__((__always_inline__))
- __exchange_and_add(volatile _Atomic_word * __mem, int __val)
- {
- return __atomic_add_fetch(__mem, __val, __ATOMIC_ACQ_REL);
- }
-
- static inline void __attribute__((__always_inline__)) __atomic_add(volatile _Atomic_word * __mem, int __val)
- {
- __atomic_add_fetch(__mem, __val, __ATOMIC_ACQ_REL);
- }
-#else
- _Atomic_word __exchange_and_add(volatile _Atomic_word *, int) _GLIBCXX_NOTHROW;
-
- void __atomic_add(volatile _Atomic_word *, int) _GLIBCXX_NOTHROW;
-#endif
-
- static inline _Atomic_word __attribute__((__always_inline__))
- __exchange_and_add_single(_Atomic_word * __mem, int __val)
- {
- return __atomic_add_fetch(__mem, __val, __ATOMIC_ACQ_REL);
- }
-
- static inline void __attribute__((__always_inline__)) __atomic_add_single(_Atomic_word * __mem, int __val)
- {
- __atomic_add_fetch(__mem, __val, __ATOMIC_ACQ_REL);
- }
-
- static inline _Atomic_word __attribute__((__always_inline__))
- __exchange_and_add_dispatch(_Atomic_word * __mem, int __val)
- {
- return __exchange_and_add_single(__mem, __val);
- }
-
- static inline void __attribute__((__always_inline__)) __atomic_add_dispatch(_Atomic_word * __mem, int __val)
- {
- __atomic_add_single(__mem, __val);
- }
-
- _GLIBCXX_END_NAMESPACE_VERSION
-} // namespace )
-
-// Even if the CPU doesn't need a memory barrier, we need to ensure
-// that the compiler doesn't reorder memory accesses across the
-// barriers.
-#ifndef _GLIBCXX_READ_MEM_BARRIER
-#define _GLIBCXX_READ_MEM_BARRIER __atomic_thread_fence(__ATOMIC_ACQUIRE)
-#endif
-#ifndef _GLIBCXX_WRITE_MEM_BARRIER
-#define _GLIBCXX_WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE)
-#endif
-
-#endif
M config/format-config.sh => config/format-config.sh +2 -0
@@ 18,6 18,8 @@ export declare ignore_paths=(
'.*/lib/'
'build'
'board/rt1051/xip/'
+ 'board/rt1051/gthr.h'
+ 'board/rt1051/newlib/cxx_guards.cpp'
'board/rt1051/newlib/dir-common.h'
'board/rt1051/newlib/include/'
'host-tools/littlefs-fuse/lfsfuse/'
M third-party/CrashDebug/CrashCatcher/CMakeLists.txt => third-party/CrashDebug/CrashCatcher/CMakeLists.txt +3 -3
@@ 20,9 20,9 @@ target_sources(
include/CrashCatcher/CrashCatcher.h
)
-set_source_files_properties(
- CrashCatcher_armv7m.S
- PROPERTIES LANGUAGE C
+set_property(
+ SOURCE CrashCatcher_armv7m.S
+ APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp"
)
target_include_directories(