1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/cxx_ctor_guards/cxa_guard.c
Marian Buschsieweke 6520db8ed9
sys/cxx_ctor_guards: Add guard for c++ ctors
For thread-safe calling of C++ constructs of statically allocated class
instances some platform support code is needed. This commit ads one
implementation compatible with g++.
2020-07-23 20:24:47 +02:00

83 lines
2.3 KiB
C

/*
* 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);
}