Merge pull request #14598 from maribu/avr-cpp
cpu/atmega_common: Provide C++ support (without libstdc++)
This commit is contained in:
commit
22e9ba12a3
@ -17,6 +17,7 @@ config CPU_COMMON_ATMEGA
|
||||
bool
|
||||
select CPU_CORE_AVR
|
||||
select HAS_ATMEGA_PCINT0
|
||||
select HAS_CPP
|
||||
select HAS_PERIPH_CPUID
|
||||
select HAS_PERIPH_EEPROM
|
||||
select HAS_PERIPH_GPIO
|
||||
|
||||
@ -4,4 +4,8 @@ MODULE = atmega_common
|
||||
# add a list of subdirectories, that should also be build
|
||||
DIRS = periph avr_libc_extra
|
||||
|
||||
ifneq (,$(filter cpu_atmega_common_cxx,$(USEMODULE)))
|
||||
DIRS += cxx
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
||||
@ -34,3 +34,8 @@ endif
|
||||
ifneq (,$(filter atmega_pcint3,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += atmega_pcint3
|
||||
endif
|
||||
|
||||
# static C++ constructors need guards for thread safe initialization
|
||||
ifneq (,$(filter cpp,$(FEATURES_USED)))
|
||||
USEMODULE += cxx_ctor_guards
|
||||
endif
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
FEATURES_PROVIDED += arch_8bit
|
||||
FEATURES_PROVIDED += arch_avr8
|
||||
FEATURES_PROVIDED += atmega_pcint0
|
||||
FEATURES_PROVIDED += cpp
|
||||
FEATURES_PROVIDED += periph_cpuid
|
||||
FEATURES_PROVIDED += periph_eeprom
|
||||
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
|
||||
|
||||
@ -28,7 +28,8 @@ DEVELHELP ?= 1
|
||||
QUIET ?= 1
|
||||
|
||||
# Features required
|
||||
FEATURES_REQUIRED += cpp
|
||||
FEATURES_REQUIRED += cpp # basic C++ support
|
||||
FEATURES_REQUIRED += libstdcpp # libstdc++ support (for #include <cstdio>)
|
||||
|
||||
# If you want to add some extra flags when compile c++ files, add these flags
|
||||
# to CXXEXFLAGS variable
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
FEATURES_REQUIRED += cpp
|
||||
FEATURES_REQUIRED += libstdcpp
|
||||
|
||||
USEMODULE += utensor-ops
|
||||
USEMODULE += utensor-util
|
||||
|
||||
1
sys/cxx_ctor_guards/Makefile
Normal file
1
sys/cxx_ctor_guards/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
82
sys/cxx_ctor_guards/cxa_guard.c
Normal file
82
sys/cxx_ctor_guards/cxa_guard.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_cxx_ctor_guards
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of the C++ ctor guards
|
||||
*
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
|
||||
*/
|
||||
|
||||
#include "test_utils/expect.h"
|
||||
#include "rmutex.h"
|
||||
|
||||
#ifdef CXX_CTOR_GUARDS_CUSTOM_TYPE
|
||||
/* Some architectures (such as ARM) have custom types for __guard in their
|
||||
* ABI defined. To support such cases, a custom header can be provided and
|
||||
* `CXX_CTOR_GUARDS_CUSTOM_TYPE` can be defined */
|
||||
#include "cxx_ctor_guards_arch.h"
|
||||
#else
|
||||
/* The ABI for"generic" CPUs defines __guard as follows:
|
||||
* (see "libstdc++-v3/config/cpu/generic/cxxabi_tweaks.h" in GCC source) */
|
||||
__extension__ typedef int __guard __attribute__((mode(__DI__)));
|
||||
/* Above is just a fancy version of `typedef int64_t __guard`. But let's stick
|
||||
* with the official type definition */
|
||||
#endif
|
||||
|
||||
#define GUARD_DONE 0x01
|
||||
#define GUARD_PENDING 0x02
|
||||
|
||||
/* A recursive mutex is needed, as the initialization of a static class could
|
||||
* require calling ctors of members of that class. With a regular mutex, this
|
||||
* would result in a deadlock.
|
||||
*/
|
||||
static rmutex_t cxa_rmutex = RMUTEX_INIT;
|
||||
|
||||
int __cxa_guard_acquire(__guard *g)
|
||||
{
|
||||
uint8_t *guard = (uint8_t *)g;
|
||||
/* Optimize for the case that the instance is already initialized by
|
||||
* doing a lock-free check. */
|
||||
if (__atomic_load_1(guard, __ATOMIC_SEQ_CST) & GUARD_DONE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rmutex_lock(&cxa_rmutex);
|
||||
/* Check again (this time protected by the rmutex) for the instance being
|
||||
* already initialized */
|
||||
if (*guard & GUARD_DONE) {
|
||||
rmutex_unlock(&cxa_rmutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*guard & GUARD_PENDING) {
|
||||
/* Recursive initialization of the *same* instance --> bug */
|
||||
expect(0);
|
||||
}
|
||||
|
||||
*guard = GUARD_PENDING;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __cxa_guard_release(__guard *g)
|
||||
{
|
||||
uint8_t *guard = (uint8_t *)g;
|
||||
*guard = GUARD_DONE;
|
||||
rmutex_unlock(&cxa_rmutex);
|
||||
}
|
||||
|
||||
void __cxa_guard_abort(__guard *g)
|
||||
{
|
||||
uint8_t *guard = (uint8_t *)g;
|
||||
*guard = 0;
|
||||
rmutex_unlock(&cxa_rmutex);
|
||||
}
|
||||
51
sys/cxx_ctor_guards/doc.txt
Normal file
51
sys/cxx_ctor_guards/doc.txt
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
@defgroup sys_cxx_ctor_guards C++ constructor guards for static instances
|
||||
@ingroup sys
|
||||
@brief C++ constructor guards for thread-safe initialization of static
|
||||
instances
|
||||
|
||||
@warning This implementation is likely only compatible with `g++`
|
||||
|
||||
# Introduction
|
||||
|
||||
The libstd++ ABI requires implementations of the following functions:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
|
||||
int __cxa_guard_acquire(__guard *g);
|
||||
void __cxa_guard_release(__guard *g);
|
||||
void __cxa_guard_abort(__guard *g);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These functions are not intended to be ever used by the programmer, instead
|
||||
the C++ compiler will emit code calling them if statically allocated class
|
||||
instances are used. In a multi-threaded environment special care needs to be
|
||||
taken to prevent race conditions while initializing and using such instances.
|
||||
This modules provides them.
|
||||
|
||||
# Usage
|
||||
|
||||
This module is intended to be used by platforms that want to provide C++
|
||||
support, but the used standard C++ library does not provide these guards. In
|
||||
this case, adding this module will do the trick. The programmer / user should
|
||||
never interact with any of the functions.
|
||||
|
||||
Note that on some platforms the type `__guard` is defined differently from the
|
||||
"generic" definition, most notably ARM. For those platforms a header named
|
||||
`cxx_ctor_guards_arch.h` needs to be created containing the correct `typedef`
|
||||
and the preprocessor macro `CXX_CTOR_GUARDS_CUSTOM_TYPE` needs to be defined.
|
||||
|
||||
# Implementation
|
||||
|
||||
This implementation provides the C++ ctor guards as defined by the libstd++ ABI
|
||||
used in g++. It will likely not be compatible with other implementations of
|
||||
libstd++.
|
||||
|
||||
The libstd++ ABI expects the functions to be implemented as C functions. Most
|
||||
implementations will put the code into C++ files and wrap everything into an
|
||||
`extern "C" {...}`. This implementation will just use a plain C file for less
|
||||
boilerplate.
|
||||
|
||||
The implementation intentionally makes only use of a single byte of the
|
||||
`__guard` type. This should result in the implementation being usable on any
|
||||
platform, regardless of the actual size of `__guard`.
|
||||
*/
|
||||
Loading…
x
Reference in New Issue
Block a user