Mistake on this page?
Report an issue in GitHub or email us
SingletonPtr.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2019 ARM Limited
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #ifndef SINGLETONPTR_H
18 #define SINGLETONPTR_H
19 
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <new>
23 #include "platform/mbed_assert.h"
24 #include "platform/mbed_atomic.h"
25 #ifdef MBED_CONF_RTOS_PRESENT
26 #include "cmsis_os2.h"
27 #endif
28 
29 #ifdef MBED_CONF_RTOS_PRESENT
30 extern osMutexId_t singleton_mutex_id;
31 #endif
32 
33 /** \addtogroup platform-public-api */
34 /** @{*/
35 
36 /**
37  * \defgroup platform_SingletonPtr SingletonPtr class
38  * @{
39  */
40 
41 /** Lock the singleton mutex
42  *
43  * This function is typically used to provide
44  * exclusive access when initializing a
45  * global object.
46  */
47 inline static void singleton_lock(void)
48 {
49 #ifdef MBED_CONF_RTOS_PRESENT
50  if (!singleton_mutex_id) {
51  // RTOS has not booted yet so no mutex is needed
52  return;
53  }
54  osMutexAcquire(singleton_mutex_id, osWaitForever);
55 #endif
56 }
57 
58 /** Unlock the singleton mutex
59  *
60  * This function is typically used to provide
61  * exclusive access when initializing a
62  * global object.
63  */
64 inline static void singleton_unlock(void)
65 {
66 #ifdef MBED_CONF_RTOS_PRESENT
67  if (!singleton_mutex_id) {
68  // RTOS has not booted yet so no mutex is needed
69  return;
70  }
71  osMutexRelease(singleton_mutex_id);
72 #endif
73 }
74 
75 /** Utility class for creating and using a singleton
76  *
77  * @note Synchronization level: Thread safe
78  *
79  * @note: This class is lazily initialized on first use.
80  * This class has a constexpr default constructor so if it is
81  * not used as a non-local variable it will be garbage collected.
82  *
83  * @note: This class would normally be used in a static standalone
84  * context. It does not call the destructor of the wrapped object
85  * when it is destroyed, effectively ensuring linker exclusion of the
86  * destructor for static objects. If used in another context, such as
87  * a member of a normal class wanting "initialize on first-use"
88  * semantics on a member, care should be taken to call the destroy
89  * method manually if necessary.
90  *
91  * @note: If used as a sub-object of a class, that class's own
92  * constructor must be constexpr to achieve its exclusion by
93  * the linker when unused. That will require explicit
94  * initialization of its other members.
95  *
96  * @note: More detail on initialization: Formerly, SingletonPtr
97  * had no constructor, so was "zero-initialized" when non-local.
98  * So if enclosed in another class with no constructor, the whole
99  * thing would be zero-initialized, and linker-excludable.
100  * Having no constructor meant SingletonPtr was not constexpr,
101  * which limited applicability in other contexts. With its new
102  * constexpr constructor, it is now "constant-initialized" when
103  * non-local. This achieves the same effect as a standalone
104  * non-local object, but as a sub-object linker exclusion is
105  * now only achieved if the outer object is itself using a
106  * constexpr constructor to get constant-initialization.
107  * Otherwise, the outer object will be neither zero-initialized
108  * nor constant-initialized, so will be "dynamic-initialized",
109  * and likely to be left in by the linker.
110  */
111 template <class T>
112 struct SingletonPtr {
113 
114  // Initializers are required to make default constructor constexpr
115  // This adds no overhead as a static object - the compiler and linker can
116  // figure out that we are effectively zero-init, and either place us in
117  // ".bss", or exclude us if unused.
118  constexpr SingletonPtr() noexcept : _ptr(), _data() { }
119 
120  /** Get a pointer to the underlying singleton
121  *
122  * @returns
123  * A pointer to the singleton
124  */
125  T *get() const
126  {
127  T *p = core_util_atomic_load(&_ptr);
128  if (p == NULL) {
129  singleton_lock();
130  p = _ptr;
131  if (p == NULL) {
132  p = new (_data) T();
133  core_util_atomic_store(&_ptr, p);
134  }
136  }
137  // _ptr was not zero initialized or was
138  // corrupted if this assert is hit
139  MBED_ASSERT(p == reinterpret_cast<T *>(&_data));
140  return p;
141  }
142 
143  /** Get a pointer to the underlying singleton
144  *
145  * @returns
146  * A pointer to the singleton
147  */
148  T *operator->() const
149  {
150  return get();
151  }
152 
153  /** Get a reference to the underlying singleton
154  *
155  * @returns
156  * A reference to the singleton
157  */
158  T &operator*() const
159  {
160  return *get();
161  }
162 
163  /** Get a pointer to the underlying singleton
164  *
165  * Gets a pointer without initialization - can be
166  * used as an optimization when it is known that
167  * initialization must have already occurred.
168  *
169  * @returns
170  * A pointer to the singleton, or NULL if not
171  * initialized.
172  */
173  T *get_no_init() const
174  {
175  return _ptr;
176  }
177 
178  /** Destroy the underlying singleton
179  *
180  * The underlying singleton is never automatically destroyed;
181  * this is a potential optimization to avoid destructors
182  * being pulled into an embedded image on the exit path,
183  * which should never occur. The destructor can be
184  * manually invoked via this call.
185  *
186  * Unlike construction, this is not thread-safe. After this call,
187  * no further operations on the object are permitted.
188  *
189  * Is a no-op if the object has not been constructed.
190  */
191  void destroy()
192  {
193  if (_ptr) {
194  _ptr->~T();
195  }
196  }
197 
198  mutable T *_ptr;
199 #if __cplusplus >= 201103L
200  // Align data appropriately
201  alignas(T) mutable char _data[sizeof(T)];
202 #else
203  // Force data to be 8 byte aligned
204  mutable uint64_t _data[(sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t)];
205 #endif
206 };
207 
208 #endif
209 /**@}*/
210 
211 /**@}*/
static void singleton_lock(void)
Lock the singleton mutex.
Definition: SingletonPtr.h:47
T * operator->() const
Get a pointer to the underlying singleton.
Definition: SingletonPtr.h:148
Utility class for creating and using a singleton.
Definition: SingletonPtr.h:112
static void singleton_unlock(void)
Unlock the singleton mutex.
Definition: SingletonPtr.h:64
#define MBED_ASSERT(expr)
MBED_ASSERT Declare runtime assertions: results in runtime error if condition is false.
Definition: mbed_assert.h:65
T & operator*() const
Get a reference to the underlying singleton.
Definition: SingletonPtr.h:158
void destroy()
Destroy the underlying singleton.
Definition: SingletonPtr.h:191
T * get_no_init() const
Get a pointer to the underlying singleton.
Definition: SingletonPtr.h:173
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.