Skip to content

Commit 4106c64

Browse files
committed
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.
1 parent 8553723 commit 4106c64

File tree

10 files changed

+148
-26
lines changed

10 files changed

+148
-26
lines changed

hal/api/AnalogIn.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#if DEVICE_ANALOGIN
2222

2323
#include "analogin_api.h"
24+
#include "mbed_singleton.h"
2425

2526
namespace mbed {
2627

@@ -110,15 +111,15 @@ class AnalogIn {
110111
protected:
111112

112113
virtual void lock() {
113-
_mutex.lock();
114+
_mutex->lock();
114115
}
115116

116117
virtual void unlock() {
117-
_mutex.unlock();
118+
_mutex->unlock();
118119
}
119120

120121
analogin_t _adc;
121-
static PlatformMutex _mutex;
122+
static SingletonPtr<PlatformMutex> _mutex;
122123
};
123124

124125
} // namespace mbed

hal/api/FileBase.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ typedef long off_t;
4141
#endif
4242

4343
#include "platform.h"
44+
#include "mbed_singleton.h"
4445

4546
namespace mbed {
4647

@@ -65,7 +66,7 @@ class FileBase {
6566
/* disallow copy constructor and assignment operators */
6667
private:
6768
static FileBase *_head;
68-
static PlatformMutex _mutex;
69+
static SingletonPtr<PlatformMutex> _mutex;
6970

7071
FileBase *_next;
7172
const char * const _name;

hal/api/I2C.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#if DEVICE_I2C
2222

2323
#include "i2c_api.h"
24+
#include "mbed_singleton.h"
2425

2526
#if DEVICE_I2C_ASYNCH
2627
#include "CThunk.h"
@@ -181,7 +182,7 @@ class I2C {
181182
i2c_t _i2c;
182183
static I2C *_owner;
183184
int _hz;
184-
static PlatformMutex _mutex;
185+
static SingletonPtr<PlatformMutex> _mutex;
185186
};
186187

187188
} // namespace mbed

hal/api/mbed_singleton.h

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2013 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#ifndef MBED_SINGLETON_H
17+
#define MBED_SINGLETON_H
18+
19+
#include <stdint.h>
20+
#include <new>
21+
#include "mbed_assert.h"
22+
#ifdef MBED_CONF_RTOS_PRESENT
23+
#include "cmsis_os.h"
24+
#endif
25+
26+
#ifdef MBED_CONF_RTOS_PRESENT
27+
extern osMutexId singleton_mutex_id;
28+
#endif
29+
30+
/** Lock the singleton mutex
31+
*
32+
* This function is typically used to provide
33+
* exclusive access when initializing a
34+
* global object.
35+
*/
36+
inline static void singleton_lock(void)
37+
{
38+
#ifdef MBED_CONF_RTOS_PRESENT
39+
osMutexWait(singleton_mutex_id, osWaitForever);
40+
#endif
41+
}
42+
43+
/** Unlock the singleton mutex
44+
*
45+
* This function is typically used to provide
46+
* exclusive access when initializing a
47+
* global object.
48+
*/
49+
inline static void singleton_unlock(void)
50+
{
51+
#ifdef MBED_CONF_RTOS_PRESENT
52+
osMutexRelease (singleton_mutex_id);
53+
#endif
54+
}
55+
56+
/** Utility class for creating an using a singleton
57+
*
58+
* @Note Synchronization level: Thread safe
59+
*
60+
* @Note: This class must only be used in a static context -
61+
* this class must never be allocated or created on the
62+
* stack.
63+
*
64+
* @Note: This class is lazily initialized on first use.
65+
* This class is a POD type so if it is not used it will
66+
* be garbage collected.
67+
*/
68+
template <class T>
69+
struct SingletonPtr {
70+
71+
/** Get a pointer to the underlying singleton
72+
*
73+
* @returns
74+
* A pointer to the singleton
75+
*/
76+
T* get() {
77+
if (NULL == _ptr) {
78+
singleton_lock();
79+
_ptr = new (_data) T;
80+
singleton_unlock();
81+
}
82+
// _ptr was not zero initialized or was
83+
// corrupted if this assert is hit
84+
MBED_ASSERT(_ptr == (T *)&_data);
85+
return _ptr;
86+
}
87+
88+
/** Get a pointer to the underlying singleton
89+
*
90+
* @returns
91+
* A pointer to the singleton
92+
*/
93+
T* operator->() {
94+
return get();
95+
}
96+
97+
// This is zero initialized when in global scope
98+
T *_ptr;
99+
uint32_t _data[(sizeof(T) + 3 / 4)];
100+
};
101+
102+
#endif

hal/common/AnalogIn.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
namespace mbed {
2424

25-
PlatformMutex AnalogIn::_mutex;
25+
SingletonPtr<PlatformMutex> AnalogIn::_mutex;
2626

2727
};
2828

hal/common/FileBase.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,24 @@
1818
namespace mbed {
1919

2020
FileBase *FileBase::_head = NULL;
21-
PlatformMutex FileBase::_mutex;
21+
SingletonPtr<PlatformMutex> FileBase::_mutex;
2222

2323
FileBase::FileBase(const char *name, PathType t) : _next(NULL),
2424
_name(name),
2525
_path_type(t) {
26-
_mutex.lock();
26+
_mutex->lock();
2727
if (name != NULL) {
2828
// put this object at head of the list
2929
_next = _head;
3030
_head = this;
3131
} else {
3232
_next = NULL;
3333
}
34-
_mutex.unlock();
34+
_mutex->unlock();
3535
}
3636

3737
FileBase::~FileBase() {
38-
_mutex.lock();
38+
_mutex->lock();
3939
if (_name != NULL) {
4040
// remove this object from the list
4141
if (_head == this) { // first in the list, so just drop me
@@ -48,38 +48,38 @@ FileBase::~FileBase() {
4848
p->_next = _next;
4949
}
5050
}
51-
_mutex.unlock();
51+
_mutex->unlock();
5252
}
5353

5454
FileBase *FileBase::lookup(const char *name, unsigned int len) {
55-
_mutex.lock();
55+
_mutex->lock();
5656
FileBase *p = _head;
5757
while (p != NULL) {
5858
/* Check that p->_name matches name and is the correct length */
5959
if (p->_name != NULL && std::strncmp(p->_name, name, len) == 0 && std::strlen(p->_name) == len) {
60-
_mutex.unlock();
60+
_mutex->unlock();
6161
return p;
6262
}
6363
p = p->_next;
6464
}
65-
_mutex.unlock();
65+
_mutex->unlock();
6666
return NULL;
6767
}
6868

6969
FileBase *FileBase::get(int n) {
70-
_mutex.lock();
70+
_mutex->lock();
7171
FileBase *p = _head;
7272
int m = 0;
7373
while (p != NULL) {
7474
if (m == n) {
75-
_mutex.unlock();
75+
_mutex->unlock();
7676
return p;
7777
}
7878

7979
m++;
8080
p = p->_next;
8181
}
82-
_mutex.unlock();
82+
_mutex->unlock();
8383
return NULL;
8484
}
8585

hal/common/I2C.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
namespace mbed {
2121

2222
I2C *I2C::_owner = NULL;
23-
PlatformMutex I2C::_mutex;
23+
SingletonPtr<PlatformMutex> I2C::_mutex;
2424

2525
I2C::I2C(PinName sda, PinName scl) :
2626
#if DEVICE_I2C_ASYNCH
@@ -113,11 +113,11 @@ void I2C::stop(void) {
113113
}
114114

115115
void I2C::lock() {
116-
_mutex.lock();
116+
_mutex->lock();
117117
}
118118

119119
void I2C::unlock() {
120-
_mutex.unlock();
120+
_mutex->unlock();
121121
}
122122

123123
#if DEVICE_I2C_ASYNCH

hal/common/retarget.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "toolchain.h"
2222
#include "semihost_api.h"
2323
#include "mbed_interface.h"
24+
#include "mbed_singleton.h"
2425
#if DEVICE_STDIO_MESSAGES
2526
#include <stdio.h>
2627
#endif
@@ -72,17 +73,17 @@ extern const char __stderr_name[] = "/stderr";
7273
* (or rather index+3, as filehandles 0-2 are stdin/out/err).
7374
*/
7475
static FileHandle *filehandles[OPEN_MAX];
75-
static PlatformMutex filehandle_mutex;
76+
static SingletonPtr<PlatformMutex> filehandle_mutex;
7677

7778
FileHandle::~FileHandle() {
78-
filehandle_mutex.lock();
79+
filehandle_mutex->lock();
7980
/* Remove all open filehandles for this */
8081
for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
8182
if (filehandles[fh_i] == this) {
8283
filehandles[fh_i] = NULL;
8384
}
8485
}
85-
filehandle_mutex.unlock();
86+
filehandle_mutex->unlock();
8687
}
8788

8889
#if DEVICE_SERIAL
@@ -162,17 +163,17 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
162163
#endif
163164

164165
// find the first empty slot in filehandles
165-
filehandle_mutex.lock();
166+
filehandle_mutex->lock();
166167
unsigned int fh_i;
167168
for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
168169
if (filehandles[fh_i] == NULL) break;
169170
}
170171
if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) {
171-
filehandle_mutex.unlock();
172+
filehandle_mutex->unlock();
172173
return -1;
173174
}
174175
filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED;
175-
filehandle_mutex.unlock();
176+
filehandle_mutex->unlock();
176177

177178
FileHandle *res;
178179

rtos/rtx/TARGET_CORTEX_A/RTX_CM_lib.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ uint32_t os_tmr = 0;
225225
uint32_t const *m_tmr = NULL;
226226
uint16_t const mp_tmr_size = 0;
227227

228+
/* singleton mutex */
229+
osMutexId singleton_mutex_id;
230+
osMutexDef(singleton_mutex);
231+
228232
#if defined (__CC_ARM) && !defined (__MICROLIB)
229233
/* A memory space for arm standard library. */
230234
static uint32_t std_libspace[OS_TASK_CNT][96/4];
@@ -434,6 +438,7 @@ void $Sub$$__cpp_initialize__aeabi_(void)
434438

435439
void pre_main()
436440
{
441+
singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex));
437442
$Super$$__cpp_initialize__aeabi_();
438443
main();
439444
}
@@ -447,6 +452,7 @@ int main(void);
447452

448453
void pre_main (void)
449454
{
455+
singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex));
450456
__rt_lib_init((unsigned)armcc_heap_base, (unsigned)armcc_heap_top);
451457
main();
452458
}
@@ -484,6 +490,7 @@ extern void __libc_init_array (void);
484490
extern int main(int argc, char **argv);
485491

486492
void pre_main(void) {
493+
singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex));
487494
atexit(__libc_fini_array);
488495
__libc_init_array();
489496
main(0, NULL);
@@ -516,6 +523,7 @@ extern int main(void);
516523
static uint8_t low_level_init_needed;
517524

518525
void pre_main(void) {
526+
singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex));
519527
if (low_level_init_needed) {
520528
__iar_dynamic_initialization();
521529
}

0 commit comments

Comments
 (0)