From 348b32c3c614567c2388ac12831b3513a4be7205 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Mon, 27 Jun 2016 18:55:07 -0500 Subject: [PATCH] Create singleton class and update code to use it Create the wrapper class SingletonPtr. This provides a safe way to declare and use singletons. This class allows both the lazy initialization of a singleton, and allows the singleton to be garbage collected by the linker if it is never referenced. This patch also updates the HAL to use SingletonPtr when declaring singleton mutexes. --- hal/api/AnalogIn.h | 7 +- hal/api/FileBase.h | 3 +- hal/api/I2C.h | 3 +- hal/api/SingletonPtr.h | 103 ++++++++++++++++++++++++++ hal/common/AnalogIn.cpp | 2 +- hal/common/FileBase.cpp | 22 +++--- hal/common/I2C.cpp | 6 +- hal/common/retarget.cpp | 13 ++-- rtos/rtx/TARGET_CORTEX_A/RTX_CM_lib.h | 8 ++ rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 8 ++ 10 files changed, 149 insertions(+), 26 deletions(-) create mode 100644 hal/api/SingletonPtr.h diff --git a/hal/api/AnalogIn.h b/hal/api/AnalogIn.h index b30fd610a9..ba35ddda6c 100644 --- a/hal/api/AnalogIn.h +++ b/hal/api/AnalogIn.h @@ -21,6 +21,7 @@ #if DEVICE_ANALOGIN #include "analogin_api.h" +#include "SingletonPtr.h" namespace mbed { @@ -110,15 +111,15 @@ public: protected: virtual void lock() { - _mutex.lock(); + _mutex->lock(); } virtual void unlock() { - _mutex.unlock(); + _mutex->unlock(); } analogin_t _adc; - static PlatformMutex _mutex; + static SingletonPtr _mutex; }; } // namespace mbed diff --git a/hal/api/FileBase.h b/hal/api/FileBase.h index e8758686af..2ee09956ea 100644 --- a/hal/api/FileBase.h +++ b/hal/api/FileBase.h @@ -41,6 +41,7 @@ typedef long off_t; #endif #include "platform.h" +#include "SingletonPtr.h" namespace mbed { @@ -65,7 +66,7 @@ public: /* disallow copy constructor and assignment operators */ private: static FileBase *_head; - static PlatformMutex _mutex; + static SingletonPtr _mutex; FileBase *_next; const char * const _name; diff --git a/hal/api/I2C.h b/hal/api/I2C.h index 38fcdbc3fd..ada9647648 100644 --- a/hal/api/I2C.h +++ b/hal/api/I2C.h @@ -21,6 +21,7 @@ #if DEVICE_I2C #include "i2c_api.h" +#include "SingletonPtr.h" #if DEVICE_I2C_ASYNCH #include "CThunk.h" @@ -181,7 +182,7 @@ protected: i2c_t _i2c; static I2C *_owner; int _hz; - static PlatformMutex _mutex; + static SingletonPtr _mutex; }; } // namespace mbed diff --git a/hal/api/SingletonPtr.h b/hal/api/SingletonPtr.h new file mode 100644 index 0000000000..998aff8245 --- /dev/null +++ b/hal/api/SingletonPtr.h @@ -0,0 +1,103 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * 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 +#include +#include "mbed_assert.h" +#ifdef MBED_CONF_RTOS_PRESENT +#include "cmsis_os.h" +#endif + +#ifdef MBED_CONF_RTOS_PRESENT +extern osMutexId 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 + osMutexWait(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 + 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 +struct SingletonPtr { + + /** Get a pointer to the underlying singleton + * + * @returns + * A pointer to the singleton + */ + T* get() { + if (NULL == _ptr) { + singleton_lock(); + _ptr = new (_data) T; + singleton_unlock(); + } + // _ptr was not zero initialized or was + // corrupted if this assert is hit + MBED_ASSERT(_ptr == (T *)&_data); + return _ptr; + } + + /** Get a pointer to the underlying singleton + * + * @returns + * A pointer to the singleton + */ + T* operator->() { + return get(); + } + + // This is zero initialized when in global scope + T *_ptr; + // Force data to be 4 byte aligned + uint32_t _data[(sizeof(T) + sizeof(uint32_t) - 1) / sizeof(uint32_t)]; +}; + +#endif diff --git a/hal/common/AnalogIn.cpp b/hal/common/AnalogIn.cpp index bbb044efb3..96343362ed 100644 --- a/hal/common/AnalogIn.cpp +++ b/hal/common/AnalogIn.cpp @@ -22,7 +22,7 @@ namespace mbed { -PlatformMutex AnalogIn::_mutex; +SingletonPtr AnalogIn::_mutex; }; diff --git a/hal/common/FileBase.cpp b/hal/common/FileBase.cpp index 46f6c27210..3e76c0e391 100644 --- a/hal/common/FileBase.cpp +++ b/hal/common/FileBase.cpp @@ -18,12 +18,12 @@ namespace mbed { FileBase *FileBase::_head = NULL; -PlatformMutex FileBase::_mutex; +SingletonPtr FileBase::_mutex; FileBase::FileBase(const char *name, PathType t) : _next(NULL), _name(name), _path_type(t) { - _mutex.lock(); + _mutex->lock(); if (name != NULL) { // put this object at head of the list _next = _head; @@ -31,11 +31,11 @@ FileBase::FileBase(const char *name, PathType t) : _next(NULL), } else { _next = NULL; } - _mutex.unlock(); + _mutex->unlock(); } FileBase::~FileBase() { - _mutex.lock(); + _mutex->lock(); if (_name != NULL) { // remove this object from the list if (_head == this) { // first in the list, so just drop me @@ -48,38 +48,38 @@ FileBase::~FileBase() { p->_next = _next; } } - _mutex.unlock(); + _mutex->unlock(); } FileBase *FileBase::lookup(const char *name, unsigned int len) { - _mutex.lock(); + _mutex->lock(); FileBase *p = _head; while (p != NULL) { /* Check that p->_name matches name and is the correct length */ if (p->_name != NULL && std::strncmp(p->_name, name, len) == 0 && std::strlen(p->_name) == len) { - _mutex.unlock(); + _mutex->unlock(); return p; } p = p->_next; } - _mutex.unlock(); + _mutex->unlock(); return NULL; } FileBase *FileBase::get(int n) { - _mutex.lock(); + _mutex->lock(); FileBase *p = _head; int m = 0; while (p != NULL) { if (m == n) { - _mutex.unlock(); + _mutex->unlock(); return p; } m++; p = p->_next; } - _mutex.unlock(); + _mutex->unlock(); return NULL; } diff --git a/hal/common/I2C.cpp b/hal/common/I2C.cpp index 79560889a5..645be71503 100644 --- a/hal/common/I2C.cpp +++ b/hal/common/I2C.cpp @@ -20,7 +20,7 @@ namespace mbed { I2C *I2C::_owner = NULL; -PlatformMutex I2C::_mutex; +SingletonPtr I2C::_mutex; I2C::I2C(PinName sda, PinName scl) : #if DEVICE_I2C_ASYNCH @@ -113,11 +113,11 @@ void I2C::stop(void) { } void I2C::lock() { - _mutex.lock(); + _mutex->lock(); } void I2C::unlock() { - _mutex.unlock(); + _mutex->unlock(); } #if DEVICE_I2C_ASYNCH diff --git a/hal/common/retarget.cpp b/hal/common/retarget.cpp index fc0ed6286c..bc7772940f 100644 --- a/hal/common/retarget.cpp +++ b/hal/common/retarget.cpp @@ -21,6 +21,7 @@ #include "toolchain.h" #include "semihost_api.h" #include "mbed_interface.h" +#include "SingletonPtr.h" #if DEVICE_STDIO_MESSAGES #include #endif @@ -72,17 +73,17 @@ extern const char __stderr_name[] = "/stderr"; * (or rather index+3, as filehandles 0-2 are stdin/out/err). */ static FileHandle *filehandles[OPEN_MAX]; -static PlatformMutex filehandle_mutex; +static SingletonPtr filehandle_mutex; FileHandle::~FileHandle() { - filehandle_mutex.lock(); + filehandle_mutex->lock(); /* Remove all open filehandles for this */ for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { if (filehandles[fh_i] == this) { filehandles[fh_i] = NULL; } } - filehandle_mutex.unlock(); + filehandle_mutex->unlock(); } #if DEVICE_SERIAL @@ -162,17 +163,17 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) { #endif // find the first empty slot in filehandles - filehandle_mutex.lock(); + filehandle_mutex->lock(); unsigned int fh_i; for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { if (filehandles[fh_i] == NULL) break; } if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) { - filehandle_mutex.unlock(); + filehandle_mutex->unlock(); return -1; } filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED; - filehandle_mutex.unlock(); + filehandle_mutex->unlock(); FileHandle *res; diff --git a/rtos/rtx/TARGET_CORTEX_A/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_A/RTX_CM_lib.h index 51e13a649a..5aef981767 100644 --- a/rtos/rtx/TARGET_CORTEX_A/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_A/RTX_CM_lib.h @@ -225,6 +225,10 @@ uint32_t os_tmr = 0; uint32_t const *m_tmr = NULL; uint16_t const mp_tmr_size = 0; +/* singleton mutex */ +osMutexId singleton_mutex_id; +osMutexDef(singleton_mutex); + #if defined (__CC_ARM) && !defined (__MICROLIB) /* A memory space for arm standard library. */ static uint32_t std_libspace[OS_TASK_CNT][96/4]; @@ -434,6 +438,7 @@ void $Sub$$__cpp_initialize__aeabi_(void) void pre_main() { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); $Super$$__cpp_initialize__aeabi_(); main(); } @@ -447,6 +452,7 @@ int main(void); void pre_main (void) { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); __rt_lib_init((unsigned)armcc_heap_base, (unsigned)armcc_heap_top); main(); } @@ -484,6 +490,7 @@ extern void __libc_init_array (void); extern int main(int argc, char **argv); void pre_main(void) { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); atexit(__libc_fini_array); __libc_init_array(); main(0, NULL); @@ -516,6 +523,7 @@ extern int main(void); static uint8_t low_level_init_needed; void pre_main(void) { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); if (low_level_init_needed) { __iar_dynamic_initialization(); } diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h index d2fa4af4f1..f9052831e1 100755 --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -187,6 +187,10 @@ uint32_t os_tmr = 0U; uint32_t const *m_tmr = NULL; uint16_t const mp_tmr_size = 0U; +/* singleton mutex */ +osMutexId singleton_mutex_id; +osMutexDef(singleton_mutex); + #if defined (__CC_ARM) && !defined (__MICROLIB) /* A memory space for arm standard library. */ static uint32_t std_libspace[OS_TASK_CNT][96/4]; @@ -585,6 +589,7 @@ void $Sub$$__cpp_initialize__aeabi_(void) void pre_main() { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); $Super$$__cpp_initialize__aeabi_(); main(); } @@ -598,6 +603,7 @@ int main(void); void pre_main (void) { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); __rt_lib_init((unsigned)armcc_heap_base, (unsigned)armcc_heap_top); main(); } @@ -664,6 +670,7 @@ extern void __libc_init_array (void); extern int main(int argc, char **argv); void pre_main(void) { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); malloc_mutex_id = osMutexCreate(osMutex(malloc_mutex)); env_mutex_id = osMutexCreate(osMutex(env_mutex)); atexit(__libc_fini_array); @@ -725,6 +732,7 @@ extern void exit(int arg); static uint8_t low_level_init_needed; void pre_main(void) { + singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); if (low_level_init_needed) { __iar_dynamic_initialization(); }