diff --git a/hal/api/AnalogIn.h b/hal/api/AnalogIn.h index b30fd610a95..ee18a97fc0a 100644 --- a/hal/api/AnalogIn.h +++ b/hal/api/AnalogIn.h @@ -118,7 +118,7 @@ class AnalogIn { } analogin_t _adc; - static PlatformMutex _mutex; + static PlatformMutexStatic _mutex; }; } // namespace mbed diff --git a/hal/api/FileBase.h b/hal/api/FileBase.h index e8758686afc..c64b0b8b0c2 100644 --- a/hal/api/FileBase.h +++ b/hal/api/FileBase.h @@ -65,7 +65,7 @@ class FileBase { /* disallow copy constructor and assignment operators */ private: static FileBase *_head; - static PlatformMutex _mutex; + static PlatformMutexStatic _mutex; FileBase *_next; const char * const _name; diff --git a/hal/api/I2C.h b/hal/api/I2C.h index 38fcdbc3fdf..098c2f6f67f 100644 --- a/hal/api/I2C.h +++ b/hal/api/I2C.h @@ -181,7 +181,7 @@ class I2C { i2c_t _i2c; static I2C *_owner; int _hz; - static PlatformMutex _mutex; + static PlatformMutexStatic _mutex; }; } // namespace mbed diff --git a/hal/api/platform.h b/hal/api/platform.h index cb1cb086199..4dbb5dad7e7 100644 --- a/hal/api/platform.h +++ b/hal/api/platform.h @@ -21,6 +21,7 @@ #include "device.h" #include "PinNames.h" #include "PeripheralNames.h" +#include "critical.h" #include #include @@ -54,4 +55,55 @@ class PlatformMutex { #endif +/** The static version of a PlatformMutex + * + * This class must only be used in a static context - + * this class must never be allocated or created on the + * stack. + * + * 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. + */ +struct PlatformMutexStatic { + PlatformMutex* _mutex; + + void _init() { + PlatformMutex* current = _mutex; + PlatformMutex* new_mutex; + + if (NULL == current) { + bool done = false; + new_mutex = new PlatformMutex; + while (!done) { + done = core_util_atomic_cas_ptr((void**)&_mutex, (void**)¤t, (void*)new_mutex); + if (current != NULL) { + // Mutex was created on another thread first + // so delete ours + delete new_mutex; + break; + } + } + } + } + + /** Wait until this Mutex becomes available. + */ + void lock() { + if (NULL == _mutex) { + _init(); + } + _mutex->lock(); + } + + /** Unlock the mutex that has previously been locked by the same thread + */ + void unlock() { + if (NULL == _mutex) { + _init(); + } + _mutex->unlock(); + } +}; + #endif diff --git a/hal/common/AnalogIn.cpp b/hal/common/AnalogIn.cpp index bbb044efb35..55a9e3a5bf2 100644 --- a/hal/common/AnalogIn.cpp +++ b/hal/common/AnalogIn.cpp @@ -22,7 +22,7 @@ namespace mbed { -PlatformMutex AnalogIn::_mutex; +PlatformMutexStatic AnalogIn::_mutex; }; diff --git a/hal/common/FileBase.cpp b/hal/common/FileBase.cpp index 46f6c272103..540bf241bb2 100644 --- a/hal/common/FileBase.cpp +++ b/hal/common/FileBase.cpp @@ -18,7 +18,7 @@ namespace mbed { FileBase *FileBase::_head = NULL; -PlatformMutex FileBase::_mutex; +PlatformMutexStatic FileBase::_mutex; FileBase::FileBase(const char *name, PathType t) : _next(NULL), _name(name), diff --git a/hal/common/I2C.cpp b/hal/common/I2C.cpp index 79560889a59..0ad61b51679 100644 --- a/hal/common/I2C.cpp +++ b/hal/common/I2C.cpp @@ -20,7 +20,7 @@ namespace mbed { I2C *I2C::_owner = NULL; -PlatformMutex I2C::_mutex; +PlatformMutexStatic I2C::_mutex; I2C::I2C(PinName sda, PinName scl) : #if DEVICE_I2C_ASYNCH diff --git a/hal/common/retarget.cpp b/hal/common/retarget.cpp index 9fbc27b7843..abd50e7b1db 100644 --- a/hal/common/retarget.cpp +++ b/hal/common/retarget.cpp @@ -72,7 +72,7 @@ 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 PlatformMutexStatic filehandle_mutex; FileHandle::~FileHandle() { filehandle_mutex.lock();