diff --git a/hal/api/AnalogIn.h b/hal/api/AnalogIn.h index 09437a25617..01b863f5554 100644 --- a/hal/api/AnalogIn.h +++ b/hal/api/AnalogIn.h @@ -25,6 +25,8 @@ namespace mbed { /** An analog input, used for reading the voltage on a pin + * + * @Note Synchronization level: Thread safe * * Example: * @code @@ -53,7 +55,9 @@ class AnalogIn { * @param name (optional) A string to identify the object */ AnalogIn(PinName pin) { + lock(); analogin_init(&_adc, pin); + unlock(); } /** Read the input voltage, represented as a float in the range [0.0, 1.0] @@ -61,7 +65,10 @@ class AnalogIn { * @returns A floating-point value representing the current input voltage, measured as a percentage */ float read() { - return analogin_read(&_adc); + lock(); + float ret = analogin_read(&_adc); + unlock(); + return ret; } /** Read the input voltage, represented as an unsigned short in the range [0x0, 0xFFFF] @@ -70,7 +77,10 @@ class AnalogIn { * 16-bit unsigned short representing the current input voltage, normalised to a 16-bit value */ unsigned short read_u16() { - return analogin_read_u16(&_adc); + lock(); + unsigned short ret = analogin_read_u16(&_adc); + unlock(); + return ret; } #ifdef MBED_OPERATORS @@ -88,12 +98,23 @@ class AnalogIn { * @endcode */ operator float() { + // Underlying call is thread safe return read(); } #endif protected: + + virtual void lock() { + _mutex.lock(); + } + + virtual void unlock() { + _mutex.unlock(); + } + analogin_t _adc; + static PlatformMutex _mutex; }; } // namespace mbed diff --git a/hal/api/AnalogOut.h b/hal/api/AnalogOut.h index 0b879a72b82..68488d97096 100644 --- a/hal/api/AnalogOut.h +++ b/hal/api/AnalogOut.h @@ -25,6 +25,8 @@ namespace mbed { /** An analog output, used for setting the voltage on a pin + * + * @Note Synchronization level: Thread safe * * Example: * @code @@ -64,7 +66,9 @@ class AnalogOut { * Values outside this range will be saturated to 0.0f or 1.0f. */ void write(float value) { + lock(); analogout_write(&_dac, value); + unlock(); } /** Set the output voltage, represented as an unsigned short in the range [0x0, 0xFFFF] @@ -73,7 +77,9 @@ class AnalogOut { * normalised to a 16-bit value (0x0000 = 0v, 0xFFFF = 3.3v) */ void write_u16(unsigned short value) { + lock(); analogout_write_u16(&_dac, value); + unlock(); } /** Return the current output voltage setting, measured as a percentage (float) @@ -87,18 +93,23 @@ class AnalogOut { * This value may not match exactly the value set by a previous write(). */ float read() { - return analogout_read(&_dac); + lock(); + float ret = analogout_read(&_dac); + unlock(); + return ret; } #ifdef MBED_OPERATORS /** An operator shorthand for write() */ AnalogOut& operator= (float percent) { + // Underlying write call is thread safe write(percent); return *this; } AnalogOut& operator= (AnalogOut& rhs) { + // Underlying write call is thread safe write(rhs.read()); return *this; } @@ -106,12 +117,23 @@ class AnalogOut { /** An operator shorthand for read() */ operator float() { + // Underlying read call is thread safe return read(); } #endif protected: + + virtual void lock() { + _mutex.lock(); + } + + virtual void unlock() { + _mutex.unlock(); + } + dac_t _dac; + PlatformMutex _mutex; }; } // namespace mbed diff --git a/hal/api/BusIn.h b/hal/api/BusIn.h index d1c9a9cd4e1..9e91ccb9d3a 100644 --- a/hal/api/BusIn.h +++ b/hal/api/BusIn.h @@ -22,6 +22,8 @@ namespace mbed { /** A digital input bus, used for reading the state of a collection of pins + * + * @Note Synchronization level: Thread safe */ class BusIn { @@ -65,6 +67,7 @@ class BusIn { * Binary mask of connected pins */ int mask() { + // No lock needed since _nc_mask is not modified outside the constructor return _nc_mask; } @@ -87,8 +90,12 @@ class BusIn { */ int _nc_mask; + PlatformMutex _mutex; + /* disallow copy constructor and assignment operators */ private: + virtual void lock(); + virtual void unlock(); BusIn(const BusIn&); BusIn & operator = (const BusIn&); }; diff --git a/hal/api/BusInOut.h b/hal/api/BusInOut.h index 54328fb0217..0d61eef1a3e 100644 --- a/hal/api/BusInOut.h +++ b/hal/api/BusInOut.h @@ -21,6 +21,8 @@ namespace mbed { /** A digital input output bus, used for setting the state of a collection of pins + * + * @Note Synchronization level: Thread safe */ class BusInOut { @@ -79,6 +81,7 @@ class BusInOut { * Binary mask of connected pins */ int mask() { + // No lock needed since _nc_mask is not modified outside the constructor return _nc_mask; } @@ -98,6 +101,8 @@ class BusInOut { #endif protected: + virtual void lock(); + virtual void unlock(); DigitalInOut* _pin[16]; /** Mask of bus's NC pins @@ -106,6 +111,8 @@ class BusInOut { */ int _nc_mask; + PlatformMutex _mutex; + /* disallow copy constructor and assignment operators */ private: BusInOut(const BusInOut&); diff --git a/hal/api/BusOut.h b/hal/api/BusOut.h index 1c55be07e98..4f3d672ae95 100644 --- a/hal/api/BusOut.h +++ b/hal/api/BusOut.h @@ -30,6 +30,8 @@ class BusOut { * * @param p DigitalOut pin to connect to bus bit (p5-p30, NC) * + * @Note Synchronization level: Thread safe + * * @note * It is only required to specify as many pin variables as is required * for the bus; the rest will default to NC (not connected) @@ -63,6 +65,7 @@ class BusOut { * Binary mask of connected pins */ int mask() { + // No lock needed since _nc_mask is not modified outside the constructor return _nc_mask; } @@ -82,6 +85,8 @@ class BusOut { #endif protected: + virtual void lock(); + virtual void unlock(); DigitalOut* _pin[16]; /** Mask of bus's NC pins @@ -90,6 +95,8 @@ class BusOut { */ int _nc_mask; + PlatformMutex _mutex; + /* disallow copy constructor and assignment operators */ private: BusOut(const BusOut&); diff --git a/hal/api/CAN.h b/hal/api/CAN.h index 241cd4c8229..44e1e08795b 100644 --- a/hal/api/CAN.h +++ b/hal/api/CAN.h @@ -27,6 +27,8 @@ namespace mbed { /** CANMessage class + * + * @Note Synchronization level: Thread safe */ class CANMessage : public CAN_Message { @@ -220,6 +222,7 @@ class CAN { */ template void attach(T* obj, void (T::*method)(), IrqType type=RxIrq) { + // Underlying call thread safe attach(Callback(obj, method), type); } @@ -232,14 +235,18 @@ class CAN { */ template void attach(T* obj, void (*method)(T*), IrqType type=RxIrq) { + // Underlying call thread safe attach(Callback(obj, method), type); } static void _irq_handler(uint32_t id, CanIrqType type); protected: + virtual void lock(); + virtual void unlock(); can_t _can; Callback _irq[9]; + PlatformMutex _mutex; }; } // namespace mbed diff --git a/hal/api/CThunk.h b/hal/api/CThunk.h index 741bf9c7c3e..3a9862ddb1d 100644 --- a/hal/api/CThunk.h +++ b/hal/api/CThunk.h @@ -71,6 +71,11 @@ /* IRQ/Exception compatible thunk entry function */ typedef void (*CThunkEntry)(void); +/** + * Class for created a pointer with data bound to it + * + * @Note Synchronization level: Not protected + */ template class CThunk { diff --git a/hal/api/CallChain.h b/hal/api/CallChain.h index babdacbf91f..5173f1d97d7 100644 --- a/hal/api/CallChain.h +++ b/hal/api/CallChain.h @@ -25,6 +25,8 @@ namespace mbed { * sequence using CallChain::call(). Used mostly by the interrupt chaining code, * but can be used for other purposes. * + * @Note Synchronization level: Not protected + * * Example: * @code * #include "mbed.h" @@ -58,6 +60,7 @@ namespace mbed { */ typedef Callback *pFunctionPointer_t; +class CallChainLink; class CallChain { public: @@ -160,17 +163,11 @@ class CallChain { } #endif -private: - void _check_size(); - - pFunctionPointer_t* _chain; - int _size; - int _elements; - /* disallow copy constructor and assignment operators */ private: CallChain(const CallChain&); CallChain & operator = (const CallChain&); + CallChainLink *_chain; }; } // namespace mbed diff --git a/hal/api/Callback.h b/hal/api/Callback.h index 86485f99262..377d84a2a0d 100644 --- a/hal/api/Callback.h +++ b/hal/api/Callback.h @@ -23,6 +23,8 @@ namespace mbed { /** Callback class based on template specialization + * + * @Note Synchronization level: Not protected */ template class Callback; diff --git a/hal/api/CircularBuffer.h b/hal/api/CircularBuffer.h index e9f3f1c843e..466288c4bef 100644 --- a/hal/api/CircularBuffer.h +++ b/hal/api/CircularBuffer.h @@ -16,9 +16,13 @@ #ifndef MBED_CIRCULARBUFFER_H #define MBED_CIRCULARBUFFER_H +#include "critical.h" + namespace mbed { /** Templated Circular buffer class + * + * @Note Synchronization level: Interrupt safe */ template class CircularBuffer { @@ -35,6 +39,7 @@ class CircularBuffer { * @param data Data to be pushed to the buffer */ void push(const T& data) { + core_util_critical_section_enter(); if (full()) { _tail++; _tail %= BufferSize; @@ -44,6 +49,7 @@ class CircularBuffer { if (_head == _tail) { _full = true; } + core_util_critical_section_exit(); } /** Pop the transaction from the buffer @@ -52,13 +58,16 @@ class CircularBuffer { * @return True if the buffer is not empty and data contains a transaction, false otherwise */ bool pop(T& data) { + bool data_popped = false; + core_util_critical_section_enter(); if (!empty()) { data = _pool[_tail++]; _tail %= BufferSize; _full = false; - return true; + data_popped = true; } - return false; + core_util_critical_section_exit(); + return data_popped; } /** Check if the buffer is empty @@ -66,7 +75,10 @@ class CircularBuffer { * @return True if the buffer is empty, false if not */ bool empty() { - return (_head == _tail) && !_full; + core_util_critical_section_enter(); + bool is_empty = (_head == _tail) && !_full; + core_util_critical_section_exit(); + return is_empty; } /** Check if the buffer is full @@ -74,16 +86,21 @@ class CircularBuffer { * @return True if the buffer is full, false if not */ bool full() { - return _full; + core_util_critical_section_enter(); + bool full = _full; + core_util_critical_section_exit(); + return full; } /** Reset the buffer * */ void reset() { + core_util_critical_section_enter(); _head = 0; _tail = 0; _full = false; + core_util_critical_section_exit(); } private: diff --git a/hal/api/DigitalIn.h b/hal/api/DigitalIn.h index b089de9faae..f0d8d82fc58 100644 --- a/hal/api/DigitalIn.h +++ b/hal/api/DigitalIn.h @@ -19,10 +19,13 @@ #include "platform.h" #include "gpio_api.h" +#include "critical.h" namespace mbed { /** A digital input, used for reading the state of a pin + * + * @Note Synchronization level: Interrupt safe * * Example: * @code @@ -51,6 +54,7 @@ class DigitalIn { * @param pin DigitalIn pin to connect to */ DigitalIn(PinName pin) : gpio() { + // No lock needed in the constructor gpio_init_in(&gpio, pin); } @@ -60,6 +64,7 @@ class DigitalIn { * @param mode the initial mode of the pin */ DigitalIn(PinName pin, PinMode mode) : gpio() { + // No lock needed in the constructor gpio_init_in_ex(&gpio, pin, mode); } /** Read the input, represented as 0 or 1 (int) @@ -69,6 +74,7 @@ class DigitalIn { * 0 for logical 0, 1 for logical 1 */ int read() { + // Thread safe / atomic HAL call return gpio_read(&gpio); } @@ -77,7 +83,9 @@ class DigitalIn { * @param mode PullUp, PullDown, PullNone, OpenDrain */ void mode(PinMode pull) { + core_util_critical_section_enter(); gpio_mode(&gpio, pull); + core_util_critical_section_exit(); } /** Return the output setting, represented as 0 or 1 (int) @@ -87,6 +95,7 @@ class DigitalIn { * 0 if gpio object was initialized with NC */ int is_connected() { + // Thread safe / atomic HAL call return gpio_is_connected(&gpio); } @@ -94,6 +103,7 @@ class DigitalIn { /** An operator shorthand for read() */ operator int() { + // Underlying read is thread safe return read(); } #endif diff --git a/hal/api/DigitalInOut.h b/hal/api/DigitalInOut.h index e30be0e6388..cb12dc80145 100644 --- a/hal/api/DigitalInOut.h +++ b/hal/api/DigitalInOut.h @@ -19,10 +19,13 @@ #include "platform.h" #include "gpio_api.h" +#include "critical.h" namespace mbed { /** A digital input/output, used for setting or reading a bi-directional pin + * + * @Note Synchronization level: Interrupt safe */ class DigitalInOut { @@ -32,6 +35,7 @@ class DigitalInOut { * @param pin DigitalInOut pin to connect to */ DigitalInOut(PinName pin) : gpio() { + // No lock needed in the constructor gpio_init_in(&gpio, pin); } @@ -43,6 +47,7 @@ class DigitalInOut { * @param value the initial value of the pin if is an output */ DigitalInOut(PinName pin, PinDirection direction, PinMode mode, int value) : gpio() { + // No lock needed in the constructor gpio_init_inout(&gpio, pin, direction, mode, value); } @@ -52,6 +57,7 @@ class DigitalInOut { * 0 for logical 0, 1 (or any other non-zero value) for logical 1 */ void write(int value) { + // Thread safe / atomic HAL call gpio_write(&gpio, value); } @@ -62,19 +68,24 @@ class DigitalInOut { * or read the input if set as an input */ int read() { + // Thread safe / atomic HAL call return gpio_read(&gpio); } /** Set as an output */ void output() { + core_util_critical_section_enter(); gpio_dir(&gpio, PIN_OUTPUT); + core_util_critical_section_exit(); } /** Set as an input */ void input() { + core_util_critical_section_enter(); gpio_dir(&gpio, PIN_INPUT); + core_util_critical_section_exit(); } /** Set the input pin mode @@ -82,7 +93,9 @@ class DigitalInOut { * @param mode PullUp, PullDown, PullNone, OpenDrain */ void mode(PinMode pull) { + core_util_critical_section_enter(); gpio_mode(&gpio, pull); + core_util_critical_section_exit(); } /** Return the output setting, represented as 0 or 1 (int) @@ -92,6 +105,7 @@ class DigitalInOut { * 0 if gpio object was initialized with NC */ int is_connected() { + // Thread safe / atomic HAL call return gpio_is_connected(&gpio); } @@ -99,18 +113,22 @@ class DigitalInOut { /** A shorthand for write() */ DigitalInOut& operator= (int value) { + // Underlying write is thread safe write(value); return *this; } DigitalInOut& operator= (DigitalInOut& rhs) { + core_util_critical_section_enter(); write(rhs.read()); + core_util_critical_section_exit(); return *this; } /** A shorthand for read() */ operator int() { + // Underlying call is thread safe return read(); } #endif diff --git a/hal/api/DigitalOut.h b/hal/api/DigitalOut.h index 0d66f907b02..1ce52a50787 100644 --- a/hal/api/DigitalOut.h +++ b/hal/api/DigitalOut.h @@ -18,10 +18,13 @@ #include "platform.h" #include "gpio_api.h" +#include "critical.h" namespace mbed { /** A digital output, used for setting the state of a pin + * + * @Note Synchronization level: Interrupt safe * * Example: * @code @@ -46,6 +49,7 @@ class DigitalOut { * @param pin DigitalOut pin to connect to */ DigitalOut(PinName pin) : gpio() { + // No lock needed in the constructor gpio_init_out(&gpio, pin); } @@ -55,6 +59,7 @@ class DigitalOut { * @param value the initial pin value */ DigitalOut(PinName pin, int value) : gpio() { + // No lock needed in the constructor gpio_init_out_ex(&gpio, pin, value); } @@ -64,6 +69,7 @@ class DigitalOut { * 0 for logical 0, 1 (or any other non-zero value) for logical 1 */ void write(int value) { + // Thread safe / atomic HAL call gpio_write(&gpio, value); } @@ -74,6 +80,7 @@ class DigitalOut { * 0 for logical 0, 1 for logical 1 */ int read() { + // Thread safe / atomic HAL call return gpio_read(&gpio); } @@ -84,6 +91,7 @@ class DigitalOut { * 0 if gpio object was initialized with NC */ int is_connected() { + // Thread safe / atomic HAL call return gpio_is_connected(&gpio); } @@ -91,18 +99,22 @@ class DigitalOut { /** A shorthand for write() */ DigitalOut& operator= (int value) { + // Underlying write is thread safe write(value); return *this; } DigitalOut& operator= (DigitalOut& rhs) { + core_util_critical_section_enter(); write(rhs.read()); + core_util_critical_section_exit(); return *this; } /** A shorthand for read() */ operator int() { + // Underlying call is thread safe return read(); } #endif diff --git a/hal/api/DirHandle.h b/hal/api/DirHandle.h index f1630101533..41463aaa474 100644 --- a/hal/api/DirHandle.h +++ b/hal/api/DirHandle.h @@ -44,6 +44,8 @@ namespace mbed { * The root directory is considered to contain all FileLike and * FileSystemLike objects, so the DIR* returned by opendir("/") will * reflect this. + * + * @Note Synchronization level: Set by subclass */ class DirHandle { @@ -85,6 +87,20 @@ class DirHandle { virtual void seekdir(off_t location) { (void)location;} virtual ~DirHandle() {} + +protected: + + /** Acquire exclusive access to this object. + */ + virtual void lock() { + // Stub + } + + /** Release exclusive access to this object. + */ + virtual void unlock() { + // Stub + } }; } // namespace mbed diff --git a/hal/api/Ethernet.h b/hal/api/Ethernet.h index d0e59a5cf7f..d4d0ee1d8c3 100644 --- a/hal/api/Ethernet.h +++ b/hal/api/Ethernet.h @@ -23,6 +23,8 @@ namespace mbed { /** An ethernet interface, to use with the ethernet pins. + * + * @Note Synchronization level: Not protected * * Example: * @code diff --git a/hal/api/FileBase.h b/hal/api/FileBase.h index 88f87842c90..e8758686afc 100644 --- a/hal/api/FileBase.h +++ b/hal/api/FileBase.h @@ -62,15 +62,14 @@ class FileBase { static FileBase *get(int n); -protected: + /* disallow copy constructor and assignment operators */ +private: static FileBase *_head; + static PlatformMutex _mutex; FileBase *_next; - const char *_name; - PathType _path_type; - - /* disallow copy constructor and assignment operators */ -private: + const char * const _name; + const PathType _path_type; FileBase(const FileBase&); FileBase & operator = (const FileBase&); }; diff --git a/hal/api/FileHandle.h b/hal/api/FileHandle.h index 0a98a827c6d..7950315ddb8 100644 --- a/hal/api/FileHandle.h +++ b/hal/api/FileHandle.h @@ -38,6 +38,8 @@ namespace mbed { * * No one ever directly tals to/instanciates a FileHandle - it gets * created by FileSystem, and wrapped up by stdio. + * + * @Note Synchronization level: Set by subclass */ class FileHandle { @@ -101,17 +103,36 @@ class FileHandle { virtual int fsync() = 0; virtual off_t flen() { + lock(); /* remember our current position */ off_t pos = lseek(0, SEEK_CUR); - if(pos == -1) return -1; + if(pos == -1) { + unlock(); + return -1; + } /* seek to the end to get the file length */ off_t res = lseek(0, SEEK_END); /* return to our old position */ lseek(pos, SEEK_SET); + unlock(); return res; } virtual ~FileHandle(); + +protected: + + /** Acquire exclusive access to this object. + */ + virtual void lock() { + // Stub + } + + /** Release exclusive access to this object. + */ + virtual void unlock() { + // Stub + } }; } // namespace mbed diff --git a/hal/api/FileLike.h b/hal/api/FileLike.h index 666575c904e..53ff786693e 100644 --- a/hal/api/FileLike.h +++ b/hal/api/FileLike.h @@ -25,6 +25,8 @@ namespace mbed { * A file-like object is one that can be opened with fopen by * fopen("/name", mode). It is intersection of the classes Base and * FileHandle. + * + * @Note Synchronization level: Set by subclass */ class FileLike : public FileHandle, public FileBase { @@ -37,6 +39,7 @@ class FileLike : public FileHandle, public FileBase { FileLike(const char *name); virtual ~FileLike(); + }; } // namespace mbed diff --git a/hal/api/FileSystemLike.h b/hal/api/FileSystemLike.h index 926330c20c8..c9add10d98b 100644 --- a/hal/api/FileSystemLike.h +++ b/hal/api/FileSystemLike.h @@ -29,6 +29,8 @@ namespace mbed { * * Implementations must define at least open (the default definitions * of the rest of the functions just return error values). + * + * @Note Synchronization level: Set by subclass */ class FileSystemLike : public FileBase { diff --git a/hal/api/I2C.h b/hal/api/I2C.h index 3097fb943e0..817c590d6e5 100644 --- a/hal/api/I2C.h +++ b/hal/api/I2C.h @@ -31,6 +31,8 @@ namespace mbed { /** An I2C Master, used for communicating with I2C slave devices + * + * @Note Synchronization level: Thread safe * * Example: * @code @@ -135,6 +137,14 @@ class I2C { */ void stop(void); + /** Acquire exclusive access to this I2C bus + */ + virtual void lock(void); + + /** Release exclusive access to this I2C bus + */ + virtual void unlock(void); + #if DEVICE_I2C_ASYNCH /** Start non-blocking I2C transfer. @@ -167,6 +177,7 @@ class I2C { i2c_t _i2c; static I2C *_owner; int _hz; + static PlatformMutex _mutex; }; } // namespace mbed diff --git a/hal/api/I2CSlave.h b/hal/api/I2CSlave.h index 738faea27e5..511998a120e 100644 --- a/hal/api/I2CSlave.h +++ b/hal/api/I2CSlave.h @@ -25,6 +25,8 @@ namespace mbed { /** An I2C Slave, used for communicating with an I2C Master device + * + * @Note Synchronization level: Not protected * * Example: * @code diff --git a/hal/api/InterruptIn.h b/hal/api/InterruptIn.h index 0e519faef40..9f6015884a5 100644 --- a/hal/api/InterruptIn.h +++ b/hal/api/InterruptIn.h @@ -23,10 +23,13 @@ #include "gpio_api.h" #include "gpio_irq_api.h" #include "Callback.h" +#include "critical.h" namespace mbed { /** A digital interrupt input, used to call a function on a rising or falling edge + * + * @Note Synchronization level: Interrupt safe * * Example: * @code @@ -81,7 +84,9 @@ class InterruptIn { */ template void rise(T *obj, M method) { + core_util_critical_section_enter(); rise(Callback(obj, method)); + core_util_critical_section_exit(); } /** Attach a function to call when a falling edge occurs on the input @@ -97,7 +102,9 @@ class InterruptIn { */ template void fall(T *obj, M method) { + core_util_critical_section_enter(); fall(Callback(obj, method)); + core_util_critical_section_exit(); } /** Set the input pin mode diff --git a/hal/api/InterruptManager.h b/hal/api/InterruptManager.h index 4959a646998..30c705f1ac4 100644 --- a/hal/api/InterruptManager.h +++ b/hal/api/InterruptManager.h @@ -1,6 +1,8 @@ #ifndef MBED_INTERRUPTMANAGER_H #define MBED_INTERRUPTMANAGER_H +#include "platform.h" + #include "cmsis.h" #include "CallChain.h" #include @@ -8,6 +10,8 @@ namespace mbed { /** Use this singleton if you need to chain interrupt handlers. + * + * @Note Synchronization level: Thread safe * * Example (for LPC1768): * @code @@ -52,6 +56,7 @@ class InterruptManager { * The function object created for 'function' */ pFunctionPointer_t add_handler(void (*function)(void), IRQn_Type irq) { + // Underlying call is thread safe return add_common(function, irq); } @@ -64,6 +69,7 @@ class InterruptManager { * The function object created for 'function' */ pFunctionPointer_t add_handler_front(void (*function)(void), IRQn_Type irq) { + // Underlying call is thread safe return add_common(function, irq, true); } @@ -78,6 +84,7 @@ class InterruptManager { */ template pFunctionPointer_t add_handler(T* tptr, void (T::*mptr)(void), IRQn_Type irq) { + // Underlying call is thread safe return add_common(tptr, mptr, irq); } @@ -92,6 +99,7 @@ class InterruptManager { */ template pFunctionPointer_t add_handler_front(T* tptr, void (T::*mptr)(void), IRQn_Type irq) { + // Underlying call is thread safe return add_common(tptr, mptr, irq, true); } @@ -105,6 +113,10 @@ class InterruptManager { */ bool remove_handler(pFunctionPointer_t handler, IRQn_Type irq); +protected: + virtual void lock(); + virtual void unlock(); + private: InterruptManager(); ~InterruptManager(); @@ -117,12 +129,14 @@ class InterruptManager { template pFunctionPointer_t add_common(T *tptr, void (T::*mptr)(void), IRQn_Type irq, bool front=false) { + _mutex.lock(); int irq_pos = get_irq_index(irq); bool change = must_replace_vector(irq); pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(tptr, mptr) : _chains[irq_pos]->add(tptr, mptr); if (change) NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper); + _mutex.unlock(); return pf; } @@ -135,6 +149,7 @@ class InterruptManager { CallChain* _chains[NVIC_NUM_VECTORS]; static InterruptManager* _instance; + PlatformMutex _mutex; }; } // namespace mbed diff --git a/hal/api/LocalFileSystem.h b/hal/api/LocalFileSystem.h index 9eb61a4b954..e6c15edaccf 100644 --- a/hal/api/LocalFileSystem.h +++ b/hal/api/LocalFileSystem.h @@ -46,8 +46,11 @@ class LocalFileHandle : public FileHandle { virtual off_t flen(); protected: + virtual void lock(); + virtual void unlock(); FILEHANDLE _fh; int pos; + PlatformMutex _mutex; }; /** A filesystem for accessing the local mbed Microcontroller USB disk drive @@ -56,6 +59,8 @@ class LocalFileHandle : public FileHandle { * mbed Microcontroller. Once created, the standard C file access functions are used to open, * read and write files. * + * @Note Synchronization level: Thread safe + * * Example: * @code * #include "mbed.h" @@ -85,6 +90,7 @@ class LocalFileHandle : public FileHandle { * not exit, you will need to hold down reset on the mbed Microcontroller to be able to see the drive again! */ class LocalFileSystem : public FileSystemLike { + // No modifiable state public: LocalFileSystem(const char* n) : FileSystemLike(n) { diff --git a/hal/api/LowPowerTicker.h b/hal/api/LowPowerTicker.h index 540788c3550..70803acdfcb 100644 --- a/hal/api/LowPowerTicker.h +++ b/hal/api/LowPowerTicker.h @@ -26,6 +26,8 @@ namespace mbed { /** Low Power Ticker + * + * @Note Synchronization level: Interrupt safe */ class LowPowerTicker : public Ticker { diff --git a/hal/api/LowPowerTimeout.h b/hal/api/LowPowerTimeout.h index c81e04946b6..8cbff2b5d5a 100644 --- a/hal/api/LowPowerTimeout.h +++ b/hal/api/LowPowerTimeout.h @@ -26,6 +26,8 @@ namespace mbed { /** Low Power Timout + * + * @Note Synchronization level: Interrupt safe */ class LowPowerTimeout : public LowPowerTicker { diff --git a/hal/api/LowPowerTimer.h b/hal/api/LowPowerTimer.h index ad7782be108..c372f3671ab 100644 --- a/hal/api/LowPowerTimer.h +++ b/hal/api/LowPowerTimer.h @@ -26,6 +26,8 @@ namespace mbed { /** Low power timer + * + * @Note Synchronization level: Interrupt safe */ class LowPowerTimer : public Timer { diff --git a/hal/api/PortIn.h b/hal/api/PortIn.h index 44686325cf1..c0cf85b1e33 100644 --- a/hal/api/PortIn.h +++ b/hal/api/PortIn.h @@ -21,10 +21,13 @@ #if DEVICE_PORTIN #include "port_api.h" +#include "critical.h" namespace mbed { /** A multiple pin digital input + * + * @Note Synchronization level: Interrupt safe * * Example: * @code @@ -56,7 +59,9 @@ class PortIn { * @param mask A bitmask to identify which bits in the port should be included (0 - ignore) */ PortIn(PortName port, int mask = 0xFFFFFFFF) { + core_util_critical_section_enter(); port_init(&_port, port, mask, PIN_INPUT); + core_util_critical_section_exit(); } /** Read the value currently output on the port @@ -73,7 +78,9 @@ class PortIn { * @param mode PullUp, PullDown, PullNone, OpenDrain */ void mode(PinMode mode) { + core_util_critical_section_enter(); port_mode(&_port, mode); + core_util_critical_section_exit(); } /** A shorthand for read() diff --git a/hal/api/PortInOut.h b/hal/api/PortInOut.h index cca755126ae..123f36174f7 100644 --- a/hal/api/PortInOut.h +++ b/hal/api/PortInOut.h @@ -21,10 +21,13 @@ #if DEVICE_PORTINOUT #include "port_api.h" +#include "critical.h" namespace mbed { /** A multiple pin digital in/out used to set/read multiple bi-directional pins + * + * @Note Synchronization level: Interrupt safe */ class PortInOut { public: @@ -35,7 +38,9 @@ class PortInOut { * @param mask A bitmask to identify which bits in the port should be included (0 - ignore) */ PortInOut(PortName port, int mask = 0xFFFFFFFF) { + core_util_critical_section_enter(); port_init(&_port, port, mask, PIN_INPUT); + core_util_critical_section_exit(); } /** Write the value to the output port @@ -58,13 +63,17 @@ class PortInOut { /** Set as an output */ void output() { + core_util_critical_section_enter(); port_dir(&_port, PIN_OUTPUT); + core_util_critical_section_exit(); } /** Set as an input */ void input() { + core_util_critical_section_enter(); port_dir(&_port, PIN_INPUT); + core_util_critical_section_exit(); } /** Set the input pin mode @@ -72,7 +81,9 @@ class PortInOut { * @param mode PullUp, PullDown, PullNone, OpenDrain */ void mode(PinMode mode) { + core_util_critical_section_enter(); port_mode(&_port, mode); + core_util_critical_section_exit(); } /** A shorthand for write() diff --git a/hal/api/PortOut.h b/hal/api/PortOut.h index bab5fe0c65b..46689df3316 100644 --- a/hal/api/PortOut.h +++ b/hal/api/PortOut.h @@ -21,9 +21,12 @@ #if DEVICE_PORTOUT #include "port_api.h" +#include "critical.h" namespace mbed { /** A multiple pin digital out + * + * @Note Synchronization level: Interrupt safe * * Example: * @code @@ -55,7 +58,9 @@ class PortOut { * @param mask A bitmask to identify which bits in the port should be included (0 - ignore) */ PortOut(PortName port, int mask = 0xFFFFFFFF) { + core_util_critical_section_enter(); port_init(&_port, port, mask, PIN_OUTPUT); + core_util_critical_section_exit(); } /** Write the value to the output port diff --git a/hal/api/PwmOut.h b/hal/api/PwmOut.h index 9e8c0bdf29a..0805474927f 100644 --- a/hal/api/PwmOut.h +++ b/hal/api/PwmOut.h @@ -20,10 +20,13 @@ #if DEVICE_PWMOUT #include "pwmout_api.h" +#include "critical.h" namespace mbed { /** A pulse-width modulation digital output + * + * @Note Synchronization level: Interrupt safe * * Example * @code @@ -59,7 +62,9 @@ class PwmOut { * @param pin PwmOut pin to connect to */ PwmOut(PinName pin) { + core_util_critical_section_enter(); pwmout_init(&_pwm, pin); + core_util_critical_section_exit(); } /** Set the ouput duty-cycle, specified as a percentage (float) @@ -70,7 +75,9 @@ class PwmOut { * Values outside this range will be saturated to 0.0f or 1.0f. */ void write(float value) { + core_util_critical_section_enter(); pwmout_write(&_pwm, value); + core_util_critical_section_exit(); } /** Return the current output duty-cycle setting, measured as a percentage (float) @@ -84,7 +91,10 @@ class PwmOut { * This value may not match exactly the value set by a previous . */ float read() { - return pwmout_read(&_pwm); + core_util_critical_section_enter(); + float val = pwmout_read(&_pwm); + core_util_critical_section_exit(); + return val; } /** Set the PWM period, specified in seconds (float), keeping the duty cycle the same. @@ -94,48 +104,62 @@ class PwmOut { * will be set to zero. */ void period(float seconds) { + core_util_critical_section_enter(); pwmout_period(&_pwm, seconds); + core_util_critical_section_exit(); } /** Set the PWM period, specified in milli-seconds (int), keeping the duty cycle the same. */ void period_ms(int ms) { + core_util_critical_section_enter(); pwmout_period_ms(&_pwm, ms); + core_util_critical_section_exit(); } /** Set the PWM period, specified in micro-seconds (int), keeping the duty cycle the same. */ void period_us(int us) { + core_util_critical_section_enter(); pwmout_period_us(&_pwm, us); + core_util_critical_section_exit(); } /** Set the PWM pulsewidth, specified in seconds (float), keeping the period the same. */ void pulsewidth(float seconds) { + core_util_critical_section_enter(); pwmout_pulsewidth(&_pwm, seconds); + core_util_critical_section_exit(); } /** Set the PWM pulsewidth, specified in milli-seconds (int), keeping the period the same. */ void pulsewidth_ms(int ms) { + core_util_critical_section_enter(); pwmout_pulsewidth_ms(&_pwm, ms); + core_util_critical_section_exit(); } /** Set the PWM pulsewidth, specified in micro-seconds (int), keeping the period the same. */ void pulsewidth_us(int us) { + core_util_critical_section_enter(); pwmout_pulsewidth_us(&_pwm, us); + core_util_critical_section_exit(); } #ifdef MBED_OPERATORS /** A operator shorthand for write() */ PwmOut& operator= (float value) { + // Underlying call is thread safe write(value); return *this; } PwmOut& operator= (PwmOut& rhs) { + // Underlying call is thread safe write(rhs.read()); return *this; } @@ -143,6 +167,7 @@ class PwmOut { /** An operator shorthand for read() */ operator float() { + // Underlying call is thread safe return read(); } #endif diff --git a/hal/api/RawSerial.h b/hal/api/RawSerial.h index a5182bb64f7..c4ef470f5ce 100644 --- a/hal/api/RawSerial.h +++ b/hal/api/RawSerial.h @@ -32,6 +32,8 @@ namespace mbed { * Can be used for Full Duplex communication, or Simplex by specifying * one pin as NC (Not Connected) * + * @Note Synchronization level: Not protected + * * Example: * @code * // Send a char to the PC @@ -81,6 +83,16 @@ class RawSerial: public SerialBase { int puts(const char *str); int printf(const char *format, ...); + +protected: + + /** Acquire exclusive access to this serial port + */ + virtual void lock(void); + + /** Release exclusive access to this serial port + */ + virtual void unlock(void); }; } // namespace mbed diff --git a/hal/api/SPI.h b/hal/api/SPI.h index 63eba2550f3..c2b04ed3549 100644 --- a/hal/api/SPI.h +++ b/hal/api/SPI.h @@ -39,6 +39,8 @@ namespace mbed { * Most SPI devices will also require Chip Select and Reset signals. These * can be controlled using pins * + * @Note Synchronization level: Thread safe + * * Example: * @code * // Send a byte to a SPI slave, and record the response @@ -56,10 +58,13 @@ namespace mbed { * // hardware ssel (where applicable) * //int response = device.write(0xFF); * + * device.lock(); * // software ssel * cs = 0; * int response = device.write(0xFF); * cs = 1; + * device.unlock(); + * * } * @endcode */ @@ -109,6 +114,14 @@ class SPI { */ virtual int write(int value); + /** Acquire exclusive access to this SPI bus + */ + virtual void lock(void); + + /** Release exclusive access to this SPI bus + */ + virtual void unlock(void); + #if DEVICE_SPI_ASYNCH /** Start non-blocking SPI transfer using 8bit buffers. @@ -233,6 +246,7 @@ class SPI { void aquire(void); static SPI *_owner; + PlatformMutex _mutex; int _bits; int _mode; int _hz; diff --git a/hal/api/SPISlave.h b/hal/api/SPISlave.h index 1875ff69bbc..1f2d75323da 100644 --- a/hal/api/SPISlave.h +++ b/hal/api/SPISlave.h @@ -28,6 +28,8 @@ namespace mbed { * * The default format is set to 8-bits, mode 0, and a clock frequency of 1MHz * + * @Note Synchronization level: Not protected + * * Example: * @code * // Reply to a SPI master as slave diff --git a/hal/api/Serial.h b/hal/api/Serial.h index aa065405bce..41a3d846f45 100644 --- a/hal/api/Serial.h +++ b/hal/api/Serial.h @@ -31,6 +31,8 @@ namespace mbed { * Can be used for Full Duplex communication, or Simplex by specifying * one pin as NC (Not Connected) * + * @Note Synchronization level: Thread safe + * * Example: * @code * // Print "Hello World" to the PC @@ -65,6 +67,10 @@ class Serial : public SerialBase, public Stream { protected: virtual int _getc(); virtual int _putc(int c); + virtual void lock(); + virtual void unlock(); + + PlatformMutex _mutex; }; } // namespace mbed diff --git a/hal/api/SerialBase.h b/hal/api/SerialBase.h index ed2e744790b..1d7ae7c34dd 100644 --- a/hal/api/SerialBase.h +++ b/hal/api/SerialBase.h @@ -33,6 +33,8 @@ namespace mbed { /** A base class for serial port implementations * Can't be instantiated directly (use Serial or RawSerial) + * + * @Note Synchronization level: Set by subclass */ class SerialBase { @@ -120,6 +122,18 @@ class SerialBase { */ void send_break(); +protected: + + /** Acquire exclusive access to this serial port + */ + virtual void lock(void); + + /** Release exclusive access to this serial port + */ + virtual void unlock(void); + +public: + #if DEVICE_SERIAL_FC /** Set the flow control type on the serial port * diff --git a/hal/api/Stream.h b/hal/api/Stream.h index ca5dfe6b51b..f0695e02fc1 100644 --- a/hal/api/Stream.h +++ b/hal/api/Stream.h @@ -26,6 +26,10 @@ extern void mbed_set_unbuffered_stream(FILE *_file); extern int mbed_getc(FILE *_file); extern char* mbed_gets(char *s, int size, FILE *_file); +/** File stream + * + * @Note Synchronization level: Set by subclass + */ class Stream : public FileLike { public: diff --git a/hal/api/Ticker.h b/hal/api/Ticker.h index 817394039b0..496e469fa6b 100644 --- a/hal/api/Ticker.h +++ b/hal/api/Ticker.h @@ -25,6 +25,8 @@ namespace mbed { * * You can use as many seperate Ticker objects as you require. * + * @Note Synchronization level: Interrupt safe + * * Example: * @code * // Toggle the blinking led after 5 seconds diff --git a/hal/api/Timeout.h b/hal/api/Timeout.h index e145d9a77fa..dfa16cf4124 100644 --- a/hal/api/Timeout.h +++ b/hal/api/Timeout.h @@ -24,6 +24,8 @@ namespace mbed { * * You can use as many seperate Timeout objects as you require. * + * @Note Synchronization level: Interrupt safe + * * Example: * @code * // Blink until timeout. diff --git a/hal/api/Timer.h b/hal/api/Timer.h index 78faf6040ac..a429db9de86 100644 --- a/hal/api/Timer.h +++ b/hal/api/Timer.h @@ -22,6 +22,8 @@ namespace mbed { /** A general purpose timer + * + * @Note Synchronization level: Interrupt safe * * Example: * @code diff --git a/hal/api/TimerEvent.h b/hal/api/TimerEvent.h index cee6fb254bc..fd3d4569053 100644 --- a/hal/api/TimerEvent.h +++ b/hal/api/TimerEvent.h @@ -22,7 +22,9 @@ namespace mbed { /** Base abstraction for timer interrupts -*/ + * + * @Note Synchronization level: Interrupt safe + */ class TimerEvent { public: TimerEvent(); diff --git a/hal/api/Transaction.h b/hal/api/Transaction.h index 92852e27023..d093c3e6b58 100644 --- a/hal/api/Transaction.h +++ b/hal/api/Transaction.h @@ -34,6 +34,8 @@ typedef struct { } transaction_t; /** Transaction class defines a transaction. + * + * @Note Synchronization level: Not protected */ template class Transaction { diff --git a/hal/api/mbed_interface.h b/hal/api/mbed_interface.h index a93a4d33da0..b87ee7b9caa 100644 --- a/hal/api/mbed_interface.h +++ b/hal/api/mbed_interface.h @@ -16,6 +16,8 @@ #ifndef MBED_INTERFACE_H #define MBED_INTERFACE_H +#include + #include "device.h" /* Mbed interface mac address @@ -107,6 +109,20 @@ void mbed_mac_address(char *mac); */ void mbed_die(void); +/** Print out an error message. This is typically called when + * hanlding a crash. + * + * @Note Synchronization level: Interrupt safe + */ +void mbed_error_printf(const char* format, ...); + +/** Print out an error message. Similar to mbed_error_printf + * but uses a va_list. + * + * @Note Synchronization level: Interrupt safe + */ +void mbed_error_vfprintf(const char * format, va_list arg); + #ifdef __cplusplus } #endif diff --git a/hal/api/platform.h b/hal/api/platform.h index 85e44e57b18..cb1cb086199 100644 --- a/hal/api/platform.h +++ b/hal/api/platform.h @@ -27,4 +27,31 @@ #include #include +#ifdef MBED_CONF_RTOS_PRESENT +#include "Mutex.h" +typedef rtos::Mutex PlatformMutex; +#else +/** A stub mutex for when an RTOS is not present +*/ +class PlatformMutex { +public: + PlatformMutex() { + // Stub + + } + ~PlatformMutex() { + // Stub + } + + void lock() { + // Do nothing + } + + void unlock() { + // Do nothing + } +}; + +#endif + #endif diff --git a/hal/api/rtc_time.h b/hal/api/rtc_time.h index 565897366ea..e7ba04ccb0a 100644 --- a/hal/api/rtc_time.h +++ b/hal/api/rtc_time.h @@ -58,6 +58,8 @@ extern "C" { * * @param t Number of seconds since January 1, 1970 (the UNIX timestamp) * + * @Note Synchronization level: Thread safe + * * Example: * @code * #include "mbed.h" @@ -71,7 +73,7 @@ void set_time(time_t t); /** Attach an external RTC to be used for the C time functions * - * Do not call this function from an interrupt while an RTC read/write operation may be occurring + * @Note Synchronization level: Thread safe * * @param read_rtc pointer to function which returns current UNIX timestamp * @param write_rtc pointer to function which sets current UNIX timestamp, can be NULL diff --git a/hal/common/AnalogIn.cpp b/hal/common/AnalogIn.cpp new file mode 100644 index 00000000000..bbb044efb35 --- /dev/null +++ b/hal/common/AnalogIn.cpp @@ -0,0 +1,29 @@ +/* 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. + */ + +#include "mbed.h" + +#include "AnalogIn.h" + +#if DEVICE_ANALOGIN + +namespace mbed { + +PlatformMutex AnalogIn::_mutex; + +}; + +#endif diff --git a/hal/common/BusIn.cpp b/hal/common/BusIn.cpp index ea67cbcb806..454b9c4dc12 100644 --- a/hal/common/BusIn.cpp +++ b/hal/common/BusIn.cpp @@ -21,6 +21,7 @@ namespace mbed { BusIn::BusIn(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName p5, PinName p6, PinName p7, PinName p8, PinName p9, PinName p10, PinName p11, PinName p12, PinName p13, PinName p14, PinName p15) { PinName pins[16] = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15}; + // No lock needed in the constructor _nc_mask = 0; for (int i=0; i<16; i++) { _pin[i] = (pins[i] != NC) ? new DigitalIn(pins[i]) : 0; @@ -31,6 +32,7 @@ BusIn::BusIn(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName } BusIn::BusIn(PinName pins[16]) { + // No lock needed in the constructor _nc_mask = 0; for (int i=0; i<16; i++) { _pin[i] = (pins[i] != NC) ? new DigitalIn(pins[i]) : 0; @@ -41,6 +43,7 @@ BusIn::BusIn(PinName pins[16]) { } BusIn::~BusIn() { + // No lock needed in the destructor for (int i=0; i<16; i++) { if (_pin[i] != 0) { delete _pin[i]; @@ -50,28 +53,42 @@ BusIn::~BusIn() { int BusIn::read() { int v = 0; + lock(); for (int i=0; i<16; i++) { if (_pin[i] != 0) { v |= _pin[i]->read() << i; } } + unlock(); return v; } void BusIn::mode(PinMode pull) { + lock(); for (int i=0; i<16; i++) { if (_pin[i] != 0) { _pin[i]->mode(pull); } } + unlock(); +} + +void BusIn::lock() { + _mutex.lock(); +} + +void BusIn::unlock() { + _mutex.unlock(); } #ifdef MBED_OPERATORS BusIn::operator int() { + // Underlying read is thread safe return read(); } DigitalIn& BusIn::operator[] (int index) { + // No lock needed since _pin is not modified outside the constructor MBED_ASSERT(index >= 0 && index <= 16); MBED_ASSERT(_pin[index]); return *_pin[index]; diff --git a/hal/common/BusInOut.cpp b/hal/common/BusInOut.cpp index 5575f90d419..d333d080dfe 100644 --- a/hal/common/BusInOut.cpp +++ b/hal/common/BusInOut.cpp @@ -21,6 +21,7 @@ namespace mbed { BusInOut::BusInOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName p5, PinName p6, PinName p7, PinName p8, PinName p9, PinName p10, PinName p11, PinName p12, PinName p13, PinName p14, PinName p15) { PinName pins[16] = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15}; + // No lock needed in the constructor _nc_mask = 0; for (int i=0; i<16; i++) { _pin[i] = (pins[i] != NC) ? new DigitalInOut(pins[i]) : 0; @@ -31,6 +32,7 @@ BusInOut::BusInOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, P } BusInOut::BusInOut(PinName pins[16]) { + // No lock needed in the constructor _nc_mask = 0; for (int i=0; i<16; i++) { _pin[i] = (pins[i] != NC) ? new DigitalInOut(pins[i]) : 0; @@ -41,6 +43,7 @@ BusInOut::BusInOut(PinName pins[16]) { } BusInOut::~BusInOut() { + // No lock needed in the destructor for (int i=0; i<16; i++) { if (_pin[i] != 0) { delete _pin[i]; @@ -49,67 +52,89 @@ BusInOut::~BusInOut() { } void BusInOut::write(int value) { + lock(); for (int i=0; i<16; i++) { if (_pin[i] != 0) { _pin[i]->write((value >> i) & 1); } } + unlock(); } int BusInOut::read() { + lock(); int v = 0; for (int i=0; i<16; i++) { if (_pin[i] != 0) { v |= _pin[i]->read() << i; } } + unlock(); return v; } void BusInOut::output() { + lock(); for (int i=0; i<16; i++) { if (_pin[i] != 0) { _pin[i]->output(); } } + unlock(); } void BusInOut::input() { + lock(); for (int i=0; i<16; i++) { if (_pin[i] != 0) { _pin[i]->input(); } } + unlock(); } void BusInOut::mode(PinMode pull) { + lock(); for (int i=0; i<16; i++) { if (_pin[i] != 0) { _pin[i]->mode(pull); } } + unlock(); } #ifdef MBED_OPERATORS BusInOut& BusInOut::operator= (int v) { + // Underlying write is thread safe write(v); return *this; } BusInOut& BusInOut::operator= (BusInOut& rhs) { + // Underlying read is thread safe write(rhs.read()); return *this; } DigitalInOut& BusInOut::operator[] (int index) { + // No lock needed since _pin is not modified outside the constructor MBED_ASSERT(index >= 0 && index <= 16); MBED_ASSERT(_pin[index]); return *_pin[index]; } BusInOut::operator int() { + // Underlying read is thread safe return read(); } #endif +void BusInOut::lock() { + _mutex.lock(); +} + +void BusInOut::unlock() { + _mutex.unlock(); +} + } // namespace mbed diff --git a/hal/common/BusOut.cpp b/hal/common/BusOut.cpp index 4277c572724..11e326954ac 100644 --- a/hal/common/BusOut.cpp +++ b/hal/common/BusOut.cpp @@ -21,6 +21,7 @@ namespace mbed { BusOut::BusOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName p5, PinName p6, PinName p7, PinName p8, PinName p9, PinName p10, PinName p11, PinName p12, PinName p13, PinName p14, PinName p15) { PinName pins[16] = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15}; + // No lock needed in the constructor _nc_mask = 0; for (int i=0; i<16; i++) { _pin[i] = (pins[i] != NC) ? new DigitalOut(pins[i]) : 0; @@ -31,6 +32,7 @@ BusOut::BusOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinNa } BusOut::BusOut(PinName pins[16]) { + // No lock needed in the constructor _nc_mask = 0; for (int i=0; i<16; i++) { _pin[i] = (pins[i] != NC) ? new DigitalOut(pins[i]) : 0; @@ -41,6 +43,7 @@ BusOut::BusOut(PinName pins[16]) { } BusOut::~BusOut() { + // No lock needed in the destructor for (int i=0; i<16; i++) { if (_pin[i] != 0) { delete _pin[i]; @@ -49,43 +52,59 @@ BusOut::~BusOut() { } void BusOut::write(int value) { + lock(); for (int i=0; i<16; i++) { if (_pin[i] != 0) { _pin[i]->write((value >> i) & 1); } } + unlock(); } int BusOut::read() { + lock(); int v = 0; for (int i=0; i<16; i++) { if (_pin[i] != 0) { v |= _pin[i]->read() << i; } } + unlock(); return v; } #ifdef MBED_OPERATORS BusOut& BusOut::operator= (int v) { + // Underlying write is thread safe write(v); return *this; } BusOut& BusOut::operator= (BusOut& rhs) { + // Underlying write is thread safe write(rhs.read()); return *this; } DigitalOut& BusOut::operator[] (int index) { + // No lock needed since _pin is not modified outside the constructor MBED_ASSERT(index >= 0 && index <= 16); MBED_ASSERT(_pin[index]); return *_pin[index]; } BusOut::operator int() { + // Underlying read is thread safe return read(); } #endif +void BusOut::lock() { + _mutex.lock(); +} + +void BusOut::unlock() { + _mutex.unlock(); +} + } // namespace mbed diff --git a/hal/common/CAN.cpp b/hal/common/CAN.cpp index b717f80461b..780a106b73d 100644 --- a/hal/common/CAN.cpp +++ b/hal/common/CAN.cpp @@ -22,58 +22,87 @@ namespace mbed { CAN::CAN(PinName rd, PinName td) : _can(), _irq() { + // No lock needed in constructor can_init(&_can, rd, td); can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this); } CAN::~CAN() { + // No lock needed in destructor can_irq_free(&_can); can_free(&_can); } int CAN::frequency(int f) { - return can_frequency(&_can, f); + lock(); + int ret = can_frequency(&_can, f); + unlock(); + return ret; } int CAN::write(CANMessage msg) { - return can_write(&_can, msg, 0); + lock(); + int ret = can_write(&_can, msg, 0); + unlock(); + return ret; } int CAN::read(CANMessage &msg, int handle) { - return can_read(&_can, &msg, handle); + lock(); + int ret = can_read(&_can, &msg, handle); + unlock(); + return ret; } void CAN::reset() { + lock(); can_reset(&_can); + unlock(); } unsigned char CAN::rderror() { - return can_rderror(&_can); + lock(); + int ret = can_rderror(&_can); + unlock(); + return ret; } unsigned char CAN::tderror() { - return can_tderror(&_can); + lock(); + int ret = can_tderror(&_can); + unlock(); + return ret; } void CAN::monitor(bool silent) { + lock(); can_monitor(&_can, (silent) ? 1 : 0); + unlock(); } int CAN::mode(Mode mode) { - return can_mode(&_can, (CanMode)mode); + lock(); + int ret = can_mode(&_can, (CanMode)mode); + unlock(); + return ret; } int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle) { - return can_filter(&_can, id, mask, format, handle); + lock(); + int ret = can_filter(&_can, id, mask, format, handle); + unlock(); + return ret; } void CAN::attach(Callback func, IrqType type) { + lock(); if (func) { _irq[(CanIrqType)type].attach(func); can_irq_set(&_can, (CanIrqType)type, 1); } else { can_irq_set(&_can, (CanIrqType)type, 0); } + unlock(); } void CAN::_irq_handler(uint32_t id, CanIrqType type) { @@ -81,6 +110,14 @@ void CAN::_irq_handler(uint32_t id, CanIrqType type) { handler->_irq[type].call(); } +void CAN::lock() { + _mutex.lock(); +} + +void CAN::unlock() { + _mutex.unlock(); +} + } // namespace mbed #endif diff --git a/hal/common/CallChain.cpp b/hal/common/CallChain.cpp index 4c4a9cba4d9..ff55f977757 100644 --- a/hal/common/CallChain.cpp +++ b/hal/common/CallChain.cpp @@ -1,82 +1,116 @@ #include "CallChain.h" #include "cmsis.h" +#include "critical.h" namespace mbed { -CallChain::CallChain(int size) : _chain(), _size(size), _elements(0) { - _chain = new pFunctionPointer_t[size](); +class CallChainLink { +public: + CallChainLink(): cb(), next(NULL) { + // No work to do + } + + CallChainLink(Callback &callback): cb(callback), next(NULL) { + // No work to do + } + Callback cb; + CallChainLink * next; +}; + +CallChain::CallChain(int size) : _chain(NULL) { + // No work to do } CallChain::~CallChain() { clear(); - delete _chain; } pFunctionPointer_t CallChain::add(Callback func) { - _check_size(); - _chain[_elements] = new Callback(func); - _elements ++; - return _chain[_elements]; + CallChainLink *new_link = new CallChainLink(func); + if (NULL == _chain) { + _chain = new_link; + return &new_link->cb; + } + + CallChainLink *link = _chain; + while (true) { + if (NULL == link->next) { + link->next = new_link; + return &new_link->cb; + } + link = link->next; + } } pFunctionPointer_t CallChain::add_front(Callback func) { - _check_size(); - memmove(_chain + 1, _chain, _elements * sizeof(pFunctionPointer_t)); - _chain[0] = new Callback(func); - _elements ++; - return _chain[0]; + CallChainLink *link = new CallChainLink(func); + link->next = _chain; + _chain = link->next; + return &link->cb; } int CallChain::size() const { - return _elements; + CallChainLink *link = _chain; + int elements = 0; + while (link != NULL) { + elements++; + link = link->next; + } + return elements; } -pFunctionPointer_t CallChain::get(int i) const { - if (i < 0 || i >= _elements) - return NULL; - return _chain[i]; +pFunctionPointer_t CallChain::get(int idx) const { + CallChainLink *link = _chain; + for (int i = 0; i < idx; i++) { + if (NULL == link) { + break; + } + link = link->next; + } + return &link->cb; } int CallChain::find(pFunctionPointer_t f) const { - for (int i = 0; i < _elements; i++) - if (f == _chain[i]) + CallChainLink *link = _chain; + int i = 0; + while (link != NULL) { + if (f == &link->cb) { return i; + } + i++; + link = link->next; + } return -1; } void CallChain::clear() { - for(int i = 0; i < _elements; i ++) { - delete _chain[i]; - _chain[i] = NULL; + CallChainLink *link = _chain; + _chain = NULL; + while (link != NULL) { + CallChainLink *temp = link->next; + delete link; + link = temp; } - _elements = 0; } bool CallChain::remove(pFunctionPointer_t f) { - int i; - - if ((i = find(f)) == -1) - return false; - if (i != _elements - 1) - memmove(_chain + i, _chain + i + 1, (_elements - i - 1) * sizeof(pFunctionPointer_t)); - delete f; - _elements --; - return true; + CallChainLink *link = _chain; + while (link != NULL) { + if (f == &link->cb) { + delete link; + return true; + } + link = link->next; + } + return false; } void CallChain::call() { - for(int i = 0; i < _elements; i++) - _chain[i]->call(); -} - -void CallChain::_check_size() { - if (_elements < _size) - return; - _size = (_size < 4) ? 4 : _size + 4; - pFunctionPointer_t* new_chain = new pFunctionPointer_t[_size](); - memcpy(new_chain, _chain, _elements * sizeof(pFunctionPointer_t)); - delete _chain; - _chain = new_chain; + CallChainLink *link = _chain; + while (link != NULL) { + link->cb.call(); + link = link->next; + } } } // namespace mbed diff --git a/hal/common/FileBase.cpp b/hal/common/FileBase.cpp index fce113d88c1..46f6c272103 100644 --- a/hal/common/FileBase.cpp +++ b/hal/common/FileBase.cpp @@ -18,10 +18,12 @@ namespace mbed { FileBase *FileBase::_head = NULL; +PlatformMutex FileBase::_mutex; FileBase::FileBase(const char *name, PathType t) : _next(NULL), _name(name), _path_type(t) { + _mutex.lock(); if (name != NULL) { // put this object at head of the list _next = _head; @@ -29,9 +31,11 @@ FileBase::FileBase(const char *name, PathType t) : _next(NULL), } else { _next = NULL; } + _mutex.unlock(); } FileBase::~FileBase() { + _mutex.lock(); if (_name != NULL) { // remove this object from the list if (_head == this) { // first in the list, so just drop me @@ -44,37 +48,48 @@ FileBase::~FileBase() { p->_next = _next; } } + _mutex.unlock(); } FileBase *FileBase::lookup(const char *name, unsigned int len) { + _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(); return p; } p = p->_next; } + _mutex.unlock(); return NULL; } FileBase *FileBase::get(int n) { + _mutex.lock(); FileBase *p = _head; int m = 0; while (p != NULL) { - if (m == n) return p; + if (m == n) { + _mutex.unlock(); + return p; + } m++; p = p->_next; } + _mutex.unlock(); return NULL; } const char* FileBase::getName(void) { + // Constant read so no lock needed return _name; } PathType FileBase::getPathType(void) { + // Constant read so no lock needed return _path_type; } diff --git a/hal/common/FileSystemLike.cpp b/hal/common/FileSystemLike.cpp index df5d86da81b..b31fd4af1d5 100644 --- a/hal/common/FileSystemLike.cpp +++ b/hal/common/FileSystemLike.cpp @@ -33,32 +33,56 @@ class BaseDirHandle : public DirHandle { } virtual int closedir() { + // No lock can be used in destructor delete this; return 0; } virtual struct dirent *readdir() { + lock(); FileBase *ptr = FileBase::get(n); - if (ptr == NULL) return NULL; + if (ptr == NULL) { + unlock(); + return NULL; + } /* Increment n, so next readdir gets the next item */ n++; /* Setup cur entry and return a pointer to it */ std::strncpy(cur_entry.d_name, ptr->getName(), NAME_MAX); + unlock(); return &cur_entry; } virtual off_t telldir() { - return n; + lock(); + off_t offset = n; + unlock(); + return offset; } virtual void seekdir(off_t offset) { + lock(); n = offset; + unlock(); } virtual void rewinddir() { + lock(); n = 0; + unlock(); + } + +protected: + PlatformMutex _mutex; + + virtual void lock() { + _mutex.lock(); + } + + virtual void unlock() { + _mutex.unlock(); } }; diff --git a/hal/common/I2C.cpp b/hal/common/I2C.cpp index 8806a5e6a3a..79560889a59 100644 --- a/hal/common/I2C.cpp +++ b/hal/common/I2C.cpp @@ -20,12 +20,15 @@ namespace mbed { I2C *I2C::_owner = NULL; +PlatformMutex I2C::_mutex; I2C::I2C(PinName sda, PinName scl) : #if DEVICE_I2C_ASYNCH _irq(this), _usage(DMA_USAGE_NEVER), #endif _i2c(), _hz(100000) { + // No lock needed in the constructor + // The init function also set the frequency to 100000 i2c_init(&_i2c, sda, scl); @@ -34,6 +37,7 @@ I2C::I2C(PinName sda, PinName scl) : } void I2C::frequency(int hz) { + lock(); _hz = hz; // We want to update the frequency even if we are already the bus owners @@ -41,60 +45,88 @@ void I2C::frequency(int hz) { // Updating the frequency of the bus we become the owners of it _owner = this; + unlock(); } void I2C::aquire() { + lock(); if (_owner != this) { i2c_frequency(&_i2c, _hz); _owner = this; } + unlock(); } // write - Master Transmitter Mode int I2C::write(int address, const char* data, int length, bool repeated) { + lock(); aquire(); int stop = (repeated) ? 0 : 1; int written = i2c_write(&_i2c, address, data, length, stop); + unlock(); return length != written; } int I2C::write(int data) { - return i2c_byte_write(&_i2c, data); + lock(); + int ret = i2c_byte_write(&_i2c, data); + unlock(); + return ret; } // read - Master Reciever Mode int I2C::read(int address, char* data, int length, bool repeated) { + lock(); aquire(); int stop = (repeated) ? 0 : 1; int read = i2c_read(&_i2c, address, data, length, stop); + unlock(); return length != read; } int I2C::read(int ack) { + lock(); + int ret; if (ack) { - return i2c_byte_read(&_i2c, 0); + ret = i2c_byte_read(&_i2c, 0); } else { - return i2c_byte_read(&_i2c, 1); + ret = i2c_byte_read(&_i2c, 1); } + unlock(); + return ret; } void I2C::start(void) { + lock(); i2c_start(&_i2c); + unlock(); } void I2C::stop(void) { + lock(); i2c_stop(&_i2c); + unlock(); +} + +void I2C::lock() { + _mutex.lock(); +} + +void I2C::unlock() { + _mutex.unlock(); } #if DEVICE_I2C_ASYNCH int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t& callback, int event, bool repeated) { + lock(); if (i2c_active(&_i2c)) { + unlock(); return -1; // transaction ongoing } aquire(); @@ -103,12 +135,15 @@ int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_bu int stop = (repeated) ? 0 : 1; _irq.callback(&I2C::irq_handler_asynch); i2c_transfer_asynch(&_i2c, (void *)tx_buffer, tx_length, (void *)rx_buffer, rx_length, address, stop, _irq.entry(), event, _usage); + unlock(); return 0; } void I2C::abort_transfer(void) { + lock(); i2c_abort_asynch(&_i2c); + unlock(); } void I2C::irq_handler_asynch(void) diff --git a/hal/common/InterruptIn.cpp b/hal/common/InterruptIn.cpp index 414529869f2..d5df2fba766 100644 --- a/hal/common/InterruptIn.cpp +++ b/hal/common/InterruptIn.cpp @@ -23,23 +23,29 @@ InterruptIn::InterruptIn(PinName pin) : gpio(), gpio_irq(), _rise(), _fall() { + // No lock needed in the constructor gpio_irq_init(&gpio_irq, pin, (&InterruptIn::_irq_handler), (uint32_t)this); gpio_init_in(&gpio, pin); } InterruptIn::~InterruptIn() { + // No lock needed in the destructor gpio_irq_free(&gpio_irq); } int InterruptIn::read() { + // Read only return gpio_read(&gpio); } void InterruptIn::mode(PinMode pull) { + core_util_critical_section_enter(); gpio_mode(&gpio, pull); + core_util_critical_section_exit(); } void InterruptIn::rise(Callback func) { + core_util_critical_section_enter(); if (func) { _rise.attach(func); gpio_irq_set(&gpio_irq, IRQ_RISE, 1); @@ -47,9 +53,11 @@ void InterruptIn::rise(Callback func) { _rise.attach(NULL); gpio_irq_set(&gpio_irq, IRQ_RISE, 0); } + core_util_critical_section_exit(); } void InterruptIn::fall(Callback func) { + core_util_critical_section_enter(); if (func) { _fall.attach(func); gpio_irq_set(&gpio_irq, IRQ_FALL, 1); @@ -57,6 +65,7 @@ void InterruptIn::fall(Callback func) { _fall.attach(NULL); gpio_irq_set(&gpio_irq, IRQ_FALL, 0); } + core_util_critical_section_exit(); } void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) { @@ -69,15 +78,20 @@ void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) { } void InterruptIn::enable_irq() { + core_util_critical_section_enter(); gpio_irq_enable(&gpio_irq); + core_util_critical_section_exit(); } void InterruptIn::disable_irq() { + core_util_critical_section_enter(); gpio_irq_disable(&gpio_irq); + core_util_critical_section_exit(); } #ifdef MBED_OPERATORS InterruptIn::operator int() { + // Underlying call is atomic return read(); } #endif diff --git a/hal/common/InterruptManager.cpp b/hal/common/InterruptManager.cpp index 183404719f2..4f38475c2f3 100644 --- a/hal/common/InterruptManager.cpp +++ b/hal/common/InterruptManager.cpp @@ -2,6 +2,7 @@ #if defined(NVIC_NUM_VECTORS) #include "InterruptManager.h" +#include "critical.h" #include #define CHAIN_INITIAL_SIZE 4 @@ -13,12 +14,28 @@ typedef void (*pvoidf)(void); InterruptManager* InterruptManager::_instance = (InterruptManager*)NULL; InterruptManager* InterruptManager::get() { - if (NULL == _instance) - _instance = new InterruptManager(); + + if (NULL == _instance) { + InterruptManager* temp = new InterruptManager(); + + // Atomically set _instance + core_util_critical_section_enter(); + if (NULL == _instance) { + _instance = temp; + } + core_util_critical_section_exit(); + + // Another thread got there first so delete ours + if (temp != _instance) { + delete temp; + } + + } return _instance; } InterruptManager::InterruptManager() { + // No mutex needed in constructor memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain*)); } @@ -39,34 +56,44 @@ InterruptManager::~InterruptManager() { } bool InterruptManager::must_replace_vector(IRQn_Type irq) { - int irq_pos = get_irq_index(irq); + lock(); + int ret = false; + int irq_pos = get_irq_index(irq); if (NULL == _chains[irq_pos]) { _chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE); _chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq)); - return true; + ret = true; } - return false; + unlock(); + return ret; } pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front) { + lock(); int irq_pos = get_irq_index(irq); bool change = must_replace_vector(irq); pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function); if (change) NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper); + unlock(); return pf; } bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq) { int irq_pos = get_irq_index(irq); + bool ret = false; - if (NULL == _chains[irq_pos]) - return false; - if (!_chains[irq_pos]->remove(handler)) - return false; - return true; + lock(); + if (_chains[irq_pos] != NULL) { + if (_chains[irq_pos]->remove(handler)) { + ret = true; + } + } + unlock(); + + return ret; } void InterruptManager::irq_helper() { @@ -74,6 +101,7 @@ void InterruptManager::irq_helper() { } int InterruptManager::get_irq_index(IRQn_Type irq) { + // Pure function - no lock needed return (int)irq + NVIC_USER_IRQ_OFFSET; } @@ -81,6 +109,14 @@ void InterruptManager::static_irq_helper() { InterruptManager::get()->irq_helper(); } +void InterruptManager::lock() { + _mutex.lock(); +} + +void InterruptManager::unlock() { + _mutex.unlock(); +} + } // namespace mbed #endif diff --git a/hal/common/LocalFileSystem.cpp b/hal/common/LocalFileSystem.cpp index 9505d91a9a6..db0477fead8 100644 --- a/hal/common/LocalFileSystem.cpp +++ b/hal/common/LocalFileSystem.cpp @@ -108,6 +108,7 @@ FILEHANDLE local_file_open(const char* name, int flags) { } LocalFileHandle::LocalFileHandle(FILEHANDLE fh) : _fh(fh), pos(0) { + // No lock needed in constructor } int LocalFileHandle::close() { @@ -117,24 +118,32 @@ int LocalFileHandle::close() { } ssize_t LocalFileHandle::write(const void *buffer, size_t length) { + lock(); ssize_t n = semihost_write(_fh, (const unsigned char*)buffer, length, 0); // number of characters not written n = length - n; // number of characters written pos += n; + unlock(); return n; } ssize_t LocalFileHandle::read(void *buffer, size_t length) { + lock(); ssize_t n = semihost_read(_fh, (unsigned char*)buffer, length, 0); // number of characters not read n = length - n; // number of characters read pos += n; + unlock(); return n; } int LocalFileHandle::isatty() { - return semihost_istty(_fh); + lock(); + int ret = semihost_istty(_fh); + unlock(); + return ret; } off_t LocalFileHandle::lseek(off_t position, int whence) { + lock(); if (whence == SEEK_CUR) { position += pos; } else if (whence == SEEK_END) { @@ -144,15 +153,30 @@ off_t LocalFileHandle::lseek(off_t position, int whence) { /* Always seems to return -1, so just ignore for now. */ semihost_seek(_fh, position); pos = position; + unlock(); return position; } int LocalFileHandle::fsync() { - return semihost_ensure(_fh); + lock(); + int ret = semihost_ensure(_fh); + unlock(); + return ret; } off_t LocalFileHandle::flen() { - return semihost_flen(_fh); + lock(); + off_t off = semihost_flen(_fh); + unlock(); + return off; +} + +void LocalFileHandle::lock() { + _mutex.lock(); +} + +void LocalFileHandle::unlock() { + _mutex.unlock(); } class LocalDirHandle : public DirHandle { @@ -165,32 +189,56 @@ class LocalDirHandle : public DirHandle { } virtual int closedir() { + // No lock can be used in destructor delete this; return 0; } virtual struct dirent *readdir() { + lock(); if (xffind("*", &info)!=0) { + unlock(); return NULL; } memcpy(cur_entry.d_name, info.name, sizeof(info.name)); + unlock(); return &cur_entry; } virtual void rewinddir() { + lock(); info.fileID = 0; + unlock(); } virtual off_t telldir() { - return info.fileID; + lock(); + int fileId = info.fileID; + unlock(); + return fileId; } virtual void seekdir(off_t offset) { + lock(); info.fileID = offset; + unlock(); + } + +protected: + PlatformMutex _mutex; + + virtual void lock() { + _mutex.lock(); + } + + virtual void unlock() { + _mutex.unlock(); } }; FileHandle *LocalFileSystem::open(const char* name, int flags) { + // No global state modified so function is thread safe + /* reject filenames with / in them */ for (const char *tmp = name; *tmp; tmp++) { if (*tmp == '/') { @@ -211,10 +259,14 @@ FileHandle *LocalFileSystem::open(const char* name, int flags) { } int LocalFileSystem::remove(const char *filename) { + // No global state modified so function is thread safe + return semihost_remove(filename); } DirHandle *LocalFileSystem::opendir(const char *name) { + // No global state modified so function is thread safe + return new LocalDirHandle(); } diff --git a/hal/common/RawSerial.cpp b/hal/common/RawSerial.cpp index c3f8fdcd421..ace09134a95 100644 --- a/hal/common/RawSerial.cpp +++ b/hal/common/RawSerial.cpp @@ -24,19 +24,28 @@ namespace mbed { RawSerial::RawSerial(PinName tx, PinName rx) : SerialBase(tx, rx) { + // No lock needed in the constructor } int RawSerial::getc() { - return _base_getc(); + lock(); + int ret = _base_getc(); + unlock(); + return ret; } int RawSerial::putc(int c) { - return _base_putc(c); + lock(); + int ret = _base_putc(c); + unlock(); + return ret; } int RawSerial::puts(const char *str) { + lock(); while (*str) putc(*str ++); + unlock(); return 0; } @@ -45,6 +54,7 @@ int RawSerial::puts(const char *str) { // We only call malloc() for the sprintf() buffer if the buffer // length is above a certain threshold, otherwise we use just the stack. int RawSerial::printf(const char *format, ...) { + lock(); std::va_list arg; va_start(arg, format); // ARMCC microlib does not properly handle a size of 0. @@ -62,9 +72,22 @@ int RawSerial::printf(const char *format, ...) { delete[] temp; } va_end(arg); + unlock(); return len; } +/** Acquire exclusive access to this serial port + */ +void RawSerial::lock() { + // No lock used - external synchronization required +} + +/** Release exclusive access to this serial port + */ +void RawSerial::unlock() { + // No lock used - external synchronization required +} + } // namespace mbed #endif diff --git a/hal/common/SPI.cpp b/hal/common/SPI.cpp index 18d402e770b..7631a4c017b 100644 --- a/hal/common/SPI.cpp +++ b/hal/common/SPI.cpp @@ -33,38 +33,57 @@ SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) : _bits(8), _mode(0), _hz(1000000) { + // No lock needed in the constructor + spi_init(&_spi, mosi, miso, sclk, ssel); spi_format(&_spi, _bits, _mode, 0); spi_frequency(&_spi, _hz); } void SPI::format(int bits, int mode) { + lock(); _bits = bits; _mode = mode; SPI::_owner = NULL; // Not that elegant, but works. rmeyer aquire(); + unlock(); } void SPI::frequency(int hz) { + lock(); _hz = hz; SPI::_owner = NULL; // Not that elegant, but works. rmeyer aquire(); + unlock(); } SPI* SPI::_owner = NULL; // ignore the fact there are multiple physical spis, and always update if it wasnt us last void SPI::aquire() { + lock(); if (_owner != this) { spi_format(&_spi, _bits, _mode, 0); spi_frequency(&_spi, _hz); _owner = this; } + unlock(); } int SPI::write(int value) { + lock(); aquire(); - return spi_master_write(&_spi, value); + int ret = spi_master_write(&_spi, value); + unlock(); + return ret; +} + +void SPI::lock() { + _mutex.lock(); +} + +void SPI::unlock() { + _mutex.unlock(); } #if DEVICE_SPI_ASYNCH diff --git a/hal/common/Serial.cpp b/hal/common/Serial.cpp index 602c87a0a7c..5a53e32727a 100644 --- a/hal/common/Serial.cpp +++ b/hal/common/Serial.cpp @@ -24,13 +24,23 @@ Serial::Serial(PinName tx, PinName rx, const char *name) : SerialBase(tx, rx), S } int Serial::_getc() { + // Mutex is already held return _base_getc(); } int Serial::_putc(int c) { + // Mutex is already held return _base_putc(c); } +void Serial::lock() { + _mutex.lock(); +} + +void Serial::unlock() { + _mutex.unlock(); +} + } // namespace mbed #endif diff --git a/hal/common/SerialBase.cpp b/hal/common/SerialBase.cpp index 94eca327d95..891c4509751 100644 --- a/hal/common/SerialBase.cpp +++ b/hal/common/SerialBase.cpp @@ -15,6 +15,7 @@ */ #include "SerialBase.h" #include "wait_api.h" +#include "critical.h" #if DEVICE_SERIAL @@ -26,35 +27,52 @@ SerialBase::SerialBase(PinName tx, PinName rx) : _rx_usage(DMA_USAGE_NEVER), #endif _serial(), _baud(9600) { + // No lock needed in the constructor + serial_init(&_serial, tx, rx); serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this); } void SerialBase::baud(int baudrate) { + lock(); serial_baud(&_serial, baudrate); _baud = baudrate; + unlock(); } void SerialBase::format(int bits, Parity parity, int stop_bits) { + lock(); serial_format(&_serial, bits, (SerialParity)parity, stop_bits); + unlock(); } int SerialBase::readable() { - return serial_readable(&_serial); + lock(); + int ret = serial_readable(&_serial); + unlock(); + return ret; } int SerialBase::writeable() { - return serial_writable(&_serial); + lock(); + int ret = serial_writable(&_serial); + unlock(); + return ret; } void SerialBase::attach(Callback func, IrqType type) { + lock(); + // Disable interrupts when attaching interrupt handler + core_util_critical_section_enter(); if (func) { _irq[type].attach(func); serial_irq_set(&_serial, (SerialIrq)type, 1); } else { serial_irq_set(&_serial, (SerialIrq)type, 0); } + core_util_critical_section_exit(); + unlock(); } void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) { @@ -63,15 +81,18 @@ void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) { } int SerialBase::_base_getc() { + // Mutex is already held return serial_getc(&_serial); } int SerialBase::_base_putc(int c) { + // Mutex is already held serial_putc(&_serial, c); return c; } void SerialBase::send_break() { + lock(); // Wait for 1.5 frames before clearing the break condition // This will have different effects on our platforms, but should // ensure that we keep the break active for at least one frame. @@ -83,10 +104,20 @@ void SerialBase::send_break() { serial_break_set(&_serial); wait_us(18000000/_baud); serial_break_clear(&_serial); + unlock(); +} + +void SerialBase::lock() { + // Stub +} + +void SerialBase:: unlock() { + // Stub } #if DEVICE_SERIAL_FC void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) { + lock(); FlowControl flow_type = (FlowControl)type; switch(type) { case RTS: @@ -105,6 +136,7 @@ void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) { default: break; } + unlock(); } #endif diff --git a/hal/common/Stream.cpp b/hal/common/Stream.cpp index 2b3105f27c7..87ec7407bcb 100644 --- a/hal/common/Stream.cpp +++ b/hal/common/Stream.cpp @@ -18,6 +18,7 @@ namespace mbed { Stream::Stream(const char *name) : FileLike(name), _file(NULL) { + // No lock needed in constructor /* open ourselves */ char buf[12]; /* :0x12345678 + null byte */ std::sprintf(buf, ":%p", this); @@ -26,24 +27,37 @@ Stream::Stream(const char *name) : FileLike(name), _file(NULL) { } Stream::~Stream() { + // No lock can be used in destructor fclose(_file); } int Stream::putc(int c) { + lock(); fflush(_file); - return std::fputc(c, _file); + int ret = std::fputc(c, _file); + unlock(); + return ret; } int Stream::puts(const char *s) { + lock(); fflush(_file); - return std::fputs(s, _file); + int ret = std::fputs(s, _file); + unlock(); + return ret; } int Stream::getc() { + lock(); fflush(_file); - return mbed_getc(_file); + int ret = mbed_getc(_file); + unlock(); + return ret; } char* Stream::gets(char *s, int size) { + lock(); fflush(_file); - return mbed_gets(s,size,_file); + char *ret = mbed_gets(s,size,_file); + unlock(); + return ret; } int Stream::close() { @@ -53,22 +67,30 @@ int Stream::close() { ssize_t Stream::write(const void* buffer, size_t length) { const char* ptr = (const char*)buffer; const char* end = ptr + length; + + lock(); while (ptr != end) { if (_putc(*ptr++) == EOF) { break; } } + unlock(); + return ptr - (const char*)buffer; } ssize_t Stream::read(void* buffer, size_t length) { char* ptr = (char*)buffer; char* end = ptr + length; + + lock(); while (ptr != end) { int c = _getc(); if (c==EOF) break; *ptr++ = c; } + unlock(); + return ptr - (const char*)buffer; } @@ -89,32 +111,40 @@ off_t Stream::flen() { } int Stream::printf(const char* format, ...) { + lock(); std::va_list arg; va_start(arg, format); fflush(_file); int r = vfprintf(_file, format, arg); va_end(arg); + unlock(); return r; } int Stream::scanf(const char* format, ...) { + lock(); std::va_list arg; va_start(arg, format); fflush(_file); int r = vfscanf(_file, format, arg); va_end(arg); + unlock(); return r; } int Stream::vprintf(const char* format, std::va_list args) { + lock(); fflush(_file); int r = vfprintf(_file, format, args); + unlock(); return r; } int Stream::vscanf(const char* format, std::va_list args) { + lock(); fflush(_file); int r = vfscanf(_file, format, args); + unlock(); return r; } diff --git a/hal/common/Ticker.cpp b/hal/common/Ticker.cpp index 06abbb36295..87980db0479 100644 --- a/hal/common/Ticker.cpp +++ b/hal/common/Ticker.cpp @@ -18,18 +18,23 @@ #include "TimerEvent.h" #include "FunctionPointer.h" #include "ticker_api.h" +#include "critical.h" namespace mbed { void Ticker::detach() { + core_util_critical_section_enter(); remove(); _function.attach(0); + core_util_critical_section_exit(); } void Ticker::setup(timestamp_t t) { + core_util_critical_section_enter(); remove(); _delay = t; insert(_delay + ticker_read(_ticker_data)); + core_util_critical_section_exit(); } void Ticker::handler() { diff --git a/hal/common/Timer.cpp b/hal/common/Timer.cpp index a0846344554..c79acee5c4b 100644 --- a/hal/common/Timer.cpp +++ b/hal/common/Timer.cpp @@ -16,6 +16,7 @@ #include "Timer.h" #include "ticker_api.h" #include "us_ticker_api.h" +#include "critical.h" namespace mbed { @@ -28,19 +29,26 @@ Timer::Timer(const ticker_data_t *data) : _running(), _start(), _time(), _ticker } void Timer::start() { + core_util_critical_section_enter(); if (!_running) { _start = ticker_read(_ticker_data); _running = 1; } + core_util_critical_section_exit(); } void Timer::stop() { + core_util_critical_section_enter(); _time += slicetime(); - _running = 0; + _running = 0; + core_util_critical_section_exit(); } int Timer::read_us() { - return _time + slicetime(); + core_util_critical_section_enter(); + int time = _time + slicetime(); + core_util_critical_section_exit(); + return time; } float Timer::read() { @@ -52,16 +60,20 @@ int Timer::read_ms() { } int Timer::slicetime() { + core_util_critical_section_enter(); + int ret = 0; if (_running) { - return ticker_read(_ticker_data) - _start; - } else { - return 0; + ret = ticker_read(_ticker_data) - _start; } + core_util_critical_section_exit(); + return ret; } void Timer::reset() { + core_util_critical_section_enter(); _start = ticker_read(_ticker_data); _time = 0; + core_util_critical_section_exit(); } #ifdef MBED_OPERATORS diff --git a/hal/common/assert.c b/hal/common/assert.c index 51394707b08..2906c5e256d 100644 --- a/hal/common/assert.c +++ b/hal/common/assert.c @@ -16,17 +16,12 @@ #include "mbed_assert.h" #include "device.h" -#if DEVICE_STDIO_MESSAGES -#include -#endif - -#include #include "mbed_interface.h" +#include "critical.h" void mbed_assert_internal(const char *expr, const char *file, int line) { -#if DEVICE_STDIO_MESSAGES - fprintf(stderr, "mbed assertation failed: %s, file: %s, line %d \n", expr, file, line); -#endif + core_util_critical_section_enter(); + mbed_error_printf("mbed assertation failed: %s, file: %s, line %d \n", expr, file, line); mbed_die(); } diff --git a/hal/common/board.c b/hal/common/board.c index fa760e747b8..2cd5f5564bb 100644 --- a/hal/common/board.c +++ b/hal/common/board.c @@ -13,11 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include "gpio_api.h" #include "wait_api.h" #include "toolchain.h" #include "mbed_interface.h" #include "critical.h" +#include "serial_api.h" + +#if DEVICE_SERIAL +extern int stdio_uart_inited; +extern serial_t stdio_uart; +#endif WEAK void mbed_die(void) { #if !defined (NRF51_H) && !defined(TARGET_EFM32) @@ -58,3 +65,27 @@ WEAK void mbed_die(void) { wait_ms(150); } } + +void mbed_error_printf(const char* format, ...) { + va_list arg; + va_start(arg, format); + mbed_error_vfprintf(format, arg); + va_end(arg); +} + +void mbed_error_vfprintf(const char * format, va_list arg) { +#if DEVICE_SERIAL + core_util_critical_section_enter(); + char buffer[128]; + int size = vsprintf(buffer, format, arg); + if (size > 0) { + if (!stdio_uart_inited) { + serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); + } + for (int i = 0; i < size; i++) { + serial_putc(&stdio_uart, buffer[i]); + } + } + core_util_critical_section_exit(); +#endif +} diff --git a/hal/common/error.c b/hal/common/error.c index b307d87565d..faa1622e31c 100644 --- a/hal/common/error.c +++ b/hal/common/error.c @@ -23,11 +23,9 @@ #endif WEAK void error(const char* format, ...) { -#if DEVICE_STDIO_MESSAGES va_list arg; va_start(arg, format); - vfprintf(stderr, format, arg); + mbed_error_vfprintf(format, arg); va_end(arg); -#endif exit(1); } diff --git a/hal/common/retarget.cpp b/hal/common/retarget.cpp index 826c7815a34..9ea80f9abfe 100644 --- a/hal/common/retarget.cpp +++ b/hal/common/retarget.cpp @@ -50,6 +50,8 @@ # define PREFIX(x) x #endif +#define FILE_HANDLE_RESERVED 0xFFFFFFFF + using namespace mbed; #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) @@ -70,14 +72,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; FileHandle::~FileHandle() { + 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(); } #if DEVICE_SERIAL @@ -150,13 +155,17 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) { #endif // find the first empty slot in filehandles + 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(); return -1; } + filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED; + filehandle_mutex.unlock(); FileHandle *res; @@ -170,19 +179,29 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) { } else { FilePath path(name); - if (!path.exists()) + if (!path.exists()) { + // Free file handle + filehandles[fh_i] = NULL; return -1; - else if (path.isFile()) { + } else if (path.isFile()) { res = path.file(); } else { FileSystemLike *fs = path.fileSystem(); - if (fs == NULL) return -1; + if (fs == NULL) { + // Free file handle + filehandles[fh_i] = NULL; + return -1; + } int posix_mode = openmode_to_posix(openmode); res = fs->open(path.fileName(), posix_mode); /* NULL if fails */ } } - if (res == NULL) return -1; + if (res == NULL) { + // Free file handle + filehandles[fh_i] = NULL; + return -1; + } filehandles[fh_i] = res; return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err diff --git a/hal/common/rtc_time.c b/hal/common/rtc_time.c index 45499379158..3c2a5cca533 100644 --- a/hal/common/rtc_time.c +++ b/hal/common/rtc_time.c @@ -42,6 +42,7 @@ time_t time(time_t *timer) #endif { + core_util_critical_section_enter(); if (_rtc_isenabled != NULL) { if (!(_rtc_isenabled())) { set_time(0); @@ -56,21 +57,26 @@ time_t time(time_t *timer) if (timer != NULL) { *timer = t; } + core_util_critical_section_exit(); return t; } void set_time(time_t t) { + core_util_critical_section_enter(); if (_rtc_init != NULL) { _rtc_init(); } if (_rtc_write != NULL) { _rtc_write(t); } + core_util_critical_section_exit(); } clock_t clock() { + core_util_critical_section_enter(); clock_t t = us_ticker_read(); t /= 1000000 / CLOCKS_PER_SEC; // convert to processor time + core_util_critical_section_exit(); return t; } diff --git a/libraries/fs/fat/FATDirHandle.cpp b/libraries/fs/fat/FATDirHandle.cpp index 19dbb14bc35..7c0e9ddb7ed 100644 --- a/libraries/fs/fat/FATDirHandle.cpp +++ b/libraries/fs/fat/FATDirHandle.cpp @@ -25,12 +25,14 @@ using namespace mbed; -FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir) { +FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir, PlatformMutex * mutex): _mutex(mutex) { dir = the_dir; } int FATDirHandle::closedir() { + lock(); int retval = f_closedir(&dir); + unlock(); delete this; return retval; } @@ -38,6 +40,7 @@ int FATDirHandle::closedir() { struct dirent *FATDirHandle::readdir() { FILINFO finfo; + lock(); #if _USE_LFN finfo.lfname = cur_entry.d_name; finfo.lfsize = sizeof(cur_entry.d_name); @@ -47,33 +50,52 @@ struct dirent *FATDirHandle::readdir() { #if _USE_LFN if(res != 0 || finfo.fname[0]==0) { + unlock(); return NULL; } else { if(cur_entry.d_name[0]==0) { // No long filename so use short filename. memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname)); } + unlock(); return &cur_entry; } #else if(res != 0 || finfo.fname[0]==0) { + unlock(); return NULL; } else { memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname)); + unlock(); return &cur_entry; } #endif /* _USE_LFN */ } void FATDirHandle::rewinddir() { + lock(); dir.index = 0; + unlock(); } off_t FATDirHandle::telldir() { - return dir.index; + lock(); + off_t offset = dir.index; + unlock(); + return offset; } void FATDirHandle::seekdir(off_t location) { + lock(); dir.index = location; + unlock(); +} + +void FATDirHandle::lock() { + _mutex->lock(); +} + +void FATDirHandle::unlock() { + _mutex->unlock(); } diff --git a/libraries/fs/fat/FATDirHandle.h b/libraries/fs/fat/FATDirHandle.h index 25ececacf3d..bb6ead342bf 100644 --- a/libraries/fs/fat/FATDirHandle.h +++ b/libraries/fs/fat/FATDirHandle.h @@ -23,19 +23,27 @@ #define MBED_FATDIRHANDLE_H #include "DirHandle.h" +#include "platform.h" using namespace mbed; class FATDirHandle : public DirHandle { public: - FATDirHandle(const FATFS_DIR &the_dir); + FATDirHandle(const FATFS_DIR &the_dir, PlatformMutex * mutex); virtual int closedir(); virtual struct dirent *readdir(); virtual void rewinddir(); virtual off_t telldir(); virtual void seekdir(off_t location); + protected: + + virtual void lock(); + virtual void unlock(); + + PlatformMutex * _mutex; + private: FATFS_DIR dir; struct dirent cur_entry; diff --git a/libraries/fs/fat/FATFileHandle.cpp b/libraries/fs/fat/FATFileHandle.cpp index 8c2bf881e4f..f5ae95b7e37 100644 --- a/libraries/fs/fat/FATFileHandle.cpp +++ b/libraries/fs/fat/FATFileHandle.cpp @@ -25,34 +25,42 @@ #include "FATFileHandle.h" -FATFileHandle::FATFileHandle(FIL fh) { +FATFileHandle::FATFileHandle(FIL fh, PlatformMutex * mutex): _mutex(mutex) { _fh = fh; } int FATFileHandle::close() { + lock(); int retval = f_close(&_fh); + unlock(); delete this; return retval; } ssize_t FATFileHandle::write(const void* buffer, size_t length) { + lock(); UINT n; FRESULT res = f_write(&_fh, buffer, length, &n); if (res) { debug_if(FFS_DBG, "f_write() failed: %d", res); + unlock(); return -1; } + unlock(); return n; } ssize_t FATFileHandle::read(void* buffer, size_t length) { + lock(); debug_if(FFS_DBG, "read(%d)\n", length); UINT n; FRESULT res = f_read(&_fh, buffer, length, &n); if (res) { debug_if(FFS_DBG, "f_read() failed: %d\n", res); + unlock(); return -1; } + unlock(); return n; } @@ -61,6 +69,7 @@ int FATFileHandle::isatty() { } off_t FATFileHandle::lseek(off_t position, int whence) { + lock(); if (whence == SEEK_END) { position += _fh.fsize; } else if(whence==SEEK_CUR) { @@ -69,22 +78,38 @@ off_t FATFileHandle::lseek(off_t position, int whence) { FRESULT res = f_lseek(&_fh, position); if (res) { debug_if(FFS_DBG, "lseek failed: %d\n", res); + unlock(); return -1; } else { debug_if(FFS_DBG, "lseek OK, returning %i\n", _fh.fptr); + unlock(); return _fh.fptr; } } int FATFileHandle::fsync() { + lock(); FRESULT res = f_sync(&_fh); if (res) { debug_if(FFS_DBG, "f_sync() failed: %d\n", res); + unlock(); return -1; } + unlock(); return 0; } off_t FATFileHandle::flen() { - return _fh.fsize; + lock(); + off_t size = _fh.fsize; + unlock(); + return size; +} + +void FATFileHandle::lock() { + _mutex->lock(); +} + +void FATFileHandle::unlock() { + _mutex->unlock(); } diff --git a/libraries/fs/fat/FATFileHandle.h b/libraries/fs/fat/FATFileHandle.h index d41592f9c3e..5365197a12f 100644 --- a/libraries/fs/fat/FATFileHandle.h +++ b/libraries/fs/fat/FATFileHandle.h @@ -23,13 +23,14 @@ #define MBED_FATFILEHANDLE_H #include "FileHandle.h" +#include "platform.h" using namespace mbed; class FATFileHandle : public FileHandle { public: - FATFileHandle(FIL fh); + FATFileHandle(FIL fh, PlatformMutex * mutex); virtual int close(); virtual ssize_t write(const void* buffer, size_t length); virtual ssize_t read(void* buffer, size_t length); @@ -40,7 +41,11 @@ class FATFileHandle : public FileHandle { protected: + virtual void lock(); + virtual void unlock(); + FIL _fh; + PlatformMutex * _mutex; }; diff --git a/libraries/fs/fat/FATFileSystem.cpp b/libraries/fs/fat/FATFileSystem.cpp index 4d877d9805e..db33546bff3 100644 --- a/libraries/fs/fat/FATFileSystem.cpp +++ b/libraries/fs/fat/FATFileSystem.cpp @@ -27,6 +27,7 @@ #include "FATFileSystem.h" #include "FATFileHandle.h" #include "FATDirHandle.h" +#include "critical.h" DWORD get_fattime(void) { time_t rawtime; @@ -41,33 +42,55 @@ DWORD get_fattime(void) { } FATFileSystem *FATFileSystem::_ffs[_VOLUMES] = {0}; +static PlatformMutex * mutex = NULL; -FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) { +PlatformMutex * get_fat_mutex() { + PlatformMutex * new_mutex = new PlatformMutex; + + core_util_critical_section_enter(); + if (NULL == mutex) { + mutex = new_mutex; + } + core_util_critical_section_exit(); + + if (mutex != new_mutex) { + delete new_mutex; + } + return mutex; +} + +FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n), _mutex(get_fat_mutex()) { + lock(); debug_if(FFS_DBG, "FATFileSystem(%s)\n", n); for(int i=0; i<_VOLUMES; i++) { if(_ffs[i] == 0) { _ffs[i] = this; _fsid[0] = '0' + i; _fsid[1] = '\0'; - debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", _name, _fsid); + debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid); f_mount(&_fs, _fsid, 0); + unlock(); return; } } error("Couldn't create %s in FATFileSystem::FATFileSystem\n", n); + unlock(); } FATFileSystem::~FATFileSystem() { + lock(); for (int i=0; i<_VOLUMES; i++) { if (_ffs[i] == this) { _ffs[i] = 0; f_mount(NULL, _fsid, 0); } } + unlock(); } FileHandle *FATFileSystem::open(const char* name, int flags) { - debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", name, _name, _fsid); + lock(); + debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", name, getName(), _fsid); char n[64]; sprintf(n, "%s:/%s", _fsid, name); @@ -92,63 +115,95 @@ FileHandle *FATFileSystem::open(const char* name, int flags) { FRESULT res = f_open(&fh, n, openmode); if (res) { debug_if(FFS_DBG, "f_open('w') failed: %d\n", res); + unlock(); return NULL; } if (flags & O_APPEND) { f_lseek(&fh, fh.fsize); } - return new FATFileHandle(fh); + FATFileHandle * handle = new FATFileHandle(fh, _mutex); + unlock(); + return handle; } int FATFileSystem::remove(const char *filename) { + lock(); FRESULT res = f_unlink(filename); if (res) { debug_if(FFS_DBG, "f_unlink() failed: %d\n", res); + unlock(); return -1; } + unlock(); return 0; } int FATFileSystem::rename(const char *oldname, const char *newname) { + lock(); FRESULT res = f_rename(oldname, newname); if (res) { debug_if(FFS_DBG, "f_rename() failed: %d\n", res); + unlock(); return -1; } + unlock(); return 0; } int FATFileSystem::format() { + lock(); FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster) if (res) { debug_if(FFS_DBG, "f_mkfs() failed: %d\n", res); + unlock(); return -1; } + unlock(); return 0; } DirHandle *FATFileSystem::opendir(const char *name) { + lock(); FATFS_DIR dir; FRESULT res = f_opendir(&dir, name); if (res != 0) { + unlock(); return NULL; } - return new FATDirHandle(dir); + FATDirHandle *handle = new FATDirHandle(dir, _mutex); + unlock(); + return handle; } int FATFileSystem::mkdir(const char *name, mode_t mode) { + lock(); FRESULT res = f_mkdir(name); + unlock(); return res == 0 ? 0 : -1; } int FATFileSystem::mount() { + lock(); FRESULT res = f_mount(&_fs, _fsid, 1); + unlock(); return res == 0 ? 0 : -1; } int FATFileSystem::unmount() { - if (disk_sync()) + lock(); + if (disk_sync()) { + unlock(); return -1; + } FRESULT res = f_mount(NULL, _fsid, 0); + unlock(); return res == 0 ? 0 : -1; } + +void FATFileSystem::lock() { + _mutex->lock(); +} + +void FATFileSystem::unlock() { + _mutex->unlock(); +} diff --git a/libraries/fs/fat/FATFileSystem.h b/libraries/fs/fat/FATFileSystem.h index 0052756e567..8125ab26017 100644 --- a/libraries/fs/fat/FATFileSystem.h +++ b/libraries/fs/fat/FATFileSystem.h @@ -26,6 +26,7 @@ #include "FileHandle.h" #include "ff.h" #include +#include "platform.h" using namespace mbed; @@ -89,6 +90,15 @@ class FATFileSystem : public FileSystemLike { virtual int disk_sync() { return 0; } virtual uint32_t disk_sectors() = 0; +protected: + + virtual void lock(); + virtual void unlock(); + +private: + + PlatformMutex *_mutex; + }; #endif diff --git a/libraries/fs/sd/SDFileSystem.cpp b/libraries/fs/sd/SDFileSystem.cpp index 27a698d42a5..91310c32e9f 100644 --- a/libraries/fs/sd/SDFileSystem.cpp +++ b/libraries/fs/sd/SDFileSystem.cpp @@ -148,11 +148,13 @@ SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, int SDFileSystem::initialise_card() { // Set to SCK for initialisation, and clock card with cs = 1 + _spi.lock(); _spi.frequency(_init_sck); _cs = 1; for (int i = 0; i < 16; i++) { _spi.write(0xFF); } + _spi.unlock(); // send CMD0, should return with all zeros except IDLE STATE set (bit 0) if (_cmd(0, 0) != R1_IDLE_STATE) { @@ -204,9 +206,11 @@ int SDFileSystem::initialise_card_v2() { } int SDFileSystem::disk_initialize() { + lock(); _is_initialized = initialise_card(); if (_is_initialized == 0) { debug("Fail to initialize card\n"); + unlock(); return 1; } debug_if(SD_DBG, "init card = %d\n", _is_initialized); @@ -215,22 +219,27 @@ int SDFileSystem::disk_initialize() { // Set block length to 512 (CMD16) if (_cmd(16, 512) != 0) { debug("Set 512-byte block timed out\n"); + unlock(); return 1; } // Set SCK for data transfer _spi.frequency(_transfer_sck); + unlock(); return 0; } int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count) { + lock(); if (!_is_initialized) { + unlock(); return -1; } for (uint32_t b = block_number; b < block_number + count; b++) { // set write address for single block (CMD24) if (_cmd(24, b * cdv) != 0) { + unlock(); return 1; } @@ -239,17 +248,21 @@ int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t block_number, uint3 buffer += 512; } + unlock(); return 0; } int SDFileSystem::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count) { + lock(); if (!_is_initialized) { + unlock(); return -1; } for (uint32_t b = block_number; b < block_number + count; b++) { // set read address for single block (CMD17) if (_cmd(17, b * cdv) != 0) { + unlock(); return 1; } @@ -258,24 +271,30 @@ int SDFileSystem::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t cou buffer += 512; } + unlock(); return 0; } int SDFileSystem::disk_status() { + lock(); // FATFileSystem::disk_status() returns 0 when initialized - if (_is_initialized) { - return 0; - } else { - return 1; - } + int ret = _is_initialized ? 0 : 1; + unlock(); + return ret; } int SDFileSystem::disk_sync() { return 0; } -uint32_t SDFileSystem::disk_sectors() { return _sectors; } +uint32_t SDFileSystem::disk_sectors() { + lock(); + uint32_t sectors = _sectors; + unlock(); + return sectors; +} // PRIVATE FUNCTIONS int SDFileSystem::_cmd(int cmd, int arg) { + _spi.lock(); _cs = 0; // send a command @@ -292,14 +311,17 @@ int SDFileSystem::_cmd(int cmd, int arg) { if (!(response & 0x80)) { _cs = 1; _spi.write(0xFF); + _spi.unlock(); return response; } } _cs = 1; _spi.write(0xFF); + _spi.unlock(); return -1; // timeout } int SDFileSystem::_cmdx(int cmd, int arg) { + _spi.lock(); _cs = 0; // send a command @@ -314,16 +336,20 @@ int SDFileSystem::_cmdx(int cmd, int arg) { for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { int response = _spi.write(0xFF); if (!(response & 0x80)) { + _cs = 1; + _spi.unlock(); return response; } } _cs = 1; _spi.write(0xFF); + _spi.unlock(); return -1; // timeout } int SDFileSystem::_cmd58() { + _spi.lock(); _cs = 0; int arg = 0; @@ -345,15 +371,18 @@ int SDFileSystem::_cmd58() { ocr |= _spi.write(0xFF) << 0; _cs = 1; _spi.write(0xFF); + _spi.unlock(); return response; } } _cs = 1; _spi.write(0xFF); + _spi.unlock(); return -1; // timeout } int SDFileSystem::_cmd8() { + _spi.lock(); _cs = 0; // send a command @@ -374,15 +403,18 @@ int SDFileSystem::_cmd8() { } _cs = 1; _spi.write(0xFF); + _spi.unlock(); return response[0]; } } _cs = 1; _spi.write(0xFF); + _spi.unlock(); return -1; // timeout } int SDFileSystem::_read(uint8_t *buffer, uint32_t length) { + _spi.lock(); _cs = 0; // read until start byte (0xFF) @@ -397,10 +429,12 @@ int SDFileSystem::_read(uint8_t *buffer, uint32_t length) { _cs = 1; _spi.write(0xFF); + _spi.unlock(); return 0; } int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) { + _spi.lock(); _cs = 0; // indicate start of block @@ -419,6 +453,7 @@ int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) { if ((_spi.write(0xFF) & 0x1F) != 0x05) { _cs = 1; _spi.write(0xFF); + _spi.unlock(); return 1; } @@ -427,6 +462,7 @@ int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) { _cs = 1; _spi.write(0xFF); + _spi.unlock(); return 0; }