mbed-os/platform/SingletonPtr.h

147 lines
3.5 KiB
C++

/** \addtogroup platform */
/** @{*/
/**
* \defgroup platform_SingletonPtr SingletonPtr class
* @{
*/
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SINGLETONPTR_H
#define SINGLETONPTR_H
#include <stdlib.h>
#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
#ifdef MBED_CONF_RTOS_PRESENT
extern osMutexId_t singleton_mutex_id;
#endif
/** Lock the singleton mutex
*
* This function is typically used to provide
* exclusive access when initializing a
* global object.
*/
inline static void singleton_lock(void)
{
#ifdef MBED_CONF_RTOS_PRESENT
if (!singleton_mutex_id) {
// RTOS has not booted yet so no mutex is needed
return;
}
osMutexAcquire(singleton_mutex_id, osWaitForever);
#endif
}
/** Unlock the singleton mutex
*
* This function is typically used to provide
* exclusive access when initializing a
* global object.
*/
inline static void singleton_unlock(void)
{
#ifdef MBED_CONF_RTOS_PRESENT
if (!singleton_mutex_id) {
// RTOS has not booted yet so no mutex is needed
return;
}
osMutexRelease(singleton_mutex_id);
#endif
}
/** Utility class for creating an using a singleton
*
* @note Synchronization level: Thread safe
*
* @note: This class must only be used in a static context -
* this class must never be allocated or created on the
* stack.
*
* @note: This class is lazily initialized on first use.
* This class is a POD type so if it is not used it will
* be garbage collected.
*/
template <class T>
struct SingletonPtr {
/** Get a pointer to the underlying singleton
*
* @returns
* A pointer to the singleton
*/
T *get() const
{
T *p = static_cast<T *>(core_util_atomic_load_ptr(&_ptr));
if (p == NULL) {
singleton_lock();
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(p == reinterpret_cast<T *>(&_data));
return p;
}
/** Get a pointer to the underlying singleton
*
* @returns
* A pointer to the singleton
*/
T *operator->() const
{
return get();
}
/** Get a reference to the underlying singleton
*
* @returns
* A reference to the singleton
*/
T &operator*() const
{
return *get();
}
// This is zero initialized when in global scope
mutable void *_ptr;
#if __cplusplus >= 201103L
// Align data appropriately
alignas(T) mutable char _data[sizeof(T)];
#else
// Force data to be 8 byte aligned
mutable uint64_t _data[(sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t)];
#endif
};
#endif
/**@}*/
/**@}*/