summaryrefslogtreecommitdiffstats
path: root/mbed/platform/SingletonPtr.h
blob: 00a396f643ef8e94c90fd1d2241dd3b5ded1dfd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

/** \addtogroup platform */
/** @{*/
/* 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 "platform/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();
            if (NULL == _ptr) {
                _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

/** @}*/