Merge pull request #9530 from kjbracey-arm/atomic_singletonptr

Use atomics for double-checked locks (SingletonPtr + __cxa_guard)
pull/9021/head
Cruz Monrreal 2019-01-31 10:22:39 -06:00 committed by GitHub
commit 0fb2870cfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 16 deletions

View File

@ -28,6 +28,7 @@
#include <stdint.h>
#include <new>
#include "platform/mbed_assert.h"
#include "platform/mbed_critical.h"
#ifdef MBED_CONF_RTOS_PRESENT
#include "cmsis_os2.h"
#endif
@ -92,17 +93,20 @@ struct SingletonPtr {
*/
T *get() const
{
if (NULL == _ptr) {
T *p = static_cast<T *>(core_util_atomic_load_ptr(&_ptr));
if (p == NULL) {
singleton_lock();
if (NULL == _ptr) {
_ptr = new (_data) T();
p = static_cast<T *>(_ptr);
if (p == NULL) {
p = new (_data) T();
core_util_atomic_store_ptr(&_ptr, p);
}
singleton_unlock();
}
// _ptr was not zero initialized or was
// corrupted if this assert is hit
MBED_ASSERT(_ptr == (T *)&_data);
return _ptr;
MBED_ASSERT(p == reinterpret_cast<T *>(&_data));
return p;
}
/** Get a pointer to the underlying singleton
@ -126,7 +130,7 @@ struct SingletonPtr {
}
// This is zero initialized when in global scope
mutable T *_ptr;
mutable void *_ptr;
#if __cplusplus >= 201103L
// Align data appropriately
alignas(T) mutable char _data[sizeof(T)];

View File

@ -1417,7 +1417,7 @@ extern "C" void __env_unlock(struct _reent *_r)
#endif
#if defined (__GNUC__) || defined(__CC_ARM) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
#if defined (__GNUC__) || defined (__ARMCC_VERSION)
#define CXA_GUARD_INIT_DONE (1 << 0)
#define CXA_GUARD_INIT_IN_PROGRESS (1 << 1)
@ -1426,38 +1426,41 @@ extern "C" void __env_unlock(struct _reent *_r)
extern "C" int __cxa_guard_acquire(int *guard_object_p)
{
uint8_t *guard_object = (uint8_t *)guard_object_p;
if (CXA_GUARD_INIT_DONE == (*guard_object & CXA_GUARD_MASK)) {
if ((core_util_atomic_load_u8(guard_object) & CXA_GUARD_MASK) == CXA_GUARD_INIT_DONE) {
return 0;
}
singleton_lock();
if (CXA_GUARD_INIT_DONE == (*guard_object & CXA_GUARD_MASK)) {
uint8_t guard = *guard_object;
if ((guard & CXA_GUARD_MASK) == CXA_GUARD_INIT_DONE) {
singleton_unlock();
return 0;
}
MBED_ASSERT(0 == (*guard_object & CXA_GUARD_MASK));
*guard_object = *guard_object | CXA_GUARD_INIT_IN_PROGRESS;
MBED_ASSERT((guard & CXA_GUARD_MASK) == 0);
core_util_atomic_store_u8(guard_object, guard | CXA_GUARD_INIT_IN_PROGRESS);
return 1;
}
extern "C" void __cxa_guard_release(int *guard_object_p)
{
uint8_t *guard_object = (uint8_t *)guard_object_p;
MBED_ASSERT(CXA_GUARD_INIT_IN_PROGRESS == (*guard_object & CXA_GUARD_MASK));
*guard_object = (*guard_object & ~CXA_GUARD_MASK) | CXA_GUARD_INIT_DONE;
uint8_t guard = *guard_object;
MBED_ASSERT((guard & CXA_GUARD_MASK) == CXA_GUARD_INIT_IN_PROGRESS);
core_util_atomic_store_u8(guard_object, (guard & ~CXA_GUARD_MASK) | CXA_GUARD_INIT_DONE);
singleton_unlock();
}
extern "C" void __cxa_guard_abort(int *guard_object_p)
{
uint8_t *guard_object = (uint8_t *)guard_object_p;
MBED_ASSERT(CXA_GUARD_INIT_IN_PROGRESS == (*guard_object & CXA_GUARD_MASK));
*guard_object = *guard_object & ~CXA_GUARD_INIT_IN_PROGRESS;
uint8_t guard = *guard_object;
MBED_ASSERT((guard & CXA_GUARD_MASK) == CXA_GUARD_INIT_IN_PROGRESS);
core_util_atomic_store_u8(guard_object, guard & ~CXA_GUARD_INIT_IN_PROGRESS);
singleton_unlock();
}
#endif
#if defined(MBED_MEM_TRACING_ENABLED) && (defined(__CC_ARM) || defined(__ICCARM__) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)))
#if defined(MBED_MEM_TRACING_ENABLED) && (defined(__ARMCC_VERSION) || defined(__ICCARM__))
// If the memory tracing is enabled, the wrappers in mbed_alloc_wrappers.cpp
// provide the implementation for these. Note: this needs to use the wrappers