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.
pull/2158/head
Russ Butler 2016-06-27 18:55:07 -05:00
parent d4627176da
commit 348b32c3c6
10 changed files with 149 additions and 26 deletions

View File

@ -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<PlatformMutex> _mutex;
};
} // namespace mbed

View File

@ -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<PlatformMutex> _mutex;
FileBase *_next;
const char * const _name;

View File

@ -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<PlatformMutex> _mutex;
};
} // namespace mbed

103
hal/api/SingletonPtr.h Normal file
View File

@ -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 <stdint.h>
#include <new>
#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 <class T>
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

View File

@ -22,7 +22,7 @@
namespace mbed {
PlatformMutex AnalogIn::_mutex;
SingletonPtr<PlatformMutex> AnalogIn::_mutex;
};

View File

@ -18,12 +18,12 @@
namespace mbed {
FileBase *FileBase::_head = NULL;
PlatformMutex FileBase::_mutex;
SingletonPtr<PlatformMutex> 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;
}

View File

@ -20,7 +20,7 @@
namespace mbed {
I2C *I2C::_owner = NULL;
PlatformMutex I2C::_mutex;
SingletonPtr<PlatformMutex> 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

View File

@ -21,6 +21,7 @@
#include "toolchain.h"
#include "semihost_api.h"
#include "mbed_interface.h"
#include "SingletonPtr.h"
#if DEVICE_STDIO_MESSAGES
#include <stdio.h>
#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<PlatformMutex> 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;

View File

@ -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();
}

View File

@ -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();
}