Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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 /**@}*/
Generated on Tue Jul 12 2022 13:54:50 by
