Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SingletonPtr.h Source File

SingletonPtr.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2019 ARM Limited
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #ifndef SINGLETONPTR_H
00018 #define SINGLETONPTR_H
00019 
00020 #include <stdlib.h>
00021 #include <stdint.h>
00022 #include <new>
00023 #include "platform/mbed_assert.h"
00024 #include "platform/mbed_atomic.h"
00025 #ifdef MBED_CONF_RTOS_PRESENT
00026 #include "cmsis_os2.h"
00027 #endif
00028 
00029 #ifdef MBED_CONF_RTOS_PRESENT
00030 extern osMutexId_t singleton_mutex_id;
00031 #endif
00032 
00033 /** \addtogroup platform-public-api */
00034 /** @{*/
00035 
00036 /**
00037  * \defgroup platform_SingletonPtr SingletonPtr class
00038  * @{
00039  */
00040 
00041 /** Lock the singleton mutex
00042  *
00043  * This function is typically used to provide
00044  * exclusive access when initializing a
00045  * global object.
00046  */
00047 inline static void singleton_lock(void)
00048 {
00049 #ifdef MBED_CONF_RTOS_PRESENT
00050     if (!singleton_mutex_id) {
00051         // RTOS has not booted yet so no mutex is needed
00052         return;
00053     }
00054     osMutexAcquire(singleton_mutex_id, osWaitForever);
00055 #endif
00056 }
00057 
00058 /** Unlock the singleton mutex
00059  *
00060  * This function is typically used to provide
00061  * exclusive access when initializing a
00062  * global object.
00063  */
00064 inline static void singleton_unlock(void)
00065 {
00066 #ifdef MBED_CONF_RTOS_PRESENT
00067     if (!singleton_mutex_id) {
00068         // RTOS has not booted yet so no mutex is needed
00069         return;
00070     }
00071     osMutexRelease(singleton_mutex_id);
00072 #endif
00073 }
00074 
00075 /** Utility class for creating and using a singleton
00076  *
00077  * @note Synchronization level: Thread safe
00078  *
00079  * @note: This class is lazily initialized on first use.
00080  * This class has a constexpr default constructor so if it is
00081  * not used as a non-local variable it will be garbage collected.
00082  *
00083  * @note: This class would normally be used in a static standalone
00084  * context. It does not call the destructor of the wrapped object
00085  * when it is destroyed, effectively ensuring linker exclusion of the
00086  * destructor for static objects. If used in another context, such as
00087  * a member of a normal class wanting "initialize on first-use"
00088  * semantics on a member, care should be taken to call the destroy
00089  * method manually if necessary.
00090  *
00091  * @note: If used as a sub-object of a class, that class's own
00092  * constructor must be constexpr to achieve its exclusion by
00093  * the linker when unused. That will require explicit
00094  * initialization of its other members.
00095  *
00096  * @note: More detail on initialization: Formerly, SingletonPtr
00097  * had no constructor, so was "zero-initialized" when non-local.
00098  * So if enclosed in another class with no constructor, the whole
00099  * thing would be zero-initialized, and linker-excludable.
00100  * Having no constructor meant SingletonPtr was not constexpr,
00101  * which limited applicability in other contexts. With its new
00102  * constexpr constructor, it is now "constant-initialized" when
00103  * non-local. This achieves the same effect as a standalone
00104  * non-local object, but as a sub-object linker exclusion is
00105  * now only achieved if the outer object is itself using a
00106  * constexpr constructor to get constant-initialization.
00107  * Otherwise, the outer object will be neither zero-initialized
00108  * nor constant-initialized, so will be "dynamic-initialized",
00109  * and likely to be left in by the linker.
00110  */
00111 template <class T>
00112 struct SingletonPtr {
00113 
00114     // Initializers are required to make default constructor constexpr
00115     // This adds no overhead as a static object - the compiler and linker can
00116     // figure out that we are effectively zero-init, and either place us in
00117     // ".bss", or exclude us if unused.
00118     constexpr SingletonPtr() noexcept : _ptr(), _data() { }
00119 
00120     /** Get a pointer to the underlying singleton
00121      *
00122      * @returns
00123      *   A pointer to the singleton
00124      */
00125     T *get() const
00126     {
00127         T *p = core_util_atomic_load (&_ptr);
00128         if (p == NULL) {
00129             singleton_lock();
00130             p = _ptr;
00131             if (p == NULL) {
00132                 p = new (_data) T();
00133                 core_util_atomic_store (&_ptr, p);
00134             }
00135             singleton_unlock();
00136         }
00137         // _ptr was not zero initialized or was
00138         // corrupted if this assert is hit
00139         MBED_ASSERT(p == reinterpret_cast<T *>(&_data));
00140         return p;
00141     }
00142 
00143     /** Get a pointer to the underlying singleton
00144      *
00145      * @returns
00146      *   A pointer to the singleton
00147      */
00148     T *operator->() const
00149     {
00150         return get();
00151     }
00152 
00153     /** Get a reference to the underlying singleton
00154      *
00155      * @returns
00156      *   A reference to the singleton
00157      */
00158     T &operator*() const
00159     {
00160         return *get();
00161     }
00162 
00163     /** Get a pointer to the underlying singleton
00164      *
00165      * Gets a pointer without initialization - can be
00166      * used as an optimization when it is known that
00167      * initialization must have already occurred.
00168      *
00169      * @returns
00170      *   A pointer to the singleton, or NULL if not
00171      *   initialized.
00172      */
00173     T *get_no_init() const
00174     {
00175         return _ptr;
00176     }
00177 
00178     /** Destroy the underlying singleton
00179      *
00180      * The underlying singleton is never automatically destroyed;
00181      * this is a potential optimization to avoid destructors
00182      * being pulled into an embedded image on the exit path,
00183      * which should never occur. The destructor can be
00184      * manually invoked via this call.
00185      *
00186      * Unlike construction, this is not thread-safe. After this call,
00187      * no further operations on the object are permitted.
00188      *
00189      * Is a no-op if the object has not been constructed.
00190      */
00191     void destroy()
00192     {
00193         if (_ptr) {
00194             _ptr->~T();
00195         }
00196     }
00197 
00198     mutable T *_ptr;
00199 #if __cplusplus >= 201103L && !defined __CC_ARM
00200     // Align data appropriately (ARM Compiler 5 does not support alignas in C++11 mode)
00201     alignas(T) mutable char _data[sizeof(T)];
00202 #else
00203     // Force data to be 8 byte aligned
00204     mutable uint64_t _data[(sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t)];
00205 #endif
00206 };
00207 
00208 #endif
00209 /**@}*/
00210 
00211 /**@}*/