├── .gitignore ├── CHANGELOG.md ├── DOXYGEN_FRONTPAGE.md ├── LICENSE ├── README.md ├── apache-2.0.txt ├── core-util ├── Array.h ├── BinaryHeap.h ├── CriticalSectionLock.h ├── Event.h ├── ExtendablePoolAllocator.h ├── FunctionPointer.h ├── FunctionPointerBase.h ├── FunctionPointerBind.h ├── PoolAllocator.h ├── SharedPointer.h ├── assert.h ├── atomic_ops.h ├── core-util.h ├── critical.h ├── sbrk.h └── uninitialized.h ├── coverage.json ├── module.json ├── source ├── ExtendablePoolAllocator.cpp ├── PoolAllocator.cpp ├── assert_mbed.c ├── assert_posix.c ├── atomic_ops.cpp ├── critical.c ├── critical_nordic.c ├── critical_posix.c └── sbrk.cpp └── test ├── Array └── main.cpp ├── BinaryHeap └── main.cpp ├── EventHandler └── main.cpp ├── ExtendablePoolAllocator └── main.cpp ├── FunctionPointer ├── int_types.cpp ├── int_types.hpp ├── lifetime.cpp ├── lifetime.hpp ├── main.cpp ├── side_effects.cpp └── side_effects.hpp ├── PoolAllocator └── main.cpp ├── SharedPointer └── main.cpp ├── sbrk-mini └── main.cpp └── uninitialized └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | yotta_modules/ 2 | yotta_targets/ 3 | build/ 4 | .yotta.json 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [Unreleased] 6 | ### Fixed 7 | - A race condition in `PoolAllocator::alloc()` 8 | 9 | 10 | ## [1.6.0] 2016-03-07 11 | ### Fixed 12 | - Tests updated to use greentea client 13 | 14 | ## [1.5.4] 2016-03-04 15 | ### Fixed 16 | - comment out assert in the critical section 17 | 18 | ## [1.5.3] 2016-03-02 19 | ### Fixed 20 | - CriticalSectionLock to use the C based solution within the clas 21 | 22 | ### Added 23 | - C critical section for nrf51 targets 24 | - C critical section for posix targets 25 | 26 | ## [1.5.2] 2016-03-01 27 | ### Fixed 28 | - Allocators aligned to 8 29 | - nrf51 critical section - fixes use with the softdevice disabled 30 | 31 | ## [1.5.1] 2016-02-29 32 | ### Release 33 | - mbed-drivers update dependency to 1.0.0 34 | 35 | ## [1.5.0] 2016-02-26 36 | ### Added 37 | - C re-entrant critical section 38 | 39 | ## [1.4.0] 2016-02-24 40 | ### Fixed 41 | - sbrk - align + set to minimum size negative sizes 42 | - Test function pointer - set baud rate removal 43 | 44 | ## [1.3.0] 2016-02-15 45 | ### Added 46 | - Add support for uninitialized data sections 47 | 48 | ## [1.2.0] 2016-02-01 49 | ### Release 50 | - mbed-drivers update dependency to ~0.12.0 51 | 52 | ## [1.1.5] 2016-01-27 53 | ### Added 54 | - Array, binaryHeap and pool allocators - forbid copying 55 | 56 | ## [1.1.4] 2016-01-20 57 | ### Fixed 58 | - Newline termination for runtime errors 59 | 60 | ## [1.1.3] 2016-01-19 61 | ### Added 62 | - Optimized specializations of atomic ops 63 | 64 | ## [1.1.3] 2016-01-19 65 | ### Fixed 66 | - Add missing template specialization prototypes 67 | 68 | ## [1.1.1] 2016-01-14 69 | ### Fixed 70 | - Shared pointer - API documentation 71 | 72 | ## [1.1.0] - 2016-01-11 73 | ### Fixed 74 | - Function pointer - fix arguments (all types of arguments, including references) 75 | 76 | ### Changed 77 | - core-util.h rename to assert.h 78 | 79 | [Unreleased]: https://github.com/ARMmbed/core-util/compare/HEAD...v1.6.0 80 | [1.6.0]: https://github.com/ARMmbed/core-util/compare/v1.5.4..v1.6.0 81 | [1.5.4]: https://github.com/ARMmbed/core-util/compare/v1.5.3...v1.5.4 82 | [1.5.3]: https://github.com/ARMmbed/core-util/compare/v1.5.2...v1.5.3 83 | [1.5.2]: https://github.com/ARMmbed/core-util/compare/v1.5.1...v1.5.2 84 | [1.5.1]: https://github.com/ARMmbed/core-util/compare/v1.5.0...v1.5.1 85 | [1.5.0]: https://github.com/ARMmbed/core-util/compare/v1.4.0...v1.5.0 86 | [1.4.0]: https://github.com/ARMmbed/core-util/compare/v1.3.0...v1.4.0 87 | [1.3.0]: https://github.com/ARMmbed/core-util/compare/v1.2.0...v1.3.0 88 | [1.2.0]: https://github.com/ARMmbed/core-util/compare/v1.1.5...v1.2.0 89 | [1.1.5]: https://github.com/ARMmbed/core-util/compare/v1.1.4...v1.1.5 90 | [1.1.4]: https://github.com/ARMmbed/core-util/compare/v1.1.3...v1.1.4 91 | [1.1.3]: https://github.com/ARMmbed/core-util/compare/v1.1.2...v1.1.3 92 | [1.1.2]: https://github.com/ARMmbed/core-util/compare/v1.1.1...v1.1.2 93 | [1.1.1]: https://github.com/ARMmbed/core-util/compare/v1.1.1...v1.1.1 94 | [1.1.0]: https://github.com/ARMmbed/core-util/compare/v1.1.0...v1.0.0 95 | -------------------------------------------------------------------------------- /DOXYGEN_FRONTPAGE.md: -------------------------------------------------------------------------------- 1 | # mbed utilities library 2 | 3 | Implementation of various generic data structures and algorithms used in mbed. 4 | 5 | # Configuration 6 | Some parameters of the core-util library can be configured in yotta. Currently, core-util supports configuring two things: the argument storage size of FunctionPointerBind and whether or not FunctionPointer checks its arguments before calling 7 | 8 | ## Configuring the storage size for FunctionPointerBind's bound arguments 9 | In some cases it may be necessary to increase FunctionPointerBind's argument size. In others, for memory optimization, it may be necessary to decrease the size of FunctionPointerBind's bound arguments. If either of these are necessary, adding a new key with yotta config will allow this configuration: ```"util": {"functionPointer":{"arg-storage" : }}```. 10 | 11 | ## Configuring whether or not FunctionPointer checks its arguments before calling 12 | For debug purposes, it is possible to have FunctionPointer check its arguments before being called. If it checks its arguments, it will use a ```CORE_UTIL_ASSERT```. Checks can be disabled with: ```"util": {"functionPointer":{"disable-null-check" : true}}``` 13 | 14 | # Atomic operations 15 | This module provides three atomic primitives: 16 | 17 | * ```atomic_cas``` 18 | * ```atomic_incr``` 19 | * ```atomic_decr``` 20 | 21 | The most versatile API is ```atomic_cas``` which provides the facility to implement any other atomic API. The base versions of ```atomic_incr``` and ```atomic_decr``` are implemented using ```atomic_cas```. 22 | 23 | ## Writing atomic operations 24 | It is possible to implement all atomic operations using ```atomic_cas``` and this API is portable across platforms. When writing a new atomic operation, best practice is to implement it using existing atomic operations, which are cross-platform. If an optimization is needed, then it should be a specialization of the portable implementation, which compiles for a specific target. 25 | 26 | ### Example of writing an atomic operation 27 | To illustrate how to write an atomic operation, consider ```atomic_add```. The signature of ```atomic_add``` will be: 28 | 29 | ```C++ 30 | /** 31 | * atomic_add 32 | * Add a non-atomic value to an atomic variable and store the result back to the atomic variable. 33 | * @param[in,out] ptr The atomic variable 34 | * @param[in] val The non-atomic value 35 | * 36 | * @return the value of the atomic variable after the addition 37 | */ 38 | template 39 | T atomic_add(T * ptr, T val); 40 | ``` 41 | 42 | The first implementation for this API is the generic, portable implementation: 43 | 44 | ```C++ 45 | template 46 | T atomic_add(T * ptr, T val) 47 | { 48 | T oldValue = *ptr; 49 | T newValue; 50 | do { 51 | newValue = oldValue + val; 52 | //This compares oldValue to *ptr, and updates oldValue if *ptr has changed 53 | } while (!atomic_cas(ptr, &oldValue, newValue)); 54 | return newValue; 55 | } 56 | ``` 57 | 58 | If a more optimized version is required, the next step is to provide a template specialization which is conditionally selected, based on the processor. The specialization must be declared in the ```atomic_ops.h``` header, and the implementation must be defined in the ```atomic_ops.cpp``` source file. 59 | 60 | Here is an example implementation: 61 | 62 | ```C++ 63 | #if (__CORTEX_M >= 0x03) 64 | template<> 65 | uint32_t atomic_add(uint32_t * ptr, uint32_t val) 66 | { 67 | uint32_t newValue; 68 | do { 69 | newValue = __LDREXW(ptr) + val; 70 | } while (__STREXW(newValue, ptr)); 71 | return newValue; 72 | } 73 | #endif 74 | ``` 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Unless specifically indicated otherwise in a file, files are licensed 2 | under the Apache 2.0 license, as can be found in: apache-2.0.txt 3 | 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Deprecation note! 2 | 3 | **Please note: this repository is deprecated and is no longer actively maintained**. 4 | 5 | # Mbed 3 utilities library 6 | 7 | Implementation of various generic data structures and algorithms used in mbed. 8 | 9 | # Configuration 10 | Some parameters of the core-util library can be configured in yotta. Currently, core-util supports configuring two things: the argument storage size of FunctionPointerBind and whether or not FunctionPointer checks its arguments before calling 11 | 12 | ## Configuring the storage size for FunctionPointerBind's bound arguments 13 | In some cases it may be necessary to increase FunctionPointerBind's argument size. In others, for memory optimization, it may be necessary to decrease the size of FunctionPointerBind's bound arguments. If either of these are necessary, adding a new key with yotta config will allow this configuration: ```"util": {"functionPointer":{"arg-storage" : }}```. 14 | 15 | ## Configuring whether or not FunctionPointer checks its arguments before calling 16 | For debug purposes, it is possible to have FunctionPointer check its arguments before being called. If it checks its arguments, it will use a ```CORE_UTIL_ASSERT```. Checks can be disabled with: ```"util": {"functionPointer":{"disable-null-check" : true}}``` 17 | 18 | # Atomic operations 19 | This module provides three atomic primitives: 20 | 21 | * ```atomic_cas``` 22 | * ```atomic_incr``` 23 | * ```atomic_decr``` 24 | 25 | The most versatile API is ```atomic_cas``` which provides the facility to implement any other atomic API. The base versions of ```atomic_incr``` and ```atomic_decr``` are implemented using ```atomic_cas```. 26 | 27 | ## Writing atomic operations 28 | It is possible to implement all atomic operations using ```atomic_cas``` and this API is portable across platforms. When writing a new atomic operation, best practice is to implement it using existing atomic operations, which are cross-platform. If an optimization is needed, then it should be a specialization of the portable implementation, which compiles for a specific target. 29 | 30 | ### Example of writing an atomic operation 31 | To illustrate how to write an atomic operation, consider ```atomic_add```. The signature of ```atomic_add``` will be: 32 | 33 | ```C++ 34 | /** 35 | * atomic_add 36 | * Add a non-atomic value to an atomic variable and store the result back to the atomic variable. 37 | * @param[in,out] ptr The atomic variable 38 | * @param[in] val The non-atomic value 39 | * 40 | * @return the value of the atomic variable after the addition 41 | */ 42 | template 43 | T atomic_add(T * ptr, T val); 44 | ``` 45 | 46 | The first implementation for this API is the generic, portable implementation: 47 | 48 | ```C++ 49 | template 50 | T atomic_add(T * ptr, T val) 51 | { 52 | T oldValue = *ptr; 53 | T newValue; 54 | do { 55 | newValue = oldValue + val; 56 | //This compares oldValue to *ptr, and updates oldValue if *ptr has changed 57 | } while (!atomic_cas(ptr, &oldValue, newValue)); 58 | return newValue; 59 | } 60 | ``` 61 | 62 | If a more optimized version is required, the next step is to provide a template specialization which is conditionally selected, based on the processor. The specialization must be declared in the ```atomic_ops.h``` header, and the implementation must be defined in the ```atomic_ops.cpp``` source file. 63 | 64 | Here is an example implementation: 65 | 66 | ```C++ 67 | #if (__CORTEX_M >= 0x03) 68 | template<> 69 | uint32_t atomic_add(uint32_t * ptr, uint32_t val) 70 | { 71 | uint32_t newValue; 72 | do { 73 | newValue = __LDREXW(ptr) + val; 74 | } while (__STREXW(newValue, ptr)); 75 | return newValue; 76 | } 77 | #endif 78 | ``` 79 | -------------------------------------------------------------------------------- /apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 ARM Limited 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /core-util/Array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __MBED_UTIL_ARRAY_H__ 19 | #define __MBED_UTIL_ARRAY_H__ 20 | 21 | #include 22 | #include 23 | #include "core-util/CriticalSectionLock.h" 24 | #include "core-util/PoolAllocator.h" 25 | #include "core-util/assert.h" 26 | #include "ualloc/ualloc.h" 27 | 28 | 29 | namespace mbed { 30 | namespace util { 31 | 32 | /** A reentrant Array class (elements can be accessed by index). It holds copies of the given type (T). 33 | * 34 | * The 'push_back' function can be used to add new entries to the array. If there's not enough space 35 | * available, the Array will try to allocate more memory and grow automatically. The array can only 36 | * grow, never shrink. 37 | * 38 | * This is not a sparse array. Trying to access elements outside the current array size will result 39 | * in a runtime error or cause undefined behaviour. 40 | * 41 | * If the templated type is a class or a struct, it needs to have a copy constructor 42 | */ 43 | template 44 | class Array { 45 | public: 46 | /** Create a new array 47 | */ 48 | Array() {} 49 | 50 | /* Forbid copy and assignment */ 51 | Array(const Array&) = delete; 52 | Array(Array&&) = delete; 53 | Array& operator =(const Array&) = delete; 54 | Array& operator =(Array&&) = delete; 55 | 56 | ~Array() { 57 | // We have copies of elements of type T in our array, so destroy them first 58 | for (unsigned i = 0; i < _elements; i ++) { 59 | T *p = get_element_address(i); 60 | p->~T(); 61 | } 62 | // Now it's safe to destroy our internal data structures 63 | array_link *crt = _head, *prev; 64 | while (crt != NULL) { 65 | prev = crt->prev; 66 | void *addr = crt->data; 67 | crt->~array_link(); // not really needed, just for completion 68 | mbed_ufree(addr); 69 | crt = prev; 70 | } 71 | } 72 | 73 | /** Initialize the array 74 | * @param initial_capacity initial number of elements in the array 75 | * @param grow_capacity number of elements to add when the array runs out of memory 76 | * @param alloc_traits allocator traits (for mbed_ualloc) 77 | * @param alignment alignment of each element in the array 78 | * @returns true if the initialization succeeded, false otherwise 79 | */ 80 | bool init(size_t initial_capacity, size_t grow_capacity, UAllocTraits_t alloc_traits, unsigned alignment = MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN) { 81 | if (_head != NULL) 82 | return false; // prevent repeated initialization 83 | _element_size = PoolAllocator::align_up(sizeof(T), alignment); 84 | _grow_capacity = grow_capacity; 85 | _alloc_traits = alloc_traits; 86 | _alignment = alignment; 87 | _capacity = initial_capacity; 88 | _elements = 0; 89 | _head = create_new_array(initial_capacity); 90 | return _head != NULL; 91 | } 92 | 93 | /** Subscript operator: return a reference to an existing element 94 | * Calling this function with an invalid index results in undefined behaviour! 95 | * @param index element index 96 | * @returns reference to the element at 'idx' 97 | */ 98 | T& operator [](unsigned idx) { 99 | return *get_element_address(idx); 100 | } 101 | 102 | /** Subscript operator: return a reference to an existing element (const version) 103 | * Calling this function with an invalid index results in undefined behaviour! 104 | * @param index element index 105 | * @returns constreference to the element at 'idx' 106 | */ 107 | const T& operator [](unsigned idx) const { 108 | return *get_element_address(idx); 109 | } 110 | 111 | /** Return a reference to an existing element 112 | * Calling this function with an invalid index results in a runtime error. 113 | * @param index element index 114 | * @returns reference to the element at 'idx' 115 | */ 116 | T& at(unsigned idx) { 117 | check_access(idx); 118 | return *get_element_address(idx); 119 | } 120 | 121 | /** Return a reference to an existing element (const version) 122 | * Calling this function with an invalid index results in a runtime error. 123 | * @param index element index 124 | * @returns const reference to the element at 'idx' 125 | */ 126 | const T& at(unsigned idx) const { 127 | check_access(idx); 128 | return *get_element_address(idx); 129 | } 130 | 131 | /** Adds an element at the end of the array 132 | * If there's not enough memory for a new element, a new zone will be allocated 133 | * @param new_element element to add 134 | * @returns true if the element was added, false otherwise (out of memory/uninitialised) 135 | */ 136 | bool push_back(const T& new_element) { 137 | unsigned idx = _elements, prev_capacity = _capacity; 138 | 139 | // element_size is calculated in the init method, thus this can be tested to determine 140 | // whether or not init has been called previously. 141 | if (_element_size == 0){ 142 | // Init function has not been invoked thus it is illegal to add an element 143 | return false; 144 | } 145 | 146 | if (_elements == _capacity) { 147 | if (_grow_capacity == 0) { // can we grow? 148 | return false; 149 | } 150 | { 151 | CriticalSectionLock lock; 152 | if (prev_capacity == _capacity) { // allocate only if someone else didn't 153 | if((_head = create_new_array(_grow_capacity, _elements, _head)) == NULL) { 154 | return false; 155 | } 156 | _capacity += _grow_capacity; 157 | } 158 | } 159 | } 160 | { 161 | // TODO: this will eventually be 'atomic_set(&_elements);' after we figure 162 | // out the atomic access primitives 163 | CriticalSectionLock lock; 164 | _elements ++; 165 | } 166 | new(get_element_address(idx)) T(new_element); 167 | return true; 168 | } 169 | 170 | /** Removes the last element in the array 171 | */ 172 | void pop_back() { 173 | T *p = NULL; 174 | { 175 | CriticalSectionLock lock; 176 | if (_elements > 0) { 177 | p = get_element_address(_elements - 1); 178 | --_elements; 179 | } 180 | } 181 | if (p != NULL) { 182 | p->~T(); 183 | } 184 | } 185 | 186 | /** Return the number of zones (linked memory areas) in this array 187 | * @returns number of zones 188 | */ 189 | unsigned get_num_zones() const { 190 | unsigned cnt = 0; 191 | array_link *crt = _head; 192 | while (crt != NULL) { 193 | cnt ++; 194 | crt = crt->prev; 195 | } 196 | return cnt; 197 | } 198 | 199 | /** Returns the number of elements in the array 200 | * @returns number of elements 201 | */ 202 | unsigned get_num_elements() const { 203 | return _elements; 204 | } 205 | 206 | /** Returns the capacity of the array 207 | * @returns capacity of the array 208 | */ 209 | unsigned get_capacity() const { 210 | return _capacity; 211 | } 212 | 213 | private: 214 | struct array_link { 215 | array_link(void *_data, unsigned _first_idx, array_link *_prev): 216 | data((uint8_t*)_data), 217 | first_idx(_first_idx), 218 | prev(_prev) { 219 | } 220 | 221 | uint8_t *data; 222 | unsigned first_idx; 223 | array_link *prev; 224 | }; 225 | 226 | array_link *create_new_array(size_t elements, unsigned first_idx = 0, array_link *prev = NULL) const { 227 | // Create the array space + an array_link structure in the same contigous memory area 228 | // Layout: array storage area | array_link structure 229 | // Since the array elements are aligned to at least 4 bytes, the array_link address will be correctly aligned 230 | size_t array_storage_size = _element_size * elements; 231 | void *temp = mbed_ualloc(array_storage_size + sizeof(array_link), _alloc_traits); 232 | if (temp == NULL) 233 | return NULL; 234 | array_link *p = new((char*)temp + array_storage_size) array_link(temp, first_idx, prev); 235 | return p; 236 | } 237 | 238 | T *get_element_address(unsigned idx) const { 239 | array_link *crt = _head; 240 | 241 | CORE_UTIL_ASSERT(idx < _elements); 242 | // first_idx in the first allocated array is 0, so the loop below is guaranteed to end 243 | while(idx < crt->first_idx) { 244 | crt = crt->prev; 245 | } 246 | CORE_UTIL_ASSERT(crt != NULL); 247 | return (T*)(crt->data + _element_size * (idx - crt->first_idx)); 248 | } 249 | 250 | void check_access(unsigned idx) const { 251 | if (NULL == _head) { 252 | CORE_UTIL_RUNTIME_ERROR("Attempt to use uninitialized Array %p\r\n", this); 253 | } 254 | if (idx >= _elements) { 255 | CORE_UTIL_RUNTIME_ERROR("Attempt to use invalid index %u in Array %p\r\n", idx, this); 256 | } 257 | } 258 | 259 | array_link *volatile _head = NULL; 260 | UAllocTraits_t _alloc_traits = {0}; 261 | size_t _element_size = 0, _grow_capacity = 0; 262 | volatile unsigned _capacity = 0, _elements = 0; 263 | unsigned _alignment = MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN; 264 | }; 265 | 266 | } // namespace util 267 | } // namespace mbed 268 | 269 | #endif // #ifndef __MBED_UTIL_ARRAY_H__ 270 | -------------------------------------------------------------------------------- /core-util/BinaryHeap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __MBED_UTIL_BINARY_HEAP_H__ 19 | #define __MBED_UTIL_BINARY_HEAP_H__ 20 | 21 | #include 22 | #include 23 | #include "core-util/CriticalSectionLock.h" 24 | #include "core-util/Array.h" 25 | #include "ualloc/ualloc.h" 26 | #include 27 | 28 | /** A reentrant binary heap class (https://en.wikipedia.org/wiki/Heap_(data_structure)) 29 | * It uses the implicit representation: the heap's nodes are stored in an Array and accessed 30 | * by index. This kind of representation requires very little additional RAM. 31 | * 32 | * Becuase it uses an Array, it can grow automatically to accomodate more elements. 33 | * 34 | * The elements are sorted according to a user supplied comparison function, which is 35 | * implemented in a comparator class. Default versions for both min-heaps (MinCompare) 36 | * and max-heaps (MaxCompare) are provided as part of the implementation. 37 | * 38 | * Usage example: 39 | * 40 | * @code 41 | * #include "core-util/BinaryHeap.h" 42 | * 43 | * class A { 44 | * public: 45 | * bool operator <=(const A& other) {...} 46 | * }; 47 | * 48 | * int main() { 49 | * BinaryHeap minh; // implicit MinCompare (min-heap) 50 | * BinaryHeap > maxh; // explicit MaxCompare (max-heap) 51 | * 52 | * // The MinCompare/MaxCompare classes can be used for classes/structure as 53 | * // long as they provide 'operator >=' or 'operator <=' respectively 54 | * BinaryHeap > minh_a; 55 | * } 56 | * @endcode 57 | */ 58 | namespace mbed { 59 | namespace util { 60 | 61 | /** Simple class that implements the compare function for min-heaps 62 | */ 63 | template 64 | class MinCompare { 65 | public: 66 | /** Function call operator used for comparing elements 67 | * @param e1 the first element 68 | * @param e2 the second element 69 | * @returns true if e1 <= e2, false otherwise 70 | */ 71 | bool operator ()(const T& e1, const T& e2) const { 72 | return e1 <= e2; 73 | } 74 | }; 75 | 76 | /** Simple class that implements the compare function for max-heaps 77 | */ 78 | template 79 | class MaxCompare { 80 | public: 81 | /** Function call operator used for comparing elements 82 | * @param e1 the first element 83 | * @param e2 the second element 84 | * @returns true if e1 >= e2, false otherwise 85 | */ 86 | bool operator ()(const T& e1, const T& e2) const { 87 | return e1 >= e2; 88 | } 89 | }; 90 | 91 | template > 92 | class BinaryHeap { 93 | public: 94 | /** Construct a new binary heap 95 | */ 96 | BinaryHeap(const Comparator& comparator = Comparator()): _array(), _comparator(comparator) { 97 | } 98 | 99 | /* Forbid copy and assignment */ 100 | BinaryHeap(const BinaryHeap&) = delete; 101 | BinaryHeap(BinaryHeap&&) = delete; 102 | BinaryHeap& operator =(const BinaryHeap&) = delete; 103 | BinaryHeap& operator =(BinaryHeap&&) = delete; 104 | 105 | /** Initialize the heap 106 | * @param initial_capacity initial capacity of the heap 107 | * @param grow_capacity number of elements to add when the heap's capacity is exceeded 108 | * @param alloc_traits allocator traits (for mbed_ualloc) 109 | * @param alignment alignment of each element in the array 110 | * @returns true if the initialization succeeded, false otherwise 111 | */ 112 | bool init(size_t initial_capacity, size_t grow_capacity, UAllocTraits_t alloc_traits, unsigned alignment = MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN) { 113 | _elements = 0; 114 | return _array.init(initial_capacity, grow_capacity, alloc_traits, alignment); 115 | } 116 | 117 | /** Inserts an element in the heap 118 | * @param p the element to insert 119 | * @returns true for success, false for failure (out of memory) 120 | */ 121 | bool insert(const T& p) { 122 | CriticalSectionLock lock; 123 | if (!_array.push_back(p)) 124 | return false; 125 | if (++_elements > 1) { 126 | _propagate_up(_elements - 1); 127 | } 128 | return true; 129 | } 130 | 131 | /** Returns a copy of the element in the root of the heap 132 | * @returns copy of the root 133 | */ 134 | T get_root() const { 135 | if (_elements == 0) { 136 | CORE_UTIL_RUNTIME_ERROR("get_root() called on an empty BinaryHeap"); 137 | } 138 | return _array[0]; 139 | } 140 | 141 | /** Remove the root of the heap and return a copy of its value 142 | * @returns copy of the root 143 | */ 144 | T pop_root() { 145 | if (_elements == 0) { 146 | CORE_UTIL_RUNTIME_ERROR("get_root() called on an empty BinaryHeap"); 147 | } 148 | CriticalSectionLock lock; 149 | T temp = _array[0]; 150 | remove_root(); 151 | return temp; 152 | } 153 | 154 | /** Removes the element at the root of the heap, possibly re-shaping the heap 155 | * to keep it consistent 156 | */ 157 | void remove_root() { 158 | if (_elements == 0) 159 | return; 160 | { 161 | CriticalSectionLock lock; 162 | _swap(0, --_elements); // element 0 will be destroyed by 'pop_back()' below 163 | _array.pop_back(); 164 | if (_elements > 1) { 165 | _propagate_down(0); 166 | } 167 | } 168 | } 169 | 170 | /** Checks if the heap is empty 171 | * @returns true if the heap is empty, false otherwise 172 | */ 173 | bool is_empty() const { 174 | return _elements == 0; 175 | } 176 | 177 | /** Remove an element from the heap. The element is searched in the heap by value using 178 | * the equality operator (==), then removed. If multiple elements with the same value 179 | * as 'e' are found, only the first one is removed. 180 | * @returns true if the element was found and removed, false otherwise. 181 | */ 182 | bool remove(const T& e) { 183 | if (_elements == 0) 184 | return false; 185 | { 186 | CriticalSectionLock lock; 187 | size_t i; 188 | for (i = 0; i < _elements; i ++) { 189 | if (e == _array[i]) 190 | break; 191 | } 192 | if (i == _elements) 193 | return false; 194 | _swap(i, --_elements); // element i will be destroyed by 'pop_back()' below 195 | _array.pop_back(); 196 | if (_elements > 1) 197 | _propagate_down(i); 198 | return true; 199 | } 200 | } 201 | 202 | /** Check the heap's consistency by applying the user supplied comparison function to its nodes 203 | * @returns true if the heap is consistent, false otherwise 204 | */ 205 | bool is_consistent(size_t node = 0) const { 206 | if (node >= _elements) 207 | return true; 208 | size_t left = _left(node), right = _right(node); 209 | if ((left < _elements) && !_comparator(_array[node], _array[left])) 210 | return false; 211 | if ((right < _elements) && !_comparator(_array[node], _array[right])) 212 | return false; 213 | return is_consistent(left) && is_consistent(right); 214 | } 215 | 216 | /** Returns the number of elements in the heap 217 | * @returns number of elements in the heap 218 | */ 219 | size_t get_num_elements() const { 220 | return _elements; 221 | } 222 | 223 | private: 224 | size_t _left(size_t i) const { 225 | return 2 * i + 1; 226 | } 227 | 228 | size_t _right(size_t i) const { 229 | return 2 * i + 2; 230 | } 231 | 232 | size_t _parent(size_t i) const { 233 | return (i - 1) / 2; 234 | } 235 | 236 | void _propagate_up(size_t node) { 237 | // This is called when a node is added in the last position in the heap 238 | // We might need to move the node up towards the parent until the heap property 239 | // is satisfied 240 | size_t parent = _parent(node); 241 | // Move the node up until it satisfies the heap property 242 | while ((node > 0) && _comparator(_array[node], _array[parent])) { 243 | _swap(node, parent); 244 | node = parent; 245 | parent = _parent(node); 246 | } 247 | } 248 | 249 | void _propagate_down(size_t node) { 250 | // This is called when an existing node is removed 251 | // When that happens, it is replaced with the node at the last position in the heap 252 | // Since that might make the heap inconsistent, we need to move the node down if its 253 | // value does not respect the comparison function when compared with its left and 254 | // right children. 255 | while (true) { 256 | size_t left = _left(node), right = _right(node), temp; 257 | bool change_left = (left < _elements) && !_comparator(_array[node], _array[left]); 258 | bool change_right = (right < _elements) && !_comparator(_array[node], _array[right]); 259 | if (change_left && change_right) { 260 | // If both left/right should change, use the comparison function to figure out 261 | // which way to go 262 | temp = _comparator(_array[left], _array[right]) ? left : right; 263 | } else if (change_left) { 264 | temp = left; 265 | } else if (change_right) { 266 | temp = right; 267 | } else { 268 | break; 269 | } 270 | _swap(node, temp); 271 | node = temp; 272 | } 273 | } 274 | 275 | void _swap(size_t pos1, size_t pos2) { 276 | if (pos1 != pos2) { 277 | T temp = _array[pos1]; 278 | _array[pos1] = _array[pos2]; 279 | _array[pos2] = temp; 280 | } 281 | } 282 | 283 | Array _array; 284 | Comparator _comparator; 285 | volatile size_t _elements; 286 | }; 287 | 288 | } // namespace util 289 | } // namespace mbed 290 | 291 | #endif // #ifndef __MBED_UTIL_BINARY_HEAP_H__ 292 | -------------------------------------------------------------------------------- /core-util/CriticalSectionLock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __MBED_UTIL_CRITICAL_SECTION_LOCK_H__ 19 | #define __MBED_UTIL_CRITICAL_SECTION_LOCK_H__ 20 | 21 | #include "core-util/critical.h" 22 | 23 | namespace mbed { 24 | namespace util { 25 | 26 | /** RAII object for disabling, then restoring, interrupt state 27 | * Usage: 28 | * @code 29 | * 30 | * void f() { 31 | * // some code here 32 | * { 33 | * CriticalSectionLock lock; 34 | * // Code in this block will run with interrupts disabled 35 | * } 36 | * // interrupts will be restored to their previous state 37 | * } 38 | * @endcode 39 | */ 40 | 41 | class CriticalSectionLock { 42 | public: 43 | CriticalSectionLock() { 44 | core_util_critical_section_enter(); 45 | } 46 | 47 | ~CriticalSectionLock() { 48 | core_util_critical_section_exit(); 49 | } 50 | 51 | }; 52 | 53 | } // namespace util 54 | } // namespace mbed 55 | 56 | #endif // #ifndef __MBED_UTIL_CRITICAL_SECTION_LOCK_H__ 57 | 58 | -------------------------------------------------------------------------------- /core-util/Event.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MBED_EVENT_H_ 18 | #define MBED_EVENT_H_ 19 | 20 | #include "FunctionPointerBind.h" 21 | namespace mbed { 22 | namespace util { 23 | typedef FunctionPointerBind Event; 24 | } /* namespace util */ 25 | } /* namespace mbed */ 26 | 27 | #endif // MBED_EVENT_H_ 28 | -------------------------------------------------------------------------------- /core-util/ExtendablePoolAllocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __MBED_UTIL_EXTENDABLE_POOL_ALLOCATOR_H__ 19 | #define __MBED_UTIL_EXTENDABLE_POOL_ALLOCATOR_H__ 20 | 21 | #include 22 | #include "core-util/PoolAllocator.h" 23 | #include "ualloc/ualloc.h" 24 | 25 | namespace mbed { 26 | namespace util { 27 | 28 | /** A pool allocator that can grow automatically to satisfy allocation requests. 29 | * 30 | * The pool allocator contains a linked list of one or more PoolAllocator instances 31 | * 32 | * ExtendablePoolAllocator starts with a single PoolAllocator. Allocation is first 33 | * attempted from the most recent pool; if that fails, allocation is attempted again 34 | * from the other pools. If that fails, a new pool is created (with a number of elements 35 | * specified by 'set_new_pool_size' and allocation is attempted from this new pool 36 | */ 37 | 38 | class ExtendablePoolAllocator { 39 | public: 40 | /** Create a new extendable pool allocator 41 | */ 42 | ExtendablePoolAllocator(); 43 | 44 | /* Forbid copy and assignment */ 45 | ExtendablePoolAllocator(const ExtendablePoolAllocator&) = delete; 46 | ExtendablePoolAllocator(ExtendablePoolAllocator&&) = delete; 47 | ExtendablePoolAllocator& operator =(const ExtendablePoolAllocator&) = delete; 48 | ExtendablePoolAllocator& operator =(ExtendablePoolAllocator&&) = delete; 49 | 50 | /** Destructor. It will automatically free all allocated memory 51 | */ 52 | ~ExtendablePoolAllocator(); 53 | 54 | /** Initialize the allocator, allocating the first pool 55 | * @param initial_elements the size of the initial pool in elements (each of element_size bytes) 56 | * @param new_pool_elements size of pools that are going to be created to satisfy 57 | * allocation requests 58 | * @param element_size size of each pool element in bytes (this might be rounded up 59 | to satisfy the 'alignment' argument) 60 | * @param alloc_traits mbed_alloc traits for allocating the pools 61 | * @param alignment allocation alignment in bytes (must be a power of 2, at least 4) 62 | * @returns true if the initialization was OK, false otherwise 63 | */ 64 | bool init(size_t initial_elements, size_t new_pool_elements, size_t element_size, UAllocTraits_t alloc_traits, unsigned alignment = MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN); 65 | 66 | /** Allocate a new element from the pool 67 | * It will try to allocate using the most recent pool 68 | * Failing that, it will try to allocate from all the other pools 69 | * Failing that, it will try to create a new pool and allocate from it 70 | * @returns the address of the new element or NULL for error 71 | */ 72 | void* alloc(); 73 | 74 | /** Allocate a new element from the pool and initialize it with 0 75 | * @returns the address of the new element or NULL for error 76 | */ 77 | void *calloc(); 78 | 79 | /** Free a previously allocated element 80 | * @param p pointer to element 81 | */ 82 | void free(void* p); 83 | 84 | /** Return the number of PoolAllocator instances in this pool 85 | * @returns number of PoolAllocator instances 86 | */ 87 | unsigned get_num_pools() const; 88 | 89 | private: 90 | struct pool_link { 91 | pool_link(void *start, size_t elements, size_t element_size, unsigned alignment, pool_link *_prev): 92 | prev(_prev), 93 | allocator(start, elements, element_size, alignment) { 94 | } 95 | 96 | pool_link *prev; 97 | PoolAllocator allocator; 98 | }; 99 | pool_link *create_new_pool(size_t elements, pool_link *prev) const; 100 | 101 | pool_link *volatile _head; 102 | size_t _element_size, _new_pool_elements; 103 | UAllocTraits_t _alloc_traits; 104 | unsigned _alignment; 105 | }; 106 | 107 | } // namespace util 108 | } // namespace mbed 109 | 110 | #endif // #ifndef __MBED_UTIL_EXTENDABLE_POOL_ALLOCATOR_H__ 111 | 112 | -------------------------------------------------------------------------------- /core-util/FunctionPointer.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef MBED_FUNCTIONPOINTER_H 17 | #define MBED_FUNCTIONPOINTER_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "core-util/FunctionPointerBase.h" 25 | #include "core-util/FunctionPointerBind.h" 26 | 27 | namespace mbed { 28 | namespace util { 29 | 30 | /** A class for storing and calling a pointer to a static or member void function without arguments 31 | */ 32 | template 33 | class FunctionPointer0 : public FunctionPointerBase{ 34 | public: 35 | typedef R(*static_fp)(void); 36 | typedef struct arg_struct{ 37 | } ArgStruct; 38 | /** Create a FunctionPointer, attaching a static function 39 | * 40 | * @param function The void static function to attach (default is none) 41 | */ 42 | FunctionPointer0(static_fp function = 0): 43 | FunctionPointerBase() 44 | { 45 | attach(function); 46 | } 47 | 48 | /** Create a FunctionPointer, attaching a member function 49 | * 50 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 51 | * @param function The address of the void member function to attach 52 | */ 53 | template 54 | FunctionPointer0(T *object, R (T::*member)(void)): 55 | FunctionPointerBase() 56 | { 57 | attach(object, member); 58 | } 59 | 60 | /** Attach a static function 61 | * 62 | * @param function The void static function to attach (default is none) 63 | */ 64 | void attach(static_fp function) { 65 | FunctionPointerBase::_object = reinterpret_cast(function); 66 | FunctionPointerBase::_membercaller = &FunctionPointer0::staticcaller; 67 | } 68 | 69 | /** Attach a member function 70 | * 71 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 72 | * @param function The address of the void member function to attach 73 | */ 74 | template 75 | void attach(T *object, R (T::*member)(void)) { 76 | FunctionPointerBase::_object = static_cast(object); 77 | *reinterpret_cast(FunctionPointerBase::_member) = member; 78 | FunctionPointerBase::_membercaller = &FunctionPointer0::membercaller; 79 | } 80 | 81 | /** Call the attached static or member function 82 | */ 83 | R call(){ 84 | return FunctionPointerBase::call(NULL); 85 | } 86 | R operator ()(void) { 87 | return FunctionPointerBase::call(NULL); 88 | } 89 | 90 | FunctionPointerBind bind() { 91 | FunctionPointerBind fp(*this); 92 | void * storage = this->pre_bind(fp, (ArgStruct *)NULL, &FunctionPointerBase::_nullops); 93 | new(storage) ArgStruct(); 94 | return fp; 95 | } 96 | 97 | static_fp get_function()const { 98 | return reinterpret_cast(FunctionPointerBase::_object); 99 | } 100 | 101 | 102 | private: 103 | template 104 | static R membercaller(void *object, char *member, void *arg) { 105 | (void) arg; 106 | T* o = static_cast(object); 107 | R (T::**m)(void) = reinterpret_cast(member); 108 | return (o->**m)(); 109 | } 110 | static R staticcaller(void *object, char *member, void *arg) { 111 | (void) arg; 112 | (void) member; 113 | static_fp f = reinterpret_cast(object); 114 | return f(); 115 | } 116 | }; 117 | 118 | 119 | /* If we had variaditic templates, this wouldn't be a problem, but until C++11 is enabled, we are stuck with multiple classes... */ 120 | 121 | /** A class for storing and calling a pointer to a static or member void function with one argument 122 | */ 123 | template 124 | class FunctionPointer1 : public FunctionPointerBase { 125 | public: 126 | typedef struct arg_struct{ 127 | A1 a1; 128 | arg_struct(const A1 &b1) : a1(b1){} 129 | } ArgStruct; 130 | typedef R(*static_fp)(A1); 131 | /** Create a FunctionPointer, attaching a static function 132 | * 133 | * @param function The void static function to attach (default is none) 134 | */ 135 | FunctionPointer1(static_fp function = 0) { 136 | attach(function); 137 | } 138 | 139 | /** Create a FunctionPointer, attaching a member function 140 | * 141 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 142 | * @param function The address of the void member function to attach 143 | */ 144 | template 145 | FunctionPointer1(T *object, R (T::*member)(A1)) { 146 | attach(object, member); 147 | } 148 | 149 | /** Attach a static function 150 | * 151 | * @param function The void static function to attach (default is none) 152 | */ 153 | void attach(static_fp function) { 154 | FunctionPointerBase::_object = reinterpret_cast(function); 155 | FunctionPointerBase::_membercaller = &FunctionPointer1::staticcaller; 156 | } 157 | 158 | /** Attach a member function 159 | * 160 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 161 | * @param function The address of the void member function to attach 162 | */ 163 | template 164 | void attach(T *object, R (T::*member)(A1)) 165 | { 166 | FunctionPointerBase::_object = static_cast(object); 167 | *reinterpret_cast(FunctionPointerBase::_member) = member; 168 | FunctionPointerBase::_membercaller = &FunctionPointer1::membercaller; 169 | } 170 | 171 | FunctionPointerBind bind(const A1 &a1) { 172 | FunctionPointerBind fp(*this); 173 | void * storage = this->pre_bind(fp, (ArgStruct *)NULL, &_fp1_ops); 174 | new(storage) ArgStruct(a1); 175 | return fp; 176 | } 177 | 178 | 179 | /** Call the attached static or member function 180 | */ 181 | R call(A1 a1) 182 | { 183 | ArgStruct Args(a1); 184 | return FunctionPointerBase::call(&Args); 185 | } 186 | R operator ()(A1 a1) { 187 | ArgStruct Args(a1); 188 | return FunctionPointerBase::call(&Args); 189 | } 190 | 191 | static_fp get_function()const 192 | { 193 | return reinterpret_cast(FunctionPointerBase::_object); 194 | } 195 | 196 | 197 | private: 198 | template 199 | static R membercaller(void *object, char *member, void *arg) { 200 | ArgStruct *Args = static_cast(arg); 201 | T* o = static_cast(object); 202 | R (T::**m)(A1) = reinterpret_cast(member); 203 | return (o->**m)(Args->a1); 204 | } 205 | static R staticcaller(void *object, char *member, void *arg) { 206 | ArgStruct *Args = static_cast(arg); 207 | (void) member; 208 | static_fp f = reinterpret_cast(object); 209 | return f(Args->a1); 210 | } 211 | static void copy_constructor(void *dest , void* src) { 212 | ArgStruct *src_args = static_cast(src); 213 | new(dest) ArgStruct(src_args->a1); 214 | } 215 | static void destructor(void *args) { 216 | ArgStruct *argstruct = static_cast(args); 217 | argstruct->~arg_struct(); 218 | } 219 | 220 | protected: 221 | static const struct FunctionPointerBase::ArgOps _fp1_ops; 222 | }; 223 | 224 | template 225 | const struct FunctionPointerBase::ArgOps FunctionPointer1::_fp1_ops = { 226 | FunctionPointer1::copy_constructor, 227 | FunctionPointer1::destructor 228 | }; 229 | 230 | 231 | /** A class for storing and calling a pointer to a static or member void function with two arguments 232 | */ 233 | template 234 | class FunctionPointer2 : public FunctionPointerBase { 235 | public: 236 | typedef struct arg_struct{ 237 | A1 a1; 238 | A2 a2; 239 | arg_struct(const A1 &b1, const A2 &b2) : a1(b1), a2(b2) {} 240 | } ArgStruct; 241 | typedef R(*static_fp)(A1, A2); 242 | /** Create a FunctionPointer, attaching a static function 243 | * 244 | * @param function The void static function to attach (default is none) 245 | */ 246 | FunctionPointer2(static_fp function = 0) { 247 | attach(function); 248 | } 249 | 250 | /** Create a FunctionPointer, attaching a member function 251 | * 252 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 253 | * @param function The address of the void member function to attach 254 | */ 255 | template 256 | FunctionPointer2(T *object, R (T::*member)(A1, A2)) { 257 | attach(object, member); 258 | } 259 | 260 | /** Attach a static function 261 | * 262 | * @param function The void static function to attach (default is none) 263 | */ 264 | void attach(static_fp function) { 265 | FunctionPointerBase::_object = reinterpret_cast(function); 266 | FunctionPointerBase::_membercaller = &FunctionPointer2::staticcaller; 267 | } 268 | 269 | /** Attach a member function 270 | * 271 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 272 | * @param function The address of the void member function to attach 273 | */ 274 | template 275 | void attach(T *object, R (T::*member)(A1, A2)) 276 | { 277 | FunctionPointerBase::_object = static_cast(object); 278 | *reinterpret_cast(FunctionPointerBase::_member) = member; 279 | FunctionPointerBase::_membercaller = &FunctionPointer2::membercaller; 280 | } 281 | 282 | FunctionPointerBind bind(const A1 &a1, const A2 &a2) { 283 | FunctionPointerBind fp(*this); 284 | void * storage = this->pre_bind(fp, (ArgStruct *)NULL, &_fp2_ops); 285 | new(storage) ArgStruct(a1,a2); 286 | return fp; 287 | } 288 | 289 | 290 | /** Call the attached static or member function 291 | */ 292 | R call(A1 a1, A2 a2) 293 | { 294 | ArgStruct Args(a1, a2); 295 | return FunctionPointerBase::call(&Args); 296 | } 297 | R operator ()(A1 a1, A2 a2) { 298 | ArgStruct Args(a1, a2); 299 | return FunctionPointerBase::call(&Args); 300 | } 301 | 302 | static_fp get_function()const 303 | { 304 | return reinterpret_cast(FunctionPointerBase::_object); 305 | } 306 | 307 | 308 | private: 309 | template 310 | static R membercaller(void *object, char *member, void *arg) { 311 | ArgStruct *Args = static_cast(arg); 312 | T* o = static_cast(object); 313 | R (T::**m)(A1, A2) = reinterpret_cast(member); 314 | return (o->**m)(Args->a1, Args->a2); 315 | } 316 | static R staticcaller(void *object, char *member, void *arg) { 317 | ArgStruct *Args = static_cast(arg); 318 | (void) member; 319 | static_fp f = reinterpret_cast(object); 320 | return f(Args->a1, Args->a2); 321 | } 322 | static void copy_constructor(void *dest , void* src) { 323 | ArgStruct *src_args = static_cast(src); 324 | new(dest) ArgStruct(src_args->a1, src_args->a2); 325 | } 326 | static void destructor(void *args) { 327 | ArgStruct *argstruct = static_cast(args); 328 | argstruct->~arg_struct(); 329 | } 330 | 331 | protected: 332 | static const struct FunctionPointerBase::ArgOps _fp2_ops; 333 | }; 334 | 335 | template 336 | const struct FunctionPointerBase::ArgOps FunctionPointer2::_fp2_ops = { 337 | FunctionPointer2::copy_constructor, 338 | FunctionPointer2::destructor 339 | }; 340 | 341 | /** A class for storing and calling a pointer to a static or member void function with three arguments 342 | */ 343 | template 344 | class FunctionPointer3 : public FunctionPointerBase { 345 | public: 346 | typedef struct arg_struct{ 347 | A1 a1; 348 | A2 a2; 349 | A3 a3; 350 | arg_struct(const A1 &b1, const A2 &b2, const A3 &b3) : a1(b1), a2(b2), a3(b3) {} 351 | } ArgStruct; 352 | typedef R(*static_fp)(A1, A2, A3); 353 | /** Create a FunctionPointer, attaching a static function 354 | * 355 | * @param function The void static function to attach (default is none) 356 | */ 357 | FunctionPointer3(static_fp function = 0) { 358 | attach(function); 359 | } 360 | 361 | /** Create a FunctionPointer, attaching a member function 362 | * 363 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 364 | * @param function The address of the void member function to attach 365 | */ 366 | template 367 | FunctionPointer3(T *object, R (T::*member)(A1, A2, A3)) { 368 | attach(object, member); 369 | } 370 | 371 | /** Attach a static function 372 | * 373 | * @param function The void static function to attach (default is none) 374 | */ 375 | void attach(static_fp function) { 376 | FunctionPointerBase::_object = reinterpret_cast(function); 377 | FunctionPointerBase::_membercaller = &FunctionPointer3::staticcaller; 378 | } 379 | 380 | /** Attach a member function 381 | * 382 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 383 | * @param function The address of the void member function to attach 384 | */ 385 | template 386 | void attach(T *object, R (T::*member)(A1, A2, A3)) 387 | { 388 | FunctionPointerBase::_object = static_cast(object); 389 | *reinterpret_cast(FunctionPointerBase::_member) = member; 390 | FunctionPointerBase::_membercaller = &FunctionPointer3::membercaller; 391 | } 392 | 393 | FunctionPointerBind bind(const A1 &a1, const A2 &a2, const A3 &a3) { 394 | FunctionPointerBind fp(*this); 395 | void * storage = this->pre_bind(fp, (ArgStruct *)NULL, &_fp3_ops); 396 | new(storage) ArgStruct(a1,a2,a3); 397 | return fp; 398 | } 399 | 400 | 401 | /** Call the attached static or member function 402 | */ 403 | R call(A1 a1, A2 a2, A3 a3) 404 | { 405 | ArgStruct Args(a1, a2, a3); 406 | return FunctionPointerBase::call(&Args); 407 | } 408 | R operator ()(A1 a1, A2 a2, A3 a3) { 409 | ArgStruct Args(a1, a2, a3); 410 | return FunctionPointerBase::call(&Args); 411 | } 412 | 413 | static_fp get_function()const 414 | { 415 | return reinterpret_cast(FunctionPointerBase::_object); 416 | } 417 | 418 | 419 | private: 420 | template 421 | static R membercaller(void *object, char *member, void *arg) { 422 | ArgStruct *Args = static_cast(arg); 423 | T* o = static_cast(object); 424 | R (T::**m)(A1, A2, A3) = reinterpret_cast(member); 425 | return (o->**m)(Args->a1, Args->a2, Args->a3); 426 | } 427 | static R staticcaller(void *object, char *member, void *arg) { 428 | ArgStruct *Args = static_cast(arg); 429 | (void) member; 430 | static_fp f = reinterpret_cast(object); 431 | return f(Args->a1, Args->a2, Args->a3); 432 | } 433 | static void copy_constructor(void *dest , void* src) { 434 | ArgStruct *src_args = static_cast(src); 435 | new(dest) ArgStruct(src_args->a1, src_args->a2, src_args->a3); 436 | } 437 | static void destructor(void *args) { 438 | ArgStruct *argstruct = static_cast(args); 439 | argstruct->~arg_struct(); 440 | } 441 | 442 | protected: 443 | static const struct FunctionPointerBase::ArgOps _fp3_ops; 444 | }; 445 | 446 | template 447 | const struct FunctionPointerBase::ArgOps FunctionPointer3::_fp3_ops = { 448 | FunctionPointer3::copy_constructor, 449 | FunctionPointer3::destructor 450 | }; 451 | 452 | /** A class for storing and calling a pointer to a static or member void function with four arguments 453 | */ 454 | template 455 | class FunctionPointer4 : public FunctionPointerBase { 456 | public: 457 | typedef struct arg_struct{ 458 | A1 a1; 459 | A2 a2; 460 | A3 a3; 461 | A4 a4; 462 | arg_struct(const A1 &b1, const A2 &b2, const A3 &b3, const A4 &b4) : 463 | a1(b1), a2(b2), a3(b3), a4(b4) {} 464 | } ArgStruct; 465 | typedef R(*static_fp)(A1, A2, A3, A4); 466 | /** Create a FunctionPointer, attaching a static function 467 | * 468 | * @param function The void static function to attach (default is none) 469 | */ 470 | FunctionPointer4(static_fp function = 0) { 471 | attach(function); 472 | } 473 | 474 | /** Create a FunctionPointer, attaching a member function 475 | * 476 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 477 | * @param function The address of the void member function to attach 478 | */ 479 | template 480 | FunctionPointer4(T *object, R (T::*member)(A1, A2, A3, A4)) { 481 | attach(object, member); 482 | } 483 | 484 | /** Attach a static function 485 | * 486 | * @param function The void static function to attach (default is none) 487 | */ 488 | void attach(static_fp function) { 489 | FunctionPointerBase::_object = reinterpret_cast(function); 490 | FunctionPointerBase::_membercaller = &FunctionPointer4::staticcaller; 491 | } 492 | 493 | /** Attach a member function 494 | * 495 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) 496 | * @param function The address of the void member function to attach 497 | */ 498 | template 499 | void attach(T *object, R (T::*member)(A1, A2, A3, A4)) 500 | { 501 | FunctionPointerBase::_object = static_cast(object); 502 | *reinterpret_cast(FunctionPointerBase::_member) = member; 503 | FunctionPointerBase::_membercaller = &FunctionPointer4::membercaller; 504 | } 505 | 506 | FunctionPointerBind bind(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) { 507 | FunctionPointerBind fp(*this); 508 | void * storage = this->pre_bind(&fp, (ArgStruct *)NULL, &_fp4_ops); 509 | new(storage) ArgStruct(a1,a2,a3,a4); 510 | return fp; 511 | } 512 | 513 | 514 | /** Call the attached static or member function 515 | */ 516 | R call(A1 a1, A2 a2, A3 a3, A4 a4) 517 | { 518 | ArgStruct Args(a1, a2, a3, a4); 519 | return FunctionPointerBase::call(&Args); 520 | } 521 | R operator ()(A1 a1, A2 a2, A3 a3, A4 a4) { 522 | ArgStruct Args(a1, a2, a3, a4); 523 | return FunctionPointerBase::call(&Args); 524 | } 525 | 526 | static_fp get_function()const 527 | { 528 | return reinterpret_cast(FunctionPointerBase::_object); 529 | } 530 | 531 | 532 | private: 533 | template 534 | static R membercaller(void *object, char *member, void *arg) { 535 | ArgStruct *Args = static_cast(arg); 536 | T* o = static_cast(object); 537 | R (T::**m)(A1, A2, A3, A4) = reinterpret_cast(member); 538 | return (o->**m)(Args->a1, Args->a2, Args->a3, Args->a4); 539 | } 540 | static R staticcaller(void *object, char *member, void *arg) { 541 | ArgStruct *Args = static_cast(arg); 542 | (void) member; 543 | static_fp f = reinterpret_cast(object); 544 | return f(Args->a1, Args->a2, Args->a3, Args->a4); 545 | } 546 | static void copy_constructor(void *dest , void* src) { 547 | ArgStruct *src_args = static_cast(src); 548 | new(dest) ArgStruct(src_args->a1, src_args->a2, src_args->a3, src_args->a4); 549 | } 550 | static void destructor(void *args) { 551 | ArgStruct *argstruct = static_cast(args); 552 | argstruct->~arg_struct(); 553 | } 554 | 555 | protected: 556 | static const struct FunctionPointerBase::ArgOps _fp4_ops; 557 | }; 558 | 559 | template 560 | const struct FunctionPointerBase::ArgOps FunctionPointer4::_fp4_ops = { 561 | FunctionPointer4::copy_constructor, 562 | FunctionPointer4::destructor 563 | }; 564 | 565 | typedef FunctionPointer0 FunctionPointer; 566 | 567 | } // namespace util 568 | } // namespace mbed 569 | 570 | #endif 571 | -------------------------------------------------------------------------------- /core-util/FunctionPointerBase.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef MBED_FUNCTIONPOINTERBASE_H 17 | #define MBED_FUNCTIONPOINTERBASE_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "core-util/assert.h" 25 | namespace mbed { 26 | namespace util { 27 | 28 | #define MBED_STATIC_ASSERT(MBED_STATIC_ASSERT_FAILED,MSG)\ 29 | switch(0){\ 30 | case 0:case (MBED_STATIC_ASSERT_FAILED): \ 31 | break;} 32 | 33 | template 34 | class FunctionPointerBind; 35 | 36 | template 37 | class FunctionPointerBase { 38 | public: 39 | inline operator bool(void) const { 40 | return (_membercaller != NULL) && (_object != NULL); 41 | } 42 | 43 | bool operator==(const FunctionPointerBase& other) const { 44 | return ((_object == other._object) && (memcmp(_member, other._member, sizeof(_member)) == 0)); 45 | } 46 | 47 | bool operator!=(const FunctionPointerBase& other) const { 48 | return !(*this == other); 49 | } 50 | 51 | /** 52 | * Clears the current function pointer assignment 53 | * After clear(), this instance will point to nothing (NULL) 54 | */ 55 | virtual void clear() { 56 | _membercaller = NULL; 57 | _object = NULL; 58 | memset(_member, 0, sizeof(_member)); 59 | } 60 | 61 | /** 62 | * Calls the member pointed to by object::member or (function)object 63 | * @param arg 64 | * @return 65 | */ 66 | inline R call(void* arg) { 67 | #ifndef YOTTA_CFG_UTIL_FUNCTIONPOINTER_DISABLE_NULL_CHECK 68 | CORE_UTIL_ASSERT((_membercaller != NULL) && (_object != NULL)); 69 | #endif 70 | return _membercaller(_object, _member, arg); 71 | } 72 | 73 | FunctionPointerBase():_object(NULL), _membercaller(NULL) { 74 | memset(_member, 0, sizeof(_member)); 75 | } 76 | FunctionPointerBase(const FunctionPointerBase & fp) { 77 | copy(&fp); 78 | } 79 | virtual ~FunctionPointerBase() { 80 | 81 | } 82 | protected: 83 | struct ArgOps { 84 | void (*copy_args)(void *, void *); 85 | void (*destructor)(void *); 86 | }; 87 | 88 | // Forward declaration of an unknown class 89 | class UnknownClass; 90 | // Forward declaration of an unknown member function to this an unknown class 91 | // this kind of declaration is authorized by the standard (see 8.3.3/2 of C++ 03 standard). 92 | // As a result, the compiler will allocate for UnknownFunctionMember_t the biggest size 93 | // and biggest alignment possible for member function. 94 | // This type can be used inside unions, it will help to provide the storage 95 | // with the proper size and alignment guarantees 96 | typedef void (UnknownClass::*UnknownFunctionMember_t)(); 97 | 98 | union { 99 | char _member[sizeof(UnknownFunctionMember_t)]; 100 | UnknownFunctionMember_t _alignementAndSizeGuarantees; 101 | }; 102 | 103 | void * _object; // object Pointer/function pointer 104 | R (*_membercaller)(void *, char *, void *); 105 | static const struct ArgOps _nullops; 106 | 107 | protected: 108 | 109 | void copy(const FunctionPointerBase * fp) { 110 | _object = fp->_object; 111 | memcpy (_member, fp->_member, sizeof(_member)); 112 | _membercaller = fp->_membercaller; 113 | } 114 | 115 | template 116 | void * pre_bind(FunctionPointerBind & fp, S * argStruct, const struct FunctionPointerBase::ArgOps *ops) 117 | { 118 | MBED_STATIC_ASSERT(sizeof(S) <= sizeof(fp._storage), ERROR: Arguments too large for FunctionPointerBind internal storage) 119 | (void) argStruct; 120 | fp._ops = ops; 121 | return (void*)fp._storage; 122 | } 123 | private: 124 | static void _null_copy_args(void *dest , void* src) {(void) dest; (void) src;} 125 | static void _null_destructor(void *args) {(void) args;} 126 | 127 | }; 128 | template 129 | const struct FunctionPointerBase::ArgOps FunctionPointerBase::_nullops = { 130 | FunctionPointerBase::_null_copy_args, 131 | FunctionPointerBase::_null_destructor 132 | }; 133 | 134 | } /* namespace util */ 135 | } /* namespace mbed */ 136 | #endif 137 | -------------------------------------------------------------------------------- /core-util/FunctionPointerBind.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef MBED_FUNCTIONPOINTERBIND_H__ 18 | #define MBED_FUNCTIONPOINTERBIND_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "core-util/FunctionPointerBase.h" 25 | 26 | 27 | #ifdef YOTTA_CFG_UTIL_FUNCTIONPOINTER_ARG_STORAGE 28 | #define EVENT_STORAGE_SIZE (YOTTA_CFG_UTIL_FUNCTIONPOINTER_ARG_STORAGE) 29 | #else 30 | #define EVENT_STORAGE_SIZE 32 31 | #endif 32 | 33 | #define MBED_STATIC_ASSERT(MBED_STATIC_ASSERT_FAILED,MSG)\ 34 | switch(0){\ 35 | case 0:case (MBED_STATIC_ASSERT_FAILED): \ 36 | break;} 37 | 38 | namespace mbed { 39 | namespace util { 40 | 41 | template 42 | class FunctionPointerBase; 43 | 44 | template 45 | class FunctionPointerBind : public FunctionPointerBase { 46 | friend FunctionPointerBase; 47 | public: 48 | // Call the Event 49 | inline R call() { 50 | return FunctionPointerBase::call(static_cast(_storage)); 51 | } 52 | FunctionPointerBind(): 53 | FunctionPointerBase(), 54 | _ops(&FunctionPointerBase::_nullops) 55 | {} 56 | 57 | FunctionPointerBind(const FunctionPointerBase & fp) : 58 | FunctionPointerBase(fp) 59 | {} 60 | 61 | FunctionPointerBind(const FunctionPointerBind & fp): 62 | FunctionPointerBase(), 63 | _ops(&FunctionPointerBase::_nullops) { 64 | *this = fp; 65 | } 66 | 67 | virtual ~FunctionPointerBind() { 68 | _ops->destructor(_storage); 69 | } 70 | 71 | FunctionPointerBind & operator=(const FunctionPointerBind& rhs) { 72 | if (_ops != &FunctionPointerBase::_nullops) { 73 | _ops->destructor(_storage); 74 | } 75 | FunctionPointerBase::copy(&rhs); 76 | _ops = rhs._ops; 77 | _ops->copy_args(_storage, (void *)rhs._storage); 78 | return *this; 79 | } 80 | 81 | /** 82 | * Clears the current binding, making this instance unbound 83 | */ 84 | virtual void clear() { 85 | if (_ops != &FunctionPointerBase::_nullops) { 86 | _ops->destructor(_storage); 87 | } 88 | _ops = &FunctionPointerBase::_nullops; 89 | FunctionPointerBase::clear(); 90 | } 91 | 92 | R operator()() { 93 | return call(); 94 | } 95 | 96 | protected: 97 | const struct FunctionPointerBase::ArgOps * _ops; 98 | uint32_t _storage[(EVENT_STORAGE_SIZE+sizeof(uint32_t)-1)/sizeof(uint32_t)]; 99 | }; 100 | 101 | } /* namespace util */ 102 | } /* namespace mbed */ 103 | 104 | #endif // MBED_FUNCTIONPOINTERBIND_H__ 105 | -------------------------------------------------------------------------------- /core-util/PoolAllocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __MBED_UTIL_POOL_ALLOCATOR_H__ 19 | #define __MBED_UTIL_POOL_ALLOCATOR_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifndef YOTTA_CFG_CORE_UTIL_POOL_ALLOC_DEFAULT_ALIGN 25 | #define YOTTA_CFG_CORE_UTIL_POOL_ALLOC_DEFAULT_ALIGN 8 26 | #endif 27 | 28 | #define MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN YOTTA_CFG_CORE_UTIL_POOL_ALLOC_DEFAULT_ALIGN 29 | 30 | namespace mbed { 31 | namespace util { 32 | 33 | /** A simple pool allocator class. It can allocate one elements oe 'element_size' bytes at a time. 34 | * alloc() and free() operations are synchronized, they can be used safely from both user 35 | * and interrupt context. 36 | */ 37 | class PoolAllocator { 38 | public: 39 | /** Create a new pool allocator 40 | * @param start pool start address 41 | * @param elements the size of pool in elements (each of element_size bytes) 42 | * @param element_size size of each pool element in bytes (this might be rounded up 43 | to satisfy the 'alignment' argument) 44 | * @param alignment allocation alignment in bytes (must be a power of 2, at least 4) 45 | */ 46 | PoolAllocator(void *start, size_t elements, size_t element_size, unsigned alignment = MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN); 47 | 48 | /* Forbid copy and assignment */ 49 | PoolAllocator(const PoolAllocator&) = delete; 50 | PoolAllocator(PoolAllocator&&) = delete; 51 | PoolAllocator& operator =(const PoolAllocator&) = delete; 52 | PoolAllocator& operator =(PoolAllocator&&) = delete; 53 | 54 | /** Allocate a new element from the pool 55 | * @returns the address of the new element or NULL for error 56 | */ 57 | void *alloc(); 58 | 59 | /** Allocate a new element from the pool and initialize it with 0 60 | * @returns the address of the new element or NULL for error 61 | */ 62 | void *calloc(); 63 | 64 | /** Free a previously allocated element 65 | * @param p pointer to element 66 | */ 67 | void free(void* p); 68 | 69 | /** Returns a pool size suitable to hold the required number of elements 70 | * @param elements the size of pool in elements (each of element_size bytes) 71 | * @param element_size size of each pool element in bytes (this might be rounded up 72 | to satisfy the 'alignment' argument) 73 | * @param alignment allocation alignment in bytes 74 | * @returns the size of the pool in bytes 75 | */ 76 | static size_t get_pool_size(size_t elements, size_t element_size, unsigned alignment = MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN); 77 | 78 | /** Check if this pool owns a pointer 79 | * @param p the pointer to check 80 | * @returns true if the pointer is inside this pool, false otherwise 81 | */ 82 | bool owns(const void *p) const; 83 | 84 | /** Aligns a quantity up to the given alignment (which must be a power of 2) 85 | * @param n the quantity to align 86 | * @param alignment the alignment 87 | * @returns the aligned quantity 88 | */ 89 | static uint32_t align_up(uint32_t n, uint32_t alignment); 90 | 91 | /** Returns the start address of the pool 92 | * @returns start address 93 | */ 94 | void* get_start_address() const; 95 | 96 | private: 97 | void _init(); 98 | 99 | void *_start, *_free_block, *_end; 100 | size_t _element_size; 101 | }; 102 | 103 | } // namespace util 104 | } // namespace mbed 105 | 106 | #endif // #ifndef __MBED_UTIL_POOL_ALLOCATOR_H__ 107 | -------------------------------------------------------------------------------- /core-util/SharedPointer.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __CORE_UTIL_SHAREDPOINTER_H__ 18 | #define __CORE_UTIL_SHAREDPOINTER_H__ 19 | 20 | #include "core-util/assert.h" 21 | #include "ualloc/ualloc.h" 22 | 23 | #include 24 | #include 25 | 26 | #ifndef NDEBUG 27 | #include 28 | #define CORE_UTIL_SHAREDPOINTER_DEBUG(...) { printf(__VA_ARGS__); } 29 | #else 30 | #define CORE_UTIL_SHAREDPOINTER_DEBUG(...) /* nothing */ 31 | #endif 32 | 33 | namespace mbed { 34 | namespace util { 35 | 36 | /** Shared pointer class. 37 | * 38 | * Similar to std::shared_ptr in C++11. 39 | * 40 | * Usage: SharedPointer POINTER(new class()) 41 | * 42 | * When POINTER is passed around by value the copy constructor and 43 | * destructor counts the number of references to the original object. 44 | * If the counter reaches zero, delete is called on the object pointed to. 45 | * 46 | * To avoid loops, "weak" references should be used by calling the original 47 | * pointer directly through POINTER.get(). 48 | */ 49 | 50 | template 51 | class SharedPointer { 52 | public: 53 | /** 54 | * @brief Create empty SharedPointer not pointing to anything. 55 | * @details Used for variable declaration. 56 | */ 57 | SharedPointer(): pointer(NULL), counter(NULL) { 58 | CORE_UTIL_SHAREDPOINTER_DEBUG("SP: %p [%p: %p]\r\n", this, pointer, counter); 59 | } 60 | 61 | /** 62 | * @brief Create new SharedPointer 63 | * @param _pointer Pointer to take control over 64 | */ 65 | SharedPointer(T* _pointer): pointer(_pointer) { 66 | CORE_UTIL_ASSERT(pointer); 67 | 68 | // allocate counter on the heap so it can be shared 69 | UAllocTraits_t traits = {0}; 70 | counter = (uint32_t*) mbed_ualloc(sizeof(uint32_t), traits); 71 | 72 | // initialize counter to 1 73 | CORE_UTIL_ASSERT(counter); 74 | *counter = 1; 75 | 76 | CORE_UTIL_SHAREDPOINTER_DEBUG("SP: %p [%p: %p = %lu]\r\n", this, pointer, counter, *counter); 77 | } 78 | 79 | /** 80 | * @brief Destructor. 81 | * @details Decrement reference counter and delete object if no longer pointed to. 82 | */ 83 | ~SharedPointer() { 84 | decrementCounter(); 85 | } 86 | 87 | /** 88 | * @brief Copy constructor. 89 | * @details Create new SharePointer from other SharedPointer by 90 | * copying pointer to original object and pointer to counter. 91 | * @param source Object being copied from. 92 | */ 93 | SharedPointer(const SharedPointer& source): pointer(source.pointer), counter(source.counter) { 94 | // increment reference counter 95 | if (counter) { 96 | (*counter)++; 97 | } 98 | 99 | CORE_UTIL_SHAREDPOINTER_DEBUG("SP&: %p = %p [%p: %p = %lu]\r\n", this, &source, pointer, counter, *counter); 100 | } 101 | 102 | /** 103 | * @brief Assignment operator. 104 | * @details Cleanup previous reference and assign new pointer and counter. 105 | * @param source Object being assigned from. 106 | * @return Object being assigned. 107 | */ 108 | SharedPointer operator=(const SharedPointer& source) { 109 | if (this != &source) { 110 | // clean up by decrementing counter 111 | decrementCounter(); 112 | 113 | // assign new values 114 | pointer = source.get(); 115 | counter = source.getCounter(); 116 | 117 | // increment new counter 118 | if (counter) { 119 | (*counter)++; 120 | } 121 | 122 | CORE_UTIL_SHAREDPOINTER_DEBUG("SP=: %p = %p [%p: %p = %lu]\r\n", this, &source, pointer, counter, *counter); 123 | } 124 | 125 | return *this; 126 | } 127 | 128 | /** 129 | * @brief Raw pointer accessor. 130 | * @details Get raw pointer to object pointed to. 131 | * @return Pointer. 132 | */ 133 | T* get() const { 134 | return pointer; 135 | } 136 | 137 | /** 138 | * @brief Reference count accessor. 139 | * @return Reference count. 140 | */ 141 | uint32_t use_count() const { 142 | if (counter) { 143 | return *counter; 144 | } else { 145 | return 0; 146 | } 147 | } 148 | 149 | /** 150 | * @brief Dereference object operator. 151 | * @details Override to return the object pointed to. 152 | */ 153 | T& operator*() const { 154 | CORE_UTIL_ASSERT(pointer); 155 | 156 | return *pointer; 157 | } 158 | 159 | /** 160 | * @brief Dereference object member operator. 161 | * @details Override to return return member in object pointed to. 162 | */ 163 | T* operator->() const { 164 | CORE_UTIL_ASSERT(pointer); 165 | 166 | return pointer; 167 | } 168 | 169 | /** 170 | * @brief Boolean conversion operator. 171 | * @return Whether or not the pointer is NULL. 172 | */ 173 | operator bool() const { 174 | CORE_UTIL_SHAREDPOINTER_DEBUG("bool: %p\r\n", pointer); 175 | 176 | return (pointer != 0); 177 | } 178 | 179 | private: 180 | /** 181 | * @brief Get pointer to reference counter. 182 | * @return Pointer to reference counter. 183 | */ 184 | uint32_t* getCounter() const { 185 | return counter; 186 | } 187 | 188 | /** 189 | * @brief Decrement reference counter. 190 | * @details If count reaches zero, free counter and delete object pointed to. 191 | */ 192 | void decrementCounter() { 193 | if (counter) { 194 | if (*counter == 1) { 195 | mbed_ufree(counter); 196 | delete pointer; 197 | 198 | CORE_UTIL_SHAREDPOINTER_DEBUG("~SP: %p [%p: %p = 0]\r\n", this, pointer, counter); 199 | } else { 200 | (*counter)--; 201 | 202 | CORE_UTIL_SHAREDPOINTER_DEBUG("~SP: %p [%p: %p = %lu]\r\n", this, pointer, counter, *counter); 203 | } 204 | } 205 | } 206 | 207 | private: 208 | // pointer to shared object 209 | T* pointer; 210 | 211 | // pointer to shared reference counter 212 | uint32_t* counter; 213 | }; 214 | 215 | /** Non-member relational operators. 216 | */ 217 | template 218 | bool operator== (const SharedPointer& lhs, const SharedPointer& rhs) { 219 | return (lhs.get() == rhs.get()); 220 | } 221 | 222 | template 223 | bool operator== (const SharedPointer& lhs, U rhs) { 224 | return (lhs.get() == (T*) rhs); 225 | } 226 | 227 | template 228 | bool operator== (U lhs, const SharedPointer& rhs) { 229 | return ((T*) lhs == rhs.get()); 230 | } 231 | 232 | /** Non-member relational operators. 233 | */ 234 | template 235 | bool operator!= (const SharedPointer& lhs, const SharedPointer& rhs) { 236 | return (lhs.get() != rhs.get()); 237 | } 238 | 239 | template 240 | bool operator!= (const SharedPointer& lhs, U rhs) { 241 | return (lhs.get() != (T*) rhs); 242 | } 243 | 244 | template 245 | bool operator!= (U lhs, const SharedPointer& rhs) { 246 | return ((T*) lhs != rhs.get()); 247 | } 248 | 249 | } // namespace util 250 | } // namespace mbed 251 | 252 | #endif // __CORE_UTIL_SHAREDPOINTER_H__ 253 | -------------------------------------------------------------------------------- /core-util/assert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __CORE_UTIL_ASSERT_H__ 19 | #define __CORE_UTIL_ASSERT_H__ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | #ifdef NDEBUG 26 | #define CORE_UTIL_ASSERT(expr) ((void)0) 27 | #define CORE_UTIL_ASSERT_MSG(expr, msg) ((void)0) 28 | #else 29 | #define CORE_UTIL_ASSERT(expr) \ 30 | do { \ 31 | if (!(expr)) { \ 32 | core_util_assert_internal(#expr, __FILE__, __LINE__, NULL); \ 33 | } \ 34 | } while (0) 35 | #define CORE_UTIL_ASSERT_MSG(expr, msg) \ 36 | do { \ 37 | if (!(expr)) { \ 38 | core_util_assert_internal(#expr, __FILE__, __LINE__, msg); \ 39 | } \ 40 | } while (0) 41 | 42 | #endif 43 | 44 | #define CORE_UTIL_RUNTIME_ERROR(...) core_util_runtime_error_internal(__FILE__, __LINE__, __VA_ARGS__) 45 | 46 | void core_util_runtime_error_internal(const char *fname, int line, const char* fmt, ...); 47 | void core_util_assert_internal(const char* expr, const char *fname, int line, const char *msg); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif // #ifndef __CORE_UTIL_ASSERT_H__ 54 | 55 | -------------------------------------------------------------------------------- /core-util/atomic_ops.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __MBED_UTIL_ATOMIC_OPS_H__ 19 | #define __MBED_UTIL_ATOMIC_OPS_H__ 20 | 21 | #include 22 | #include "core-util/CriticalSectionLock.h" 23 | 24 | namespace mbed { 25 | namespace util { 26 | 27 | /** 28 | * Atomic compare and set. It compares the contents of a memory location to a 29 | * given value and, only if they are the same, modifies the contents of that 30 | * memory location to a given new value. This is done as a single atomic 31 | * operation. The atomicity guarantees that the new value is calculated based on 32 | * up-to-date information; if the value had been updated by another thread in 33 | * the meantime, the write would fail due to a mismatched expectedCurrentValue. 34 | * 35 | * Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect 36 | * you to the article on compare-and swap]. 37 | * 38 | * @param ptr The target memory location. 39 | * @param[in,out] expectedCurrentValue A pointer to some location holding the 40 | * expected current value of the data being set atomically. 41 | * The computed 'desiredValue' should be a function of this current value. 42 | * @Note: This is an in-out parameter. In the 43 | * failure case of atomic_cas (where the 44 | * destination isn't set), the pointee of expectedCurrentValue is 45 | * updated with the current value. 46 | * @param[in] desiredValue The new value computed based on '*expectedCurrentValue'. 47 | * 48 | * @return true if the memory location was atomically 49 | * updated with the desired value (after verifying 50 | * that it contained the expectedCurrentValue), 51 | * false otherwise. In the failure case, 52 | * exepctedCurrentValue is updated with the new 53 | * value of the target memory location. 54 | * 55 | * pseudocode: 56 | * function cas(p : pointer to int, old : pointer to int, new : int) returns bool { 57 | * if *p != *old { 58 | * *old = *p 59 | * return false 60 | * } 61 | * *p = new 62 | * return true 63 | * } 64 | * 65 | * @Note: In the failure case (where the destination isn't set), the value 66 | * pointed to by expectedCurrentValue is still updated with the current value. 67 | * This property helps writing concise code for the following incr: 68 | * 69 | * function incr(p : pointer to int, a : int) returns int { 70 | * done = false 71 | * *value = *p // This fetch operation need not be atomic. 72 | * while not done { 73 | * done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success 74 | * } 75 | * return value + a 76 | * } 77 | * 78 | * The following is the generic implementation. It can be specialized using 79 | * load-store-exclusive primitives for architectures offering appropriate 80 | * instructions. The generic implementation applies for architectures lacking 81 | * load-store-exclusive primitives, or when matching against target types larger 82 | * than the word-size. 83 | */ 84 | template 85 | bool atomic_cas(T *ptr, T *expectedCurrentValue, T desiredValue) 86 | { 87 | bool rc = true; 88 | 89 | CriticalSectionLock lock; 90 | 91 | T currentValue = *ptr; 92 | if (currentValue == *expectedCurrentValue) { 93 | *ptr = desiredValue; 94 | } else { 95 | *expectedCurrentValue = currentValue; 96 | rc = false; 97 | } 98 | 99 | return rc; 100 | } 101 | 102 | /** 103 | * Atomic increment. 104 | * @param valuePtr Target memory location being incremented. 105 | * @param delta The amount being incremented. 106 | * @return The new incremented value. 107 | */ 108 | template 109 | T atomic_incr(T *valuePtr, T delta) 110 | { 111 | T oldValue = *valuePtr; 112 | while (true) { 113 | const T newValue = oldValue + delta; 114 | if (atomic_cas(valuePtr, &oldValue, newValue)) { 115 | return newValue; 116 | } 117 | } 118 | } 119 | /** 120 | * Atomic decrement. 121 | * @param valuePtr Target memory location being decremented. 122 | * @param delta The amount being decremented. 123 | * @return The new decremented value. 124 | */ 125 | template 126 | T atomic_decr(T *valuePtr, T delta) 127 | { 128 | T oldValue = *valuePtr; 129 | while (true) { 130 | const T newValue = oldValue - delta; 131 | if (atomic_cas(valuePtr, &oldValue, newValue)) { 132 | return newValue; 133 | } 134 | } 135 | } 136 | 137 | /* For ARMv7-M and above, we use the load/store-exclusive instructions to 138 | * implement atomic_cas, so we provide three template specializations 139 | * corresponding to the byte, half-word, and word variants of the instructions. 140 | */ 141 | #if (__CORTEX_M >= 0x03) 142 | template<> 143 | bool atomic_cas(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue); 144 | template<> 145 | bool atomic_cas(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue); 146 | template<> 147 | bool atomic_cas(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue); 148 | 149 | template<> 150 | uint8_t atomic_incr(uint8_t * valuePtr, uint8_t delta); 151 | template<> 152 | uint16_t atomic_incr(uint16_t * valuePtr, uint16_t delta); 153 | template<> 154 | uint32_t atomic_incr(uint32_t * valuePtr, uint32_t delta); 155 | 156 | template<> 157 | uint8_t atomic_decr(uint8_t * valuePtr, uint8_t delta); 158 | template<> 159 | uint16_t atomic_decr(uint16_t * valuePtr, uint16_t delta); 160 | template<> 161 | uint32_t atomic_decr(uint32_t * valuePtr, uint32_t delta); 162 | #endif /* #if (__CORTEX_M >= 0x03) */ 163 | 164 | } // namespace util 165 | } // namespace mbed 166 | 167 | #endif // #ifndef __MBED_UTIL_ATOMIC_OPS_H__ 168 | -------------------------------------------------------------------------------- /core-util/core-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __CORE_UTIL_CORE_UTIL_H__ 19 | #define __CORE_UTIL_CORE_UTIL_H__ 20 | 21 | // this file used to include the definitions now in assert.h, forward the 22 | // include for compatibility: 23 | #warning "core-util/core-util.h is deprecated: use core-util/assert.h instead" 24 | #include "./assert.h" 25 | 26 | #endif // ndef __CORE_UTIL_CORE_UTIL_H__ 27 | -------------------------------------------------------------------------------- /core-util/critical.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2016, ARM Limited, All Rights Reserved 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef __MBED_UTIL_CRITICAL_H__ 19 | #define __MBED_UTIL_CRITICAL_H__ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | /** Mark the start of a critical section 26 | * 27 | * This function should be called to mark the start of a critical section of code. 28 | * \note 29 | * NOTES: 30 | * 1) The use of this style of critical section is targetted at C based implementations. 31 | * 2) These critical sections can be nested. 32 | * 3) The interrupt enable state on entry to the first critical section (of a nested set, or single 33 | * section) will be preserved on exit from the section. 34 | * 4) This implementation will currently only work on code running in privileged mode. 35 | */ 36 | void core_util_critical_section_enter(); 37 | 38 | /** Mark the end of a critical section 39 | * 40 | * This function should be called to mark the end of a critical section of code. 41 | * \note 42 | * NOTES: 43 | * 1) The use of this style of critical section is targetted at C based implementations. 44 | * 2) These critical sections can be nested. 45 | * 3) The interrupt enable state on entry to the first critical section (of a nested set, or single 46 | * section) will be preserved on exit from the section. 47 | * 4) This implementation will currently only work on code running in privileged mode. 48 | */ 49 | void core_util_critical_section_exit(); 50 | 51 | #ifdef __cplusplus 52 | } // extern "C" 53 | #endif 54 | 55 | 56 | #endif // __MBED_UTIL_CRITICAL_H__ 57 | -------------------------------------------------------------------------------- /core-util/sbrk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #ifndef __MBED_ALLOC_H 18 | #define __MBED_ALLOC_H 19 | 20 | #include 21 | 22 | #if defined(__ARMCC_VERSION) 23 | # include 24 | # define PREFIX(x) _sys##x 25 | # define OPEN_MAX _SYS_OPEN 26 | # ifdef __MICROLIB 27 | # pragma import(__use_full_stdio) 28 | # endif 29 | 30 | #elif defined(__ICCARM__) 31 | # include 32 | # define PREFIX(x) _##x 33 | # define OPEN_MAX 16 34 | 35 | # define STDIN_FILENO 0 36 | # define STDOUT_FILENO 1 37 | # define STDERR_FILENO 2 38 | 39 | #else 40 | # ifndef TARGET_LIKE_POSIX 41 | # include 42 | # else 43 | # include 44 | # endif 45 | # define PREFIX(x) x 46 | #endif 47 | 48 | #ifndef pid_t 49 | typedef int pid_t; 50 | #endif 51 | #ifndef caddr_t 52 | typedef char * caddr_t; 53 | #endif 54 | 55 | #ifndef SBRK_ALIGN 56 | #define SBRK_ALIGN 8U 57 | #endif 58 | #if (SBRK_ALIGN & (SBRK_ALIGN-1)) 59 | #error SBRK_ALIGN must be a power of 2 60 | #endif 61 | 62 | #ifndef SBRK_INC_MIN 63 | #define SBRK_INC_MIN (SBRK_ALIGN) 64 | #endif 65 | 66 | #ifndef KRBS_ALIGN 67 | #define KRBS_ALIGN 8U 68 | #endif 69 | #if (KRBS_ALIGN & (KRBS_ALIGN-1)) 70 | #error KRBS_ALIGN must be a power of 2 71 | #endif 72 | 73 | #ifndef KRBS_INC_MIN 74 | #define KRBS_INC_MIN (KRBS_ALIGN) 75 | #endif 76 | 77 | /** 78 | * Here's a picture to explain the mbed OS memory layout. It should help with 79 | * some of the concepts below. 80 | * 81 | * | inaccessible | 82 | * | or RAM-end | 83 | * high addrs +--------------+ +--+--+ 84 | * | krbs_start | | 85 | * | + | | 86 | * | | | | 87 | * | | | | 88 | * | v | | 89 | * | | | 90 | * | Free store | heap_size 91 | * | | | 92 | * | ^ | | 93 | * | | | | 94 | * | | | | 95 | * | + | | 96 | * | sbrk_start | | 97 | * +--------------+ +--+--+ 98 | * | | 99 | * | BSS | 100 | * | | 101 | * +--------------+ 102 | * | | 103 | * | Data | 104 | * | | 105 | * +---------+----+ 106 | * | | | 107 | * | stack | | 108 | * | v | 109 | * | | 110 | * low addrs +--------------+ 111 | * | inaccessible | 112 | * | or RAM-start | 113 | */ 114 | 115 | /** 116 | * __heap_size is a symbol defined by the yotta target to contain the size of 117 | * the free-store. In mbed OS, this is typically defined in the linker script 118 | * associated with the target. The value is resolved at link time and is 119 | * available within the program using the const R-value expression `&__heap_size`. 120 | * 121 | * For some targets, __heap_size may also be given a value programmatically by 122 | * the application during system startup; in this case, it is available 123 | * as a regular extern const L-value symbol. 124 | * 125 | * The macro MBED_HEAP_SIZE adds a level of indirection to abstract __heap_size. 126 | */ 127 | #ifndef MBED_HEAP_SIZE 128 | # ifndef TARGET_LIKE_POSIX 129 | # ifdef __ARMCC_VERSION 130 | # define __heap_size (Image$$ARM_LIB_HEAP$$ZI$$Length) 131 | # endif 132 | extern unsigned int __heap_size; 133 | # define MBED_HEAP_SIZE ((ptrdiff_t)&__heap_size) 134 | # else 135 | extern unsigned int __heap_size; 136 | # define MBED_HEAP_SIZE ((ptrdiff_t) __heap_size) 137 | # endif 138 | #endif /* #ifndef MBED_HEAP_SIZE */ 139 | 140 | /** 141 | * The symbols __mbed_sbrk_start and __mbed_krbs_start are defined by the yotta- 142 | * target to mark the boundary of the free-store. In mbed OS, these are 143 | * typically defined in the linker script associated with the target. The 144 | * values are resolved at link time and are available within the program using 145 | * toolchain specific const R-value expressions. 146 | * 147 | * For some targets, sbrk_start and krbs_start may also be given a value 148 | * programmatically by the application during system startup; in this case, 149 | * these are available as a regular extern const L-value symbols. 150 | * 151 | * The macros MBED_SBRK_START and MBED_KRBS_START add a level of indirection to 152 | * abstract these symbols. 153 | */ 154 | #if !defined(MBED_SBRK_START) || !defined(MBED_KRBS_START) 155 | # ifndef TARGET_LIKE_POSIX 156 | # ifdef __ARMCC_VERSION 157 | # define __mbed_sbrk_start (Image$$ARM_LIB_HEAP$$Base) 158 | # define __mbed_krbs_start (Image$$ARM_LIB_HEAP$$ZI$$Limit) 159 | # pragma import(__use_two_region_memory) 160 | # endif /* #ifdef __ARMCC_VERSION */ 161 | extern unsigned int __mbed_sbrk_start; 162 | extern unsigned int __mbed_krbs_start; 163 | # define MBED_SBRK_START &__mbed_sbrk_start 164 | # define MBED_KRBS_START &__mbed_krbs_start 165 | # else /* #ifdef TARGET_LIKE_POSIX */ 166 | extern void *__mbed_sbrk_start; 167 | extern void *__mbed_krbs_start; 168 | # define MBED_SBRK_START __mbed_sbrk_start 169 | # define MBED_KRBS_START __mbed_krbs_start 170 | # endif /* #ifdef TARGET_LIKE_POSIX */ 171 | #endif 172 | 173 | #ifdef __cplusplus 174 | extern "C" { 175 | #endif 176 | void * mbed_sbrk(ptrdiff_t size); 177 | void * mbed_krbs(const ptrdiff_t size); 178 | void * mbed_krbs_ex(const ptrdiff_t size, ptrdiff_t *actual); 179 | #ifdef __cplusplus 180 | } 181 | #endif 182 | 183 | 184 | #endif // __MBED_ALLOC_H 185 | -------------------------------------------------------------------------------- /core-util/uninitialized.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015-2016 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #ifndef __CORE_UTIL_UNINITIALIZED_H__ 18 | #define __CORE_UTIL_UNINITIALIZED_H__ 19 | 20 | /** 21 | * The following macros are used to place uninitialized data in a dedicated 22 | * section, which is not touched by the C/C++ library at startup time. They can 23 | * be used, for example, to hold data and state across reboots. 24 | * 25 | * Note: These macros require additional support from the platform linker 26 | * script. 27 | * 28 | * In GCC: 29 | * .uninitialized (NOLOAD): 30 | * { 31 | * . = ALIGN(32); 32 | * __uninitialized_start = .; 33 | * *(.uninitialized) 34 | * KEEP(*(.keep.uninitialized)) 35 | * . = ALIGN(32); 36 | * __uninitialized_end = .; 37 | * } > RAM 38 | * 39 | * In ARMCC: 40 | * ER_UNINITIALIZED +0 UNINIT NOCOMPRESS 41 | { 42 | * (.keep.uninitialized) 43 | * (.uninitialized) 44 | } 45 | * which also requires an additional linker option: 46 | * set(CMAKE_EXE_LINKER_FLAGS_INIT 47 | * "${CMAKE_EXE_LINKER_FLAGS_INIT} --keep=\"*(.keep*)\"") 48 | * to make sure that unused symbols are not discarded. The GNU extensions must 49 | * be enabled (--gnu). 50 | */ 51 | 52 | #if defined(__GNUC__) || defined (__CC_ARM) || defined(__clang__) 53 | 54 | #ifndef __uninitialized 55 | #define __uninitialized __attribute__((section(".uninitialized"))) 56 | #endif 57 | 58 | #ifndef __force_uninitialized 59 | #define __force_uninitialized __attribute__((section(".keep.uninitialized"))) 60 | #endif 61 | 62 | #else 63 | 64 | #error "This compiler is not yet supported by core-util/uninitialized.h." 65 | 66 | #endif /* defined(__GNUC__) || defined (__CC_ARM) || defined(__clang__) */ 67 | 68 | #endif /* __CORE_UTIL_UNINITIALIZED_H__ */ 69 | -------------------------------------------------------------------------------- /coverage.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "debug":{ 4 | "options" : { 5 | "coverage" : { 6 | "modules" : { 7 | "core-util" : true 8 | } 9 | } 10 | } 11 | }, 12 | "mbed-os": { 13 | "stdio": { 14 | "default-baud": 115200 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "core-util", 3 | "version": "1.8.0", 4 | "description": "mbed utilities library", 5 | "keywords": [ 6 | "mbed", 7 | "mbed-official" 8 | ], 9 | "licenses": [ 10 | { 11 | "url": "https://spdx.org/licenses/Apache-2.0", 12 | "type": "Apache-2.0" 13 | } 14 | ], 15 | "author": "Bogdan Marinescu ", 16 | "repository": { 17 | "url": "git@github.com:ARMmbed/core-util.git", 18 | "type": "git" 19 | }, 20 | "homepage": "https://github.com/ARMmbed/core-util", 21 | "dependencies": { 22 | "ualloc": "*" 23 | }, 24 | "targetDependencies": { 25 | "mbed": { 26 | "cmsis-core": "^1.0.0", 27 | "mbed-drivers": ">=0.11.0,<2.0.0" 28 | } 29 | }, 30 | "testDependencies": { 31 | "unity": "^2.0.0", 32 | "greentea-client": ">=0.1.4,<2.0.0" 33 | }, 34 | "scripts": { 35 | "testReporter": [ 36 | "mbedgt", 37 | "--digest", 38 | "stdin", 39 | "-v", 40 | "-V" 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /source/ExtendablePoolAllocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core-util/ExtendablePoolAllocator.h" 19 | #include "core-util/PoolAllocator.h" 20 | #include "core-util/CriticalSectionLock.h" 21 | #include "ualloc/ualloc.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace mbed { 28 | namespace util { 29 | 30 | ExtendablePoolAllocator::ExtendablePoolAllocator(): _head(NULL) { 31 | } 32 | 33 | bool ExtendablePoolAllocator::init(size_t initial_elements, size_t new_pool_elements, size_t element_size, UAllocTraits_t alloc_traits, unsigned alignment) { 34 | if (_head != NULL) 35 | return false; // don't initialize twice 36 | _new_pool_elements = new_pool_elements; 37 | _element_size = PoolAllocator::align_up(element_size, alignment); 38 | _alloc_traits = alloc_traits; 39 | _alignment = alignment; 40 | _head = create_new_pool(initial_elements, NULL); 41 | return _head != NULL; 42 | } 43 | 44 | ExtendablePoolAllocator::~ExtendablePoolAllocator() { 45 | pool_link *crt = _head, *prev; 46 | void *area; 47 | while (crt != NULL) { 48 | prev = crt->prev; 49 | area = crt->allocator.get_start_address(); 50 | crt->~pool_link(); // this assumes that the PoolAllocator doesn't free its storage! 51 | mbed_ufree(area); 52 | crt = prev; 53 | } 54 | } 55 | 56 | void* ExtendablePoolAllocator::alloc() { 57 | // Try the current pool first 58 | if (NULL == _head) 59 | return NULL; 60 | void *blk = _head->allocator.alloc(); 61 | if (blk != NULL) 62 | return blk; 63 | 64 | // Try all the other pools 65 | pool_link *prev_head = _head; 66 | pool_link *crt = prev_head->prev; 67 | while (crt != NULL) { 68 | if ((blk = crt->allocator.alloc()) != NULL) { 69 | return blk; 70 | } 71 | crt = crt->prev; 72 | } 73 | 74 | // Not enough space, need to create another pool 75 | { 76 | CriticalSectionLock lock; // execute with interrupts disabled 77 | if (_head != prev_head) { // if someone else already allocated a new pool, use it 78 | if ((blk = _head->allocator.alloc()) != NULL) { 79 | return blk; 80 | } 81 | } 82 | // Create a new pool and link it in the list of pools 83 | if ((crt = create_new_pool(_new_pool_elements, _head)) != NULL) { 84 | _head = crt; 85 | return crt->allocator.alloc(); 86 | } 87 | } 88 | return NULL; 89 | } 90 | 91 | void *ExtendablePoolAllocator::calloc() { 92 | uint32_t *blk = (uint32_t*)alloc(); 93 | 94 | if (blk == NULL) 95 | return NULL; 96 | for (unsigned i = 0; i < _element_size / 4; i ++, blk ++) 97 | *blk = 0; 98 | return blk; 99 | } 100 | 101 | void ExtendablePoolAllocator::free(void *p) { 102 | pool_link *crt = _head; 103 | 104 | // Delegate freeing to the pool that owns the pointer 105 | while (crt != NULL) { 106 | if (crt->allocator.owns(p)) { 107 | crt->allocator.free(p); 108 | return; 109 | } 110 | crt = crt->prev; 111 | } 112 | } 113 | 114 | unsigned ExtendablePoolAllocator::get_num_pools() const { 115 | pool_link *crt = _head; 116 | unsigned cnt = 0; 117 | 118 | while (crt != NULL) { 119 | cnt ++; 120 | crt = crt->prev; 121 | } 122 | return cnt; 123 | } 124 | 125 | ExtendablePoolAllocator::pool_link* ExtendablePoolAllocator::create_new_pool(size_t elements, pool_link *prev) const { 126 | // Create a pool instance + the actual pool space + a link to the previous pool allocator in the chain in a contigous memory area. 127 | // Layout: pool storage area | pool_link structure (pointer to previous pool and PoolAllocator instance) 128 | // Since the pool storage area aligns all the allocations internally to at least 4 bytes, the pool_link address will be correctly aligned 129 | size_t pool_storage_size = PoolAllocator::get_pool_size(elements, _element_size, _alignment); 130 | void *temp = mbed_ualloc(pool_storage_size + sizeof(pool_link), _alloc_traits); 131 | if (temp == NULL) 132 | return NULL; 133 | pool_link *p = new((char*)temp + pool_storage_size) pool_link(temp, elements, _element_size, _alignment, prev); 134 | return p; 135 | } 136 | 137 | } // namespace util 138 | } // namespace mbed 139 | 140 | -------------------------------------------------------------------------------- /source/PoolAllocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core-util/PoolAllocator.h" 19 | #include 20 | #include 21 | #include 22 | 23 | #include "core-util/atomic_ops.h" 24 | 25 | namespace mbed { 26 | namespace util { 27 | 28 | PoolAllocator::PoolAllocator(void *start, size_t elements, size_t element_size, unsigned alignment): 29 | _start(start), _element_size(align_up(element_size, alignment)) { 30 | _end = (void*)((uint8_t*)start + _element_size * elements); 31 | _init(); 32 | } 33 | 34 | void* PoolAllocator::alloc() { 35 | uintptr_t prev_free = reinterpret_cast(_free_block); 36 | while (true) { 37 | if (0 == prev_free) 38 | return NULL; 39 | void **const new_free = (void **)(*((void **)prev_free)); 40 | if (atomic_cas((uintptr_t*)&_free_block, &prev_free, (uintptr_t)new_free)) { 41 | return (void*)prev_free; 42 | } 43 | } 44 | } 45 | 46 | void PoolAllocator::free(void* p) { 47 | if (owns(p)) { 48 | while (true) { 49 | uintptr_t prev_free = reinterpret_cast(_free_block); 50 | 51 | *((void**)p) = (void*)prev_free; 52 | if (atomic_cas((uintptr_t*)&_free_block, &prev_free, (uintptr_t)p)) { 53 | break; 54 | } 55 | } 56 | } 57 | } 58 | 59 | bool PoolAllocator::owns(const void *p) const { 60 | return (p >= _start) && (p < _end); 61 | } 62 | 63 | size_t PoolAllocator::get_pool_size(size_t elements, size_t element_size, unsigned alignment) { 64 | element_size = align_up(element_size, alignment); 65 | return element_size * elements; 66 | } 67 | 68 | void* PoolAllocator::calloc() { 69 | uint32_t *blk = (uint32_t*)alloc(); 70 | 71 | if (NULL == blk) 72 | return NULL; 73 | for(unsigned i = 0; i < _element_size / 4; i ++, blk ++) 74 | *blk = 0; 75 | return blk; 76 | } 77 | 78 | uint32_t PoolAllocator:: align_up(uint32_t n, uint32_t alignment) { 79 | return (n + alignment - 1) & ~(alignment - 1); 80 | } 81 | 82 | void* PoolAllocator::get_start_address() const { 83 | return _start; 84 | } 85 | 86 | void PoolAllocator::_init() { 87 | _free_block = _start; 88 | 89 | // Link all free blocks using offsets. 90 | void* next; 91 | void* blk = _free_block; 92 | 93 | while(true) { 94 | next = ((uint8_t *) blk) + _element_size; 95 | if(next > _end) 96 | break; 97 | *((void **)blk) = next; 98 | blk = next; 99 | } 100 | // count back one block and mark it as the last one 101 | blk = ((uint8_t *) blk) - _element_size; 102 | *((void **)blk) = 0; 103 | } 104 | 105 | } // namespace util 106 | } // namespace mbed 107 | 108 | -------------------------------------------------------------------------------- /source/assert_mbed.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifdef TARGET_LIKE_MBED // only include this code for mbed targets 19 | 20 | // device.h header file defines whether we have files or not, so must come 21 | // first 22 | #include "device.h" 23 | 24 | #include 25 | #include 26 | #if DEVICE_STDIO_MESSAGES 27 | #include 28 | #endif 29 | 30 | #include "mbed-drivers/mbed_interface.h" 31 | #include "core-util/assert.h" 32 | 33 | void core_util_runtime_error_internal(const char *file, int line, const char* format, ...) { 34 | #if DEVICE_STDIO_MESSAGES 35 | fprintf(stderr, "Runtime error in file %s, line %d: ", file, line); 36 | va_list arg; 37 | va_start(arg, format); 38 | vfprintf(stderr, format, arg); 39 | va_end(arg); 40 | fprintf(stderr, "\n"); 41 | #endif 42 | exit(1); 43 | } 44 | 45 | void core_util_assert_internal(const char *expr, const char *file, int line, const char* msg) 46 | { 47 | #if DEVICE_STDIO_MESSAGES 48 | fprintf(stderr, "assertation failed: %s, file: %s, line %d", expr, file, line); 49 | if (msg) 50 | fprintf(stderr, " (%s)", msg); 51 | fprintf(stderr, "\n"); 52 | #endif 53 | mbed_die(); 54 | } 55 | 56 | #endif // #ifdef TARGET_LIKE_MBED 57 | 58 | -------------------------------------------------------------------------------- /source/assert_posix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifdef TARGET_LIKE_POSIX 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "core-util/assert.h" 25 | 26 | void core_util_runtime_error_internal(const char *file, int line, const char* format, ...) { 27 | fprintf(stderr, "Runtime error in file %s, line %d: ", file, line); 28 | va_list arg; 29 | va_start(arg, format); 30 | vfprintf(stderr, format, arg); 31 | va_end(arg); 32 | 33 | exit(1); 34 | } 35 | 36 | void core_util_assert_internal(const char *expr, const char *file, int line, const char* msg) 37 | { 38 | fprintf(stderr, "assertation failed: %s, file: %s, line %d", expr, file, line); 39 | if (msg) 40 | fprintf(stderr, " (%s)", msg); 41 | fprintf(stderr, "\r\n"); 42 | 43 | abort(); 44 | } 45 | 46 | #endif // #ifdef TARGET_LIKE_POSIX 47 | -------------------------------------------------------------------------------- /source/atomic_ops.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core-util/atomic_ops.h" 19 | #if defined(TARGET_LIKE_MBED) 20 | #include "cmsis.h" 21 | #endif 22 | 23 | namespace mbed { 24 | namespace util { 25 | 26 | /* For ARMv7-M and above, we use the load/store-exclusive instructions to 27 | * implement atomic_cas, so we provide three template specializations 28 | * corresponding to the byte, half-word, and word variants of the instructions. 29 | */ 30 | #if (__CORTEX_M >= 0x03) 31 | 32 | template<> 33 | bool atomic_cas(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue) 34 | { 35 | uint8_t currentValue = __LDREXB(ptr); 36 | if (currentValue != *expectedCurrentValue) { 37 | *expectedCurrentValue = currentValue; 38 | __CLREX(); 39 | return false; 40 | } 41 | 42 | return !__STREXB(desiredValue, ptr); 43 | } 44 | 45 | template<> 46 | bool atomic_cas(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue) 47 | { 48 | uint16_t currentValue = __LDREXH(ptr); 49 | if (currentValue != *expectedCurrentValue) { 50 | *expectedCurrentValue = currentValue; 51 | __CLREX(); 52 | return false; 53 | } 54 | 55 | return !__STREXH(desiredValue, ptr); 56 | } 57 | 58 | template<> 59 | bool atomic_cas(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue) 60 | { 61 | uint32_t currentValue = __LDREXW(ptr); 62 | if (currentValue != *expectedCurrentValue) { 63 | *expectedCurrentValue = currentValue; 64 | __CLREX(); 65 | return false; 66 | } 67 | 68 | return !__STREXW(desiredValue, ptr); 69 | } 70 | 71 | template<> 72 | uint8_t atomic_incr(uint8_t * valuePtr, uint8_t delta) 73 | { 74 | uint8_t newValue; 75 | do { 76 | newValue = __LDREXB(valuePtr) + delta; 77 | } while (__STREXB(newValue, valuePtr)); 78 | return newValue; 79 | } 80 | template<> 81 | uint16_t atomic_incr(uint16_t * valuePtr, uint16_t delta) 82 | { 83 | uint16_t newValue; 84 | do { 85 | newValue = __LDREXH(valuePtr) + delta; 86 | } while (__STREXH(newValue, valuePtr)); 87 | return newValue; 88 | } 89 | template<> 90 | uint32_t atomic_incr(uint32_t * valuePtr, uint32_t delta) 91 | { 92 | uint32_t newValue; 93 | do { 94 | newValue = __LDREXW(valuePtr) + delta; 95 | } while (__STREXW(newValue, valuePtr)); 96 | return newValue; 97 | } 98 | 99 | template<> 100 | uint8_t atomic_decr(uint8_t * valuePtr, uint8_t delta) 101 | { 102 | uint8_t newValue; 103 | do { 104 | newValue = __LDREXB(valuePtr) - delta; 105 | } while (__STREXB(newValue, valuePtr)); 106 | return newValue; 107 | } 108 | template<> 109 | uint16_t atomic_decr(uint16_t * valuePtr, uint16_t delta) 110 | { 111 | uint16_t newValue; 112 | do { 113 | newValue = __LDREXH(valuePtr) - delta; 114 | } while (__STREXH(newValue, valuePtr)); 115 | return newValue; 116 | } 117 | 118 | template<> 119 | uint32_t atomic_decr(uint32_t * valuePtr, uint32_t delta) 120 | { 121 | uint32_t newValue; 122 | do { 123 | newValue = __LDREXW(valuePtr) - delta; 124 | } while (__STREXW(newValue, valuePtr)); 125 | return newValue;} 126 | 127 | #endif /* #if (__CORTEX_M >= 0x03) */ 128 | 129 | } // namespace util 130 | } // namespace mbed 131 | -------------------------------------------------------------------------------- /source/critical.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2016, ARM Limited, All Rights Reserved 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // This critical section implementation is generic for mbed OS targets, 19 | // except Nordic ones 20 | #if defined(TARGET_LIKE_MBED) && !defined(TARGET_NORDIC) 21 | 22 | #include // uint32_t, UINT32_MAX 23 | #include // NULL 24 | #include "cmsis-core/core_generic.h" //__disable_irq, __enable_irq 25 | #include 26 | 27 | // Module include 28 | #include "core-util/critical.h" 29 | 30 | static volatile uint32_t interruptEnableCounter = 0; 31 | static volatile uint32_t critical_primask = 0; 32 | 33 | void core_util_critical_section_enter() 34 | { 35 | uint32_t primask = __get_PRIMASK(); // get the current interrupt enabled state 36 | __disable_irq(); 37 | 38 | // Save the interrupt enabled state as it was prior to any nested critical section lock use 39 | if (!interruptEnableCounter) { 40 | critical_primask = primask & 0x1; 41 | } 42 | 43 | /* If the interruptEnableCounter overflows or we are in a nested critical section and interrupts 44 | are enabled, then something has gone badly wrong thus assert an error. 45 | */ 46 | 47 | /* FIXME: This assertion needs to be commented out for the moment, as it 48 | * triggers a fault when uVisor is enabled. For more information on 49 | * the fault please checkout ARMmbed/mbed-drivers#176. */ 50 | /* assert(interruptEnableCounter < UINT32_MAX); */ 51 | if (interruptEnableCounter > 0) { 52 | /* FIXME: This assertion needs to be commented out for the moment, as it 53 | * triggers a fault when uVisor is enabled. For more information 54 | * on the fault please checkout ARMmbed/mbed-drivers#176. */ 55 | /* assert(primask & 0x1); */ 56 | } 57 | interruptEnableCounter++; 58 | } 59 | 60 | void core_util_critical_section_exit() 61 | { 62 | // If critical_section_enter has not previously been called, do nothing 63 | if (interruptEnableCounter) { 64 | 65 | uint32_t primask = __get_PRIMASK(); // get the current interrupt enabled state 66 | 67 | /* FIXME: This assertion needs to be commented out for the moment, as it 68 | * triggers a fault when uVisor is enabled. For more information 69 | * on the fault please checkout ARMmbed/mbed-drivers#176. */ 70 | /* assert(primask & 0x1); // Interrupts must be disabled on invoking an exit from a critical section */ 71 | 72 | interruptEnableCounter--; 73 | 74 | /* Only re-enable interrupts if we are exiting the last of the nested critical sections and 75 | interrupts were enabled on entry to the first critical section. 76 | */ 77 | if (!interruptEnableCounter && !critical_primask) { 78 | __enable_irq(); 79 | } 80 | } 81 | } 82 | 83 | #endif // defined(TARGET_LIKE_MBED) && !defined(TARGET_NORDIC) 84 | -------------------------------------------------------------------------------- /source/critical_nordic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2016, ARM Limited, All Rights Reserved 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifdef TARGET_NORDIC 19 | 20 | #include // uint32_t, UINT32_MAX 21 | #include // NULL 22 | #include //__disable_irq, __enable_irq 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | // Module include 29 | #include "core-util/critical.h" 30 | 31 | static volatile union { 32 | uint32_t _PRIMASK_state; 33 | uint8_t _sd_state; 34 | } _state = { 0 } ; 35 | static volatile uint32_t _entry_count = 0; 36 | static volatile bool _use_softdevice_routine = false; 37 | 38 | void core_util_critical_section_enter() 39 | { 40 | // if a critical section has already been entered, just update the counter 41 | if (_entry_count) { 42 | ++_entry_count; 43 | return; 44 | } 45 | 46 | // in this path, a critical section has never been entered 47 | uint32_t primask = __get_PRIMASK(); 48 | 49 | // if interrupts are enabled, try to use the soft device 50 | uint8_t sd_enabled; 51 | if ((primask == 0) && (sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && sd_enabled == 1) { 52 | // if the soft device can be use, use it 53 | sd_nvic_critical_region_enter(&_state._sd_state); 54 | _use_softdevice_routine = true; 55 | } else { 56 | // if interrupts where enabled, disable them 57 | if(primask == 0) { 58 | __disable_irq(); 59 | } 60 | 61 | // store the PRIMASK state, it will be restored at the end of the critical section 62 | _state._PRIMASK_state = primask; 63 | _use_softdevice_routine = false; 64 | } 65 | 66 | assert(_entry_count == 0); // entry count should always be equal to 0 at this point 67 | ++_entry_count; 68 | } 69 | 70 | void core_util_critical_section_exit() 71 | { 72 | assert(_entry_count > 0); 73 | --_entry_count; 74 | 75 | // If their is other segments which have entered the critical section, just leave 76 | if (_entry_count) { 77 | return; 78 | } 79 | 80 | // This is the last segment of the critical section, state should be restored as before entering 81 | // the critical section 82 | if (_use_softdevice_routine) { 83 | sd_nvic_critical_region_exit(_state._sd_state); 84 | } else { 85 | __set_PRIMASK(_state._PRIMASK_state); 86 | } 87 | } 88 | 89 | #endif //TARGET_NORDIC 90 | -------------------------------------------------------------------------------- /source/critical_posix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2016, ARM Limited, All Rights Reserved 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #if defined(TARGET_LIKE_POSIX) 19 | 20 | // It's probably a better idea to define _POSIX_SOURCE in the target description 21 | #ifndef _POSIX_SOURCE 22 | #define _POSIX_SOURCE 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | // Module include 31 | #include "core-util/critical.h" 32 | 33 | static volatile unsigned irq_nesting_depth; 34 | static sigset_t old_sig_set; 35 | 36 | void core_util_critical_section_enter() { 37 | if (++irq_nesting_depth > 1) { 38 | return; 39 | } 40 | 41 | int rc; 42 | sigset_t full_set; 43 | rc = sigfillset(&full_set); 44 | assert(rc == 0); 45 | rc = sigprocmask(SIG_BLOCK, &full_set, &old_sig_set); 46 | assert(rc == 0); 47 | } 48 | 49 | void core_util_critical_section_exit() { 50 | assert(irq_nesting_depth > 0); 51 | if (--irq_nesting_depth == 0) { 52 | int rc = sigprocmask(SIG_SETMASK, &old_sig_set, NULL); 53 | assert(rc == 0); 54 | } 55 | } 56 | 57 | #endif // defined(TARGET_LIKE_POSIX) 58 | 59 | -------------------------------------------------------------------------------- /source/sbrk.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "core-util/atomic_ops.h" 18 | #include "core-util/sbrk.h" 19 | 20 | #include 21 | 22 | void * volatile mbed_krbs_ptr = MBED_KRBS_START; 23 | void * volatile mbed_sbrk_ptr = MBED_SBRK_START; 24 | volatile ptrdiff_t mbed_sbrk_diff = MBED_HEAP_SIZE; 25 | 26 | void * mbed_sbrk(ptrdiff_t size) 27 | { 28 | if (size == 0) { 29 | return (void *) mbed_sbrk_ptr; 30 | } 31 | 32 | // align absolute size requested 33 | ptrdiff_t size_internal = abs(size); 34 | if ((uintptr_t)size_internal < SBRK_INC_MIN) { 35 | size_internal = SBRK_INC_MIN; 36 | } 37 | size_internal = ( size_internal + SBRK_ALIGN - 1) & ~(SBRK_ALIGN - 1); 38 | // it's min sized plus aligned, assign back the sign 39 | if (size < 0) { 40 | size_internal = -size_internal; 41 | } 42 | 43 | /* Decrement mbed_sbrk_diff by the size being allocated. */ 44 | ptrdiff_t ptr_diff = mbed_sbrk_diff; 45 | while (1) { 46 | if (size_internal > ptr_diff) { 47 | return (void *) -1; 48 | } 49 | if (mbed::util::atomic_cas((uint32_t *)&mbed_sbrk_diff, (uint32_t *)&ptr_diff, (uint32_t)(ptr_diff - size_internal))) { 50 | break; 51 | } 52 | } 53 | 54 | uintptr_t new_sbrk_ptr = mbed::util::atomic_incr((uint32_t *)&mbed_sbrk_ptr, (uint32_t)size_internal); 55 | return (void *)(new_sbrk_ptr - size_internal); 56 | } 57 | 58 | void * mbed_krbs(const ptrdiff_t size) 59 | { 60 | return mbed_krbs_ex(size, NULL); 61 | } 62 | 63 | void * mbed_krbs_ex(const ptrdiff_t size, ptrdiff_t *actual) 64 | { 65 | if (size == 0) { 66 | return (void *) mbed_krbs_ptr; 67 | } 68 | // krbs does not support deallocation. 69 | if (size < 0) { 70 | return (void *) -1; 71 | } 72 | 73 | uintptr_t size_internal = (uintptr_t)size; 74 | // Guarantee minimum allocation size 75 | if (size_internal < KRBS_INC_MIN) { 76 | size_internal = KRBS_INC_MIN; 77 | } 78 | size_internal = (size_internal + KRBS_ALIGN - 1) & ~(KRBS_ALIGN - 1); 79 | 80 | /* Decrement mbed_sbrk_diff by the size being allocated. */ 81 | ptrdiff_t ptr_diff = mbed_sbrk_diff; 82 | while (1) { 83 | if ((size_internal > (uintptr_t)ptr_diff) && (actual == NULL)) { 84 | return (void *) -1; 85 | } 86 | if (mbed::util::atomic_cas((uint32_t *)&mbed_sbrk_diff, (uint32_t *)&ptr_diff, (uint32_t)(ptr_diff - size_internal))) { 87 | break; 88 | } 89 | } 90 | 91 | return (void *)mbed::util::atomic_decr((uint32_t *)&mbed_krbs_ptr, (uint32_t)size_internal); 92 | } 93 | -------------------------------------------------------------------------------- /test/Array/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core-util/Array.h" 19 | #include "greentea-client/test_env.h" 20 | #include "mbed-drivers/mbed.h" 21 | #include "unity/unity.h" 22 | #include "utest/utest.h" 23 | #include 24 | #include 25 | 26 | using namespace utest::v1; 27 | using namespace mbed::util; 28 | 29 | static void test_pod() { 30 | Array array; 31 | 32 | const size_t initial_capacity = 20, grow_capacity = 12, alignment = 4; 33 | UAllocTraits_t traits = {0}; 34 | TEST_ASSERT_TRUE(array.init(initial_capacity, grow_capacity, traits, alignment)); 35 | 36 | // Start filling the array 37 | for (unsigned i = 0; i < initial_capacity; i ++ ) { 38 | array.push_back(i); 39 | } 40 | TEST_ASSERT_EQUAL(initial_capacity, array.get_num_elements()); 41 | for (unsigned i = 0; i < initial_capacity; i ++) { 42 | TEST_ASSERT_EQUAL(i, array[i]); 43 | } 44 | TEST_ASSERT_EQUAL(1, array.get_num_zones()); 45 | 46 | // Add another element, this should trigger the creation of another zone 47 | array.push_back(1000); 48 | TEST_ASSERT_EQUAL(2, array.get_num_zones()); 49 | TEST_ASSERT_EQUAL(initial_capacity + 1, array.get_num_elements()); 50 | // Fill the second zone too 51 | for (unsigned i = 1; i < grow_capacity; i ++) { 52 | array.push_back(1000 + i); 53 | } 54 | TEST_ASSERT_EQUAL(initial_capacity + grow_capacity, array.get_num_elements()); 55 | for (unsigned i = 0; i < grow_capacity; i ++) { 56 | TEST_ASSERT_EQUAL(1000 + i, array.at(i + initial_capacity)); 57 | } 58 | TEST_ASSERT_EQUAL(2, array.get_num_zones()); 59 | unsigned save_for_later = array[initial_capacity + grow_capacity - 1]; 60 | // Add yet another element, which should result in the creation of another zone 61 | array.push_back(10000); 62 | TEST_ASSERT_EQUAL(10000, array[initial_capacity + grow_capacity]); 63 | TEST_ASSERT_EQUAL(3, array.get_num_zones()); 64 | TEST_ASSERT_EQUAL(initial_capacity + grow_capacity + 1, array.get_num_elements()); 65 | 66 | // Remove the last element 67 | array.pop_back(); 68 | TEST_ASSERT_EQUAL(initial_capacity + grow_capacity, array.get_num_elements()); 69 | TEST_ASSERT_EQUAL(save_for_later, array[array.get_num_elements() - 1]); 70 | TEST_ASSERT_EQUAL(3, array.get_num_zones()); // the array doesn't (yet?) shrink 71 | 72 | // Simple bubble sort test illustrating moving around elements in the array 73 | const size_t total = initial_capacity + grow_capacity; 74 | for (unsigned i = 0; i < total; i ++) { 75 | array.at(i) = total - i - 1; 76 | } 77 | 78 | for (unsigned i = 0; i < total - 1; i ++) { 79 | for (unsigned j = i + 1; j < total; j ++) { 80 | if (array[i] > array[j]) { 81 | unsigned temp = array[i]; 82 | array[i] = array[j]; 83 | array[j] = temp; 84 | } 85 | } 86 | } 87 | for (unsigned i = 0; i < total; i ++) { 88 | TEST_ASSERT_EQUAL(i, array[i]); 89 | } 90 | 91 | TEST_ASSERT_EQUAL(3, array.get_num_zones()); 92 | } 93 | 94 | struct Test { 95 | Test(unsigned a = 0, uint8_t c = 0): _a(a), _c(c) { 96 | inst_count ++; 97 | } 98 | 99 | Test(const Test& t): _a(t._a), _c(t._c) { 100 | inst_count ++; 101 | } 102 | 103 | ~Test() { 104 | inst_count --; 105 | } 106 | 107 | bool operator ==(const Test& t) const { 108 | return (t._a == _a) && (t._c == _c); 109 | } 110 | 111 | unsigned _a; 112 | uint8_t _c; 113 | static int inst_count; 114 | }; 115 | 116 | int Test::inst_count = 0; 117 | 118 | static void test_non_pod() { 119 | { 120 | Array array; 121 | 122 | const size_t initial_capacity = 10, grow_capacity = 6, alignment = 4; 123 | UAllocTraits_t traits = {0}; 124 | TEST_ASSERT_TRUE(array.init(initial_capacity, grow_capacity, traits, alignment)); 125 | 126 | // Just fill the first part of the array and verify 127 | unsigned idx; 128 | for (idx = 0; idx < initial_capacity; idx ++) { 129 | array.push_back(Test(idx, 'a')); 130 | } 131 | for (idx = 0; idx < initial_capacity; idx ++) { 132 | TEST_ASSERT_TRUE(array[idx] == Test(idx, 'a')); 133 | } 134 | 135 | // Now override what we wrote with different data 136 | for (idx = 0; idx < initial_capacity; idx ++) { 137 | array[idx] = Test(idx, 'b'); 138 | } 139 | for (idx = 0; idx < initial_capacity; idx ++) { 140 | const Test& t = array[idx]; 141 | TEST_ASSERT_TRUE(t == Test(idx, 'b')); 142 | } 143 | 144 | // Pop the last element from array (checks if destructor is called) 145 | array.pop_back(); 146 | 147 | TEST_ASSERT_EQUAL(initial_capacity - 1, array.get_num_elements()); 148 | TEST_ASSERT_EQUAL(1, array.get_num_zones()); 149 | } 150 | TEST_ASSERT_EQUAL(0, Test::inst_count); 151 | } 152 | 153 | static status_t test_setup(const size_t number_of_cases) { 154 | GREENTEA_SETUP(5, "default_auto"); 155 | 156 | return greentea_test_setup_handler(number_of_cases); 157 | } 158 | 159 | status_t greentea_failure_handler(const Case *const source, const failure_t reason) { 160 | greentea_case_failure_abort_handler(source, reason); 161 | return STATUS_CONTINUE; 162 | } 163 | 164 | static Case cases[] = { 165 | Case("Array - test with plain old data", test_pod, greentea_failure_handler), 166 | Case("Array - test with complex data", test_non_pod, greentea_failure_handler) 167 | }; 168 | 169 | static Specification specification(test_setup, cases, greentea_test_teardown_handler); 170 | 171 | void app_start(int, char**) { 172 | Harness::run(specification); 173 | } 174 | 175 | -------------------------------------------------------------------------------- /test/BinaryHeap/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core-util/BinaryHeap.h" 19 | #include "greentea-client/test_env.h" 20 | #include "mbed-drivers/mbed.h" 21 | #include "unity/unity.h" 22 | #include "utest/utest.h" 23 | #include 24 | #include 25 | 26 | using namespace utest::v1; 27 | using namespace mbed::util; 28 | 29 | template 30 | static void test_heap(const T* data, unsigned data_size, const T* sorted_data, 31 | const T* to_remove, unsigned removed_size, const T* sorted_after_remove, 32 | const T& not_in_heap) { 33 | BinaryHeap heap; 34 | const size_t initial_capacity = data_size / 2, grow_capacity = (data_size * 3) / 2, alignment = 4; 35 | UAllocTraits_t traits = {0}; 36 | TEST_ASSERT_TRUE(heap.init(initial_capacity, grow_capacity, traits, alignment)); 37 | 38 | // Fill the heap with data 39 | for (unsigned i = 0; i < data_size; i++) { 40 | heap.insert(data[i]); 41 | TEST_ASSERT_TRUE(heap.is_consistent()); 42 | } 43 | TEST_ASSERT_EQUAL(data_size, heap.get_num_elements()); 44 | 45 | // Remove and check root at each step 46 | for (unsigned i = 0; i < data_size; i ++) { 47 | T root = heap.get_root(); 48 | TEST_ASSERT_TRUE(root == sorted_data[i]); 49 | heap.remove_root(); 50 | TEST_ASSERT_TRUE(heap.is_consistent()); 51 | } 52 | TEST_ASSERT_TRUE(heap.is_empty()); 53 | 54 | // Put everything back again 55 | for (unsigned i = 0; i < data_size; i++) { 56 | heap.insert(data[i]); 57 | TEST_ASSERT_TRUE(heap.is_consistent()); 58 | } 59 | TEST_ASSERT_EQUAL(data_size, heap.get_num_elements()); 60 | 61 | // And check removing 62 | for (unsigned i = 0; i < removed_size; i ++) { 63 | TEST_ASSERT_TRUE(heap.remove(to_remove[i])); 64 | TEST_ASSERT_TRUE(heap.is_consistent()); 65 | } 66 | TEST_ASSERT_TRUE(!heap.remove(not_in_heap)); // this element is not in the heap 67 | TEST_ASSERT_EQUAL(data_size - removed_size, heap.get_num_elements()); 68 | // Remove and check root at each step 69 | for (unsigned i = 0; i < data_size - removed_size; i ++) { 70 | T root = heap.pop_root(); 71 | TEST_ASSERT_TRUE(root == sorted_after_remove[i]); 72 | TEST_ASSERT_TRUE(heap.is_consistent()); 73 | } 74 | TEST_ASSERT_TRUE(heap.is_empty()); 75 | TEST_ASSERT_EQUAL(0, heap.get_num_elements()); 76 | } 77 | 78 | static void test_min_heap_pod() { 79 | int data[] = {20, 13, 8, 7, 100, -50, 0, 16, 1000, 2}; 80 | int sorted_data[] = {-50, 0, 2, 7, 8, 13, 16, 20, 100, 1000}; 81 | int to_remove[] = {-50, 100, 8, 2}; 82 | int sorted_after_remove[] = {0, 7, 13, 16, 20, 1000}; 83 | 84 | printf("********** Starting test_min_heap_pod()\r\n"); 85 | test_heap >(data, sizeof(data)/sizeof(int), sorted_data, 86 | to_remove, sizeof(to_remove)/sizeof(int), sorted_after_remove, 87 | 2000); 88 | printf("********** Ending test_min_heap_pod()\r\n"); 89 | } 90 | 91 | static void test_max_heap_pod() { 92 | unsigned data[] = {53, 0, 21, 19, 77, 123, 81, 0, 1001, 66, 17, 5}; 93 | unsigned sorted_data[] = {1001, 123, 81, 77, 66, 53, 21, 19, 17, 5, 0, 0}; 94 | unsigned to_remove[] = {0, 21, 66, 5, 81, 1001}; 95 | unsigned sorted_after_remove[] = {123, 77, 53, 19, 17, 0}; 96 | 97 | printf("********** Starting test_max_heap_pod()\r\n"); 98 | test_heap >(data, sizeof(data)/sizeof(unsigned), sorted_data, 99 | to_remove, sizeof(to_remove)/sizeof(unsigned), sorted_after_remove, 100 | 2000); 101 | printf("********** Ending test_max_heap_pod()\r\n"); 102 | } 103 | 104 | struct Test { 105 | Test(int a = 0, uint8_t c = 10): _a(a), _c(c) { 106 | inst_count ++; 107 | } 108 | 109 | Test(const Test& t): _a(t._a), _c(t._c) { 110 | inst_count ++; 111 | } 112 | 113 | ~Test() { 114 | inst_count --; 115 | } 116 | 117 | bool operator ==(const Test& t) const { 118 | return (t._a == _a) && (t._c == _c); 119 | } 120 | 121 | bool operator <=(const Test& t) const { 122 | return _a <= t._a; 123 | } 124 | 125 | bool operator >=(const Test& t) const { 126 | return _a >= t._a; 127 | } 128 | 129 | int _a; 130 | uint8_t _c; 131 | static int inst_count; 132 | }; 133 | int Test::inst_count = 0; 134 | 135 | static void test_min_heap_non_pod() { 136 | { 137 | Test data[] = {20, 13, 8, 7, 100, -50, 0, 16, 1000, 2}; 138 | Test sorted_data[] = {-50, 0, 2, 7, 8, 13, 16, 20, 100, 1000}; 139 | Test to_remove[] = {-50, 100, 8, 2}; 140 | Test sorted_after_remove[] = {0, 7, 13, 16, 20, 1000}; 141 | 142 | printf("********** Starting test_min_heap_non_pod()\r\n"); 143 | test_heap >(data, sizeof(data)/sizeof(Test), sorted_data, 144 | to_remove, sizeof(to_remove)/sizeof(Test), sorted_after_remove, 145 | 2000); 146 | } 147 | TEST_ASSERT_EQUAL(0, Test::inst_count); 148 | printf("********** Ending test_min_heap_non_pod()\r\n"); 149 | } 150 | 151 | static void test_max_heap_non_pod() { 152 | { 153 | Test data[] = {291, 62, 364, 63, 753, 325, -382, -736, -930, -927, 734, -591, 136, 753, 576, -59, -930, -700, -380, 764}; 154 | Test sorted_data[] = {764, 753, 753, 734, 576, 364, 325, 291, 136, 63, 62, -59, -380, -382, -591, -700, -736, -927, -930, -930}; 155 | Test to_remove[] = {-927, 576, 63, 753, -930, 364, 753}; // this will remove two elements with the same value 156 | Test sorted_after_remove[] = {764, 734, 325, 291, 136, 62, -59, -380, -382, -591, -700, -736, -930}; 157 | 158 | printf("********** Starting test_max_heap_non_pod()\r\n"); 159 | test_heap >(data, sizeof(data)/sizeof(Test), sorted_data, 160 | to_remove, sizeof(to_remove)/sizeof(Test), sorted_after_remove, 161 | 2000); 162 | } 163 | TEST_ASSERT_EQUAL(0, Test::inst_count); 164 | printf("********** Ending test_max_heap_non_pod()\r\n"); 165 | } 166 | 167 | static status_t test_setup(const size_t number_of_cases) { 168 | GREENTEA_SETUP(5, "default_auto"); 169 | 170 | return greentea_test_setup_handler(number_of_cases); 171 | } 172 | 173 | status_t greentea_failure_handler(const Case *const source, const failure_t reason) { 174 | greentea_case_failure_abort_handler(source, reason); 175 | return STATUS_CONTINUE; 176 | } 177 | 178 | static Case cases[] = { 179 | Case("BinaryHeap - test_min_heap_pod", test_min_heap_pod, greentea_failure_handler), 180 | Case("BinaryHeap - test_max_heap_pod", test_max_heap_pod, greentea_failure_handler), 181 | Case("BinaryHeap - test_min_heap_non_pod", test_min_heap_non_pod, greentea_failure_handler), 182 | Case("BinaryHeap - test_max_heap_non_pod", test_max_heap_non_pod, greentea_failure_handler) 183 | }; 184 | 185 | static Specification specification(test_setup, cases, greentea_test_teardown_handler); 186 | 187 | void app_start(int, char**) { 188 | Harness::run(specification); 189 | } 190 | 191 | -------------------------------------------------------------------------------- /test/EventHandler/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "greentea-client/test_env.h" 18 | #include "mbed-drivers/mbed.h" 19 | #include "unity/unity.h" 20 | #include "utest/utest.h" 21 | #include "core-util/Event.h" 22 | #include 23 | 24 | using namespace utest::v1; 25 | using namespace mbed::util; 26 | 27 | /****************************************************************************** 28 | * Generic helpers 29 | *****************************************************************************/ 30 | 31 | template 32 | static void call_fp1(const char* name, FunctionPointer1& fptr, const Arg& arg) { 33 | printf(">>>>>>>> Testing '%s' (one arg) <<<<<<<<\r\n", name); 34 | printf("[Direct call] "); 35 | fptr(arg); 36 | Event e(fptr.bind(arg)); 37 | printf("[Event call] "); 38 | e.call(); 39 | } 40 | 41 | template 42 | static void call_fp2(const char* name, FunctionPointer2& fptr, const Arg1& arg1, const Arg2& arg2) { 43 | printf(">>>>>>>> Testing '%s' (2 args)<<<<<<<<\r\n", name); 44 | printf("[Direct call] "); 45 | fptr(arg1, arg2); 46 | Event e(fptr.bind(arg1, arg2)); 47 | printf("[Event call] "); 48 | e.call(); 49 | } 50 | 51 | template 52 | static void call_fp3(const char* name, FunctionPointer3& fptr, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { 53 | printf(">>>>>>>> Testing '%s' (3 args) <<<<<<<<\r\n", name); 54 | printf("[Direct call] "); 55 | fptr(arg1, arg2, arg3); 56 | Event e(fptr.bind(arg1, arg2, arg3)); 57 | printf("[Event call] "); 58 | e.call(); 59 | } 60 | 61 | template 62 | static void call_fp0(const char* name, FunctionPointer0& fptr) { 63 | printf(">>>>>>>> Testing '%s' (no args) <<<<<<<<\r\n", name); 64 | printf("[Direct call] "); 65 | fptr(); 66 | Event e(fptr.bind()); 67 | printf("[Event call] "); 68 | e(); 69 | } 70 | 71 | static void call_event(const char* name, Event& e) { 72 | printf("[Call event '%s'] ", name); 73 | e.call(); 74 | } 75 | 76 | /****************************************************************************** 77 | * Test with functions that are not part of a class 78 | *****************************************************************************/ 79 | 80 | static void sa_func_1(const char *msg) { 81 | printf("Calling sa_func_1 with msg=%s\r\n", msg); 82 | } 83 | 84 | static void sa_func_2(int arg) { 85 | printf("Calling sa_func_2 with arg=%d\r\n", arg); 86 | } 87 | 88 | static void sa_func_3() { 89 | printf("Calling sa_func_3 (no arguments)\r\n"); 90 | } 91 | 92 | static void sa_func_4(int arg1, const char* arg2, double arg3) { 93 | printf("Calling sa_func_4 with arg1=%d, arg=%s, arg3=%f\r\n", arg1, arg2, arg3); 94 | } 95 | 96 | static void test_standalone_funcs() { 97 | printf("\r\n********** Starting test_standalone_funcs **********\r\n"); 98 | const char *testmsg1 = "Test message 1"; 99 | const char *testmsg2 = "Test message 2"; 100 | const int testint1 = 13; 101 | const double testdouble = 100.0; 102 | 103 | // First call function pointers directly 104 | FunctionPointer1 fp1(sa_func_1); 105 | FunctionPointer1 fp2(sa_func_2); 106 | FunctionPointer0 fp3(sa_func_3); 107 | FunctionPointer3 fp4(sa_func_4); 108 | call_fp1("ptr to standalone func(char*)", fp1, testmsg1); 109 | call_fp1("ptr to standalone func(char*)", fp1, testmsg2); 110 | call_fp1("ptr to standalone func(int)", fp2, testint1); 111 | call_fp0("ptr to standalone func(void)", fp3); 112 | call_fp3("ptr to standalong func(int, const char*, double)", fp4, testint1, testmsg1, testdouble); 113 | } 114 | 115 | /****************************************************************************** 116 | * Test with functions that are part of a class (trivially copyable arguments) 117 | *****************************************************************************/ 118 | 119 | class VBase { 120 | public: 121 | VBase(int arg): _arg(arg) {} 122 | void print_baseonly(const char * msg) { 123 | printf("VBase::print_baseonly: %s, _arg=%d\r\n", msg, _arg); 124 | } 125 | virtual void print_virtual_str(const char * msg) { 126 | printf("VBase::print_virtual_str: %s, _arg=%d\r\n", msg, _arg); 127 | } 128 | virtual void print_virtual_noargs() { 129 | printf("VBase::print_virtual_noargs, _arg=%d\r\n", _arg); 130 | } 131 | void print_non_virtual(const char* msg, int farg) { 132 | printf("VBase::print_non_virtual, msg=%s, farg=%d, _arg=%d\r\n", msg, farg, _arg); 133 | } 134 | protected: 135 | int _arg; 136 | }; 137 | 138 | class VDerived : public VBase { 139 | public: 140 | VDerived(int arg1, int arg2): VBase(arg1), _arg2(arg2) {} 141 | void print_non_virtual(const char* msg) { 142 | printf("VDerived::print_non_virtual, _msg=%s, _arg=%d, _arg2=%d\r\n", msg, _arg, _arg2); 143 | } 144 | virtual void print_virtual_str(const char * msg) { 145 | printf("VDerived::print_virtual_str: %s, _arg=%d, _arg2=%d\r\n", msg, _arg, _arg2); 146 | } 147 | virtual void print_virtual_noargs() { 148 | printf("VDerived::print_virtual_noargs, _arg=%d, _arg2=%d\r\n", _arg, _arg2); 149 | } 150 | private: 151 | int _arg2; 152 | }; 153 | 154 | static void test_class_funcs_tca() { 155 | printf("\r\n********** Starting test_class_funcs_tca **********\r\n"); 156 | VBase base(10); 157 | VDerived derived(20, 100); 158 | const char *testmsg1 = "Test message 1"; 159 | const char *testmsg2 = "Test message 2"; 160 | const int testint1 = 17; 161 | 162 | printf("---- Part 1: test virtual functions\r\n"); 163 | FunctionPointer1 p1_fp1(&base, &VBase::print_virtual_str); 164 | FunctionPointer1 p1_fp2(&derived, &VDerived::print_virtual_str); 165 | FunctionPointer1 p1_fp3((VBase*)&derived, &VBase::print_virtual_str); 166 | FunctionPointer0 p1_fp4((VBase*)&derived, &VBase::print_virtual_noargs); 167 | call_fp1("ptr to base::print_virtual_str", p1_fp1, testmsg1); 168 | call_fp1("ptr to derived::print_virtual_str", p1_fp2, testmsg2); 169 | call_fp1("ptr to derived::print_virtual_str via VBase* pointer", p1_fp3, testmsg2); 170 | call_fp0("ptr to derived::print_virtual_noargs via VBase* pointer", p1_fp4); 171 | printf("---- Part 2: call base-only function from base and derived\r\n"); 172 | FunctionPointer1 p2_fp1(&base, &VBase::print_baseonly); 173 | FunctionPointer1 p2_fp2((VBase*)&derived, &VBase::print_baseonly); 174 | call_fp1("ptr to base::print_baseonly", p2_fp1, testmsg1); 175 | call_fp1("ptr to base::print_baseonly using VDerived instance", p2_fp2, testmsg1); 176 | printf("---- Part 3: call non-virtual function from base and derived\r\n"); 177 | FunctionPointer2 p3_fp1(&base, &VBase::print_non_virtual); 178 | FunctionPointer1 p3_fp2(&derived, &VDerived::print_non_virtual); 179 | FunctionPointer2 p3_fp3((VBase*)&derived, &VBase::print_non_virtual); 180 | call_fp2("ptr to base::print_non_virtual", p3_fp1, testmsg1, testint1); 181 | call_fp1("ptr to derived::print_non_virtual", p3_fp2, testmsg2); 182 | call_fp2("ptr to base::print_non_virtual via Derived* pointer", p3_fp3, testmsg2, testint1); 183 | } 184 | 185 | /****************************************************************************** 186 | * Mixed test (stand alone functions and class function) using non-trivially 187 | * copyable arguments 188 | *****************************************************************************/ 189 | 190 | class MyArg { 191 | public: 192 | MyArg(const char* id = "(none)", int arg1 = 0, int arg2 = 0): _id(id), _arg1(arg1), _arg2(arg2) { 193 | instcount ++; 194 | } 195 | 196 | MyArg(const MyArg& arg): _arg1(arg._arg1), _arg2(arg._arg2) { 197 | _id = !strcmp(arg._id, "test") ? "(copy)" : arg._id; 198 | instcount ++; 199 | } 200 | 201 | ~MyArg() { 202 | instcount --; 203 | } 204 | 205 | void print() const { 206 | printf("Instance '%s'[%p] of MyArg, arg1=%d, arg2=%d\r\n", _id, this, _arg1, _arg2); 207 | } 208 | 209 | const char *_id; 210 | int _arg1, _arg2; 211 | static int instcount; 212 | }; 213 | 214 | int MyArg::instcount = 0; 215 | 216 | static void sa_ntc(MyArg arg) { 217 | printf("Called sa_ntc with arg '%s': ", arg._id); 218 | arg.print(); 219 | } 220 | 221 | class ABase { 222 | public: 223 | ABase(int arg): _arg(arg) {} 224 | virtual void print_virtual_arg(MyArg a) { 225 | printf("ABase::print_virtual_arg: %s, _arg=%d\r\n", a._id, _arg); 226 | } 227 | protected: 228 | int _arg; 229 | }; 230 | 231 | class ADerived : public ABase { 232 | public: 233 | ADerived(int arg1, int arg2): ABase(arg1), _arg2(arg2) {} 234 | virtual void print_virtual_arg(MyArg a) { 235 | printf("ADerived::print_virtual_arg: %s, _arg=%d, _arg2=%d\r\n", a._id, _arg, _arg2); 236 | } 237 | private: 238 | int _arg2; 239 | }; 240 | 241 | static void test_funcs_nontca() { 242 | { 243 | printf("\r\n********** Starting test_funcs_nontca **********\r\n"); 244 | 245 | FunctionPointer1 fp1(sa_ntc); 246 | Event e1, e2, e3; 247 | { 248 | // Test binding argument that gets out of scope at the end of this block 249 | MyArg arg("test", 10, 20); 250 | call_fp1("ptr to standalong func taking non-trivial arg", fp1, arg); 251 | e1 = e2 = e3 = fp1.bind(arg); 252 | } 253 | e1.call(); // This should work, since it has a copy of 'arg' above 254 | // Test functions taking non-trivial arguments inside classes 255 | ADerived d(10, 100); 256 | ABase *pDerived = &d; 257 | FunctionPointer1 fp2(&d, &ADerived::print_virtual_arg); 258 | FunctionPointer1 fp3(pDerived, &ABase::print_virtual_arg); 259 | call_fp1("ptr to virtual method taking non-tc argument", fp2, MyArg("notest", 5, 8)); 260 | call_fp1("ptr to virtual method taking non-tc argument (via base class pointer)", fp2, MyArg("notest", 5, 8)); 261 | } 262 | TEST_ASSERT_EQUAL(0, MyArg::instcount); 263 | } 264 | 265 | /****************************************************************************** 266 | * Create an array of events from different kinds of function pointers 267 | * Call each one in turn (unified interface) 268 | *****************************************************************************/ 269 | 270 | static void test_array_of_events() { 271 | { 272 | printf("\r\n********** Starting test_array_of_events **********\r\n"); 273 | const char* testmsg1 = "Test message 1"; 274 | const char* testmsg2 = "Test message 2"; 275 | const int testint = 13; 276 | VDerived derived(20, 100); 277 | MyArg arg("array", 5, 10); 278 | 279 | FunctionPointer1 fp1((VBase*)&derived, &VBase::print_virtual_str); 280 | FunctionPointer0 fp2(sa_func_3); 281 | FunctionPointer1 fp3(sa_func_2); 282 | FunctionPointer0 fp4(&derived, &VDerived::print_virtual_noargs); 283 | FunctionPointer1 fp5(sa_ntc); 284 | Event events[] = {fp1.bind(testmsg1), fp1.bind(testmsg2), fp2.bind(), fp3.bind(testint), 285 | fp4.bind(), fp5.bind(arg)}; 286 | 287 | for (unsigned i = 0; i < sizeof(events)/sizeof(events[0]); i ++) { 288 | events[i].call(); 289 | } 290 | } 291 | TEST_ASSERT_EQUAL(0, MyArg::instcount); 292 | } 293 | 294 | /****************************************************************************** 295 | * Test assignment between various kinds of events 296 | *****************************************************************************/ 297 | 298 | static void swap_events_using_eq(Event &e1, Event &e2) { 299 | Event temp; 300 | temp = e1; 301 | e1 = e2; 302 | e2 = temp; 303 | } 304 | 305 | static void swap_events_using_cc(Event &e1, Event &e2) { 306 | Event temp = e1; 307 | e1 = e2; 308 | e2 = temp; 309 | } 310 | 311 | static void test_event_assignment_and_swap() { 312 | { 313 | printf("\r\n********** Starting test_event_assignment_and_swap **********\r\n"); 314 | ADerived aderived(10, 10); 315 | FunctionPointer1 fp_sa_tc1(sa_func_1); 316 | FunctionPointer1 fp_sa_tc2(sa_func_2); 317 | FunctionPointer0 fp_sa_noargs(sa_func_3); 318 | FunctionPointer1 fp_sa_ntc(sa_ntc); 319 | FunctionPointer1 fp_class_ntc(&aderived, &ADerived::print_virtual_arg); 320 | MyArg arg("test_event_assignment"); 321 | Event e_sa_tc1(fp_sa_tc1.bind("test_event_assignment")); 322 | Event e_sa_tc2(fp_sa_tc2.bind(17)); 323 | Event e_sa_noargs(fp_sa_noargs.bind()); 324 | Event e_sa_ntc(fp_sa_ntc.bind(arg)); 325 | Event e_class_ntc(fp_class_ntc.bind(arg)); 326 | Event e1 = e_sa_tc1, e2 = e_class_ntc, e3; 327 | e3 = e_sa_noargs; 328 | 329 | // Swap them around like crazy. I'm going to regret this in the morning. 330 | swap_events_using_eq(e1, e_sa_noargs); // e1: fp_sa_noargs, e_sa_noargs: fp_sa_tcl 331 | swap_events_using_cc(e2, e_class_ntc); // Intentional NOOP, e2 = e_class_ntc: fp_class_ntc 332 | swap_events_using_eq(e_sa_ntc, e_sa_tc2); // e_sa_ntc: fp_sa_tc2, e_sa_tc2: fp_sa_ntc 333 | swap_events_using_cc(e3, e_sa_tc1); //e3: fp_sa_tc1, e_sa_tc1: fp_sa_noargs 334 | swap_events_using_eq(e_sa_noargs, e2); // e_sa_noargs: fp_class_ntc, e2: fp_sa_tc1 335 | swap_events_using_cc(e_sa_tc2, e_class_ntc); // e_sa_tc2: fp_class_ntc, e_class_ntc: fp_sa_ntc 336 | // Final assignments: 337 | // e_sa_tc1: fp_sa_noargs 338 | // e_sa_tc2: fp_class_ntc 339 | // e_sa_noargs: fp_class_ntc 340 | // e_sa_ntc: fp_sa_tc2 341 | // e_class_ntc: fp_sa_ntc 342 | // e1: fp_sa_noargs 343 | // e2: fp_sa_tc1 344 | // e3: fp_sa_tc1 345 | 346 | // Now call all of them and prepare for a headache 347 | call_event("e_sa_tc1", e_sa_tc1); 348 | call_event("e_sa_tc2", e_sa_tc2); 349 | call_event("e_sa_noargs", e_sa_noargs); 350 | call_event("e_sa_ntc", e_sa_ntc); 351 | call_event("e_class_ntc", e_class_ntc); 352 | call_event("e1", e1); 353 | call_event("e2", e2); 354 | call_event("e3", e3); 355 | } 356 | TEST_ASSERT_EQUAL(0, MyArg::instcount); 357 | } 358 | 359 | static status_t test_setup(const size_t number_of_cases) { 360 | GREENTEA_SETUP(10, "default_auto"); 361 | 362 | return greentea_test_setup_handler(number_of_cases); 363 | } 364 | 365 | status_t greentea_failure_handler(const Case *const source, const failure_t reason) { 366 | greentea_case_failure_abort_handler(source, reason); 367 | return STATUS_CONTINUE; 368 | } 369 | 370 | static Case cases[] = { 371 | Case("EventHandler - test_standalone_funcs", test_standalone_funcs, greentea_failure_handler), 372 | Case("EventHandler - test_class_funcs_tca", test_class_funcs_tca, greentea_failure_handler), 373 | Case("EventHandler - test_funcs_nontca", test_funcs_nontca, greentea_failure_handler), 374 | Case("EventHandler - test_array_of_events", test_array_of_events, greentea_failure_handler), 375 | Case("EventHandler - test_event_assignment_and_swap", test_event_assignment_and_swap, greentea_failure_handler) 376 | }; 377 | 378 | static Specification specification(test_setup, cases, greentea_test_teardown_handler); 379 | 380 | void app_start(int, char**) { 381 | Harness::run(specification); 382 | } 383 | -------------------------------------------------------------------------------- /test/ExtendablePoolAllocator/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core-util/ExtendablePoolAllocator.h" 19 | #include "greentea-client/test_env.h" 20 | #include "unity/unity.h" 21 | #include "utest/utest.h" 22 | #include "ualloc/ualloc.h" 23 | #include 24 | #include 25 | 26 | using namespace utest::v1; 27 | using namespace mbed::util; 28 | 29 | static bool check_value_and_alignment(void *p, unsigned alignment = MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN) { 30 | if (NULL == p) 31 | return false; 32 | return ((uint32_t)p & (alignment - 1)) == 0; 33 | } 34 | 35 | static void test_extendable_pool_allocator() { 36 | // Create the allocator 37 | const size_t initial_elements = 20, new_pool_elements = 12, element_size = 6; 38 | UAllocTraits_t traits = {0}; 39 | ExtendablePoolAllocator allocator; 40 | TEST_ASSERT_TRUE(allocator.init(initial_elements, new_pool_elements, element_size, traits)); 41 | 42 | // Fill the first pool 43 | for (unsigned i = 0; i < initial_elements; i ++) { 44 | TEST_ASSERT_TRUE(check_value_and_alignment(allocator.alloc())); 45 | } 46 | TEST_ASSERT_EQUAL(1, allocator.get_num_pools()); 47 | 48 | // Allocating just another element should add another pool 49 | void *p = allocator.alloc(); 50 | TEST_ASSERT_TRUE(check_value_and_alignment(p)); 51 | TEST_ASSERT_EQUAL(2, allocator.get_num_pools()); 52 | // Fill the new pool 53 | for (unsigned i = 0; i < new_pool_elements - 1; i ++) { 54 | TEST_ASSERT_TRUE(check_value_and_alignment(allocator.alloc())); 55 | } 56 | TEST_ASSERT_EQUAL(2, allocator.get_num_pools()); 57 | 58 | // Free one previously allocated area 59 | allocator.free(p); 60 | // And allocate again. Since there's a single free place, it should be used now 61 | void *newp = allocator.alloc(); 62 | TEST_ASSERT_TRUE(check_value_and_alignment(newp)); 63 | TEST_ASSERT_EQUAL(p, newp); 64 | TEST_ASSERT_EQUAL(2, allocator.get_num_pools()); 65 | } 66 | 67 | static status_t test_setup(const size_t number_of_cases) { 68 | GREENTEA_SETUP(5, "default_auto"); 69 | 70 | return greentea_test_setup_handler(number_of_cases); 71 | } 72 | 73 | static Case cases[] = { 74 | Case("ExtendablePoolAllocator - test_extendable_pool_allocator", test_extendable_pool_allocator) 75 | }; 76 | 77 | static Specification specification(test_setup, cases, greentea_test_teardown_handler); 78 | 79 | void app_start(int, char**) { 80 | Harness::run(specification); 81 | } 82 | -------------------------------------------------------------------------------- /test/FunctionPointer/int_types.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "core-util/FunctionPointer.h" 19 | #include "int_types.hpp" 20 | 21 | bool called; 22 | 23 | static void vsi(int i) 24 | { 25 | called=true; 26 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, i); 27 | } 28 | static void vspi(int *pi) 29 | { 30 | called=true; 31 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, *pi); 32 | } 33 | static void vsri(int& ri) 34 | { 35 | called=true; 36 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, ri); 37 | } 38 | static void vsci(const int i) 39 | { 40 | called=true; 41 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, i); 42 | } 43 | static void vscpi(const int *pi) 44 | { 45 | called=true; 46 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, *pi); 47 | } 48 | static void vscri(const int& ri) 49 | { 50 | called=true; 51 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, ri); 52 | } 53 | 54 | bool testInts(){ 55 | bool passed = true; 56 | { 57 | mbed::util::FunctionPointer1 fp_vsi(vsi); 58 | called = false; 59 | fp_vsi(1); 60 | passed = called && passed; 61 | } 62 | { 63 | mbed::util::FunctionPointer1 fp_vspi(vspi); 64 | called = false; 65 | int i = 2; 66 | fp_vspi(&i); 67 | passed = called && passed; 68 | } 69 | { 70 | mbed::util::FunctionPointer1 fp_vsri(vsri); 71 | called = false; 72 | int i = 3; 73 | fp_vsri(i); 74 | passed = called && passed; 75 | } 76 | { 77 | mbed::util::FunctionPointer1 fp_vsci(vsci); 78 | called = false; 79 | fp_vsci(4); 80 | passed = called && passed; 81 | } 82 | { 83 | mbed::util::FunctionPointer1 fp_vscpi(vscpi); 84 | called = false; 85 | int i = 5; 86 | fp_vscpi(&i); 87 | passed = called && passed; 88 | } 89 | { 90 | mbed::util::FunctionPointer1 fp_vscri(vscri); 91 | called = false; 92 | int i = 6; 93 | fp_vscri(i); 94 | passed = called && passed; 95 | } 96 | return passed; 97 | } 98 | -------------------------------------------------------------------------------- /test/FunctionPointer/int_types.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __CORE_UTIL_TEST_FUNCTIONPOINTER_INT_TYPES_H__ 18 | #define __CORE_UTIL_TEST_FUNCTIONPOINTER_INT_TYPES_H__ 19 | 20 | bool testInts(); 21 | 22 | #endif // __CORE_UTIL_TEST_FUNCTIONPOINTER_INT_TYPES_H__ 23 | -------------------------------------------------------------------------------- /test/FunctionPointer/lifetime.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include "lifetime.hpp" 18 | #include "core-util/FunctionPointer.h" 19 | 20 | class LifetimeChecker { 21 | public: 22 | LifetimeChecker(int arg) : _arg(arg) { 23 | _activeInstances++; 24 | } 25 | LifetimeChecker(const LifetimeChecker & lc) : _arg(lc._arg) { 26 | _cc = true; 27 | _activeInstances++; 28 | } 29 | ~LifetimeChecker() { 30 | _activeInstances--; 31 | } 32 | 33 | LifetimeChecker& operator = (const LifetimeChecker & rhs) { 34 | _cc = true; 35 | _arg = rhs._arg; 36 | return *this; 37 | } 38 | 39 | static int getInstances() { 40 | return _activeInstances; 41 | } 42 | int getArg() { 43 | return _arg; 44 | } 45 | static void reset() { 46 | _wasCalled = false; 47 | _ok = false; 48 | _cc = false; 49 | } 50 | static bool wasCalled() { 51 | return _wasCalled; 52 | } 53 | static bool isOk() { 54 | return _ok; 55 | } 56 | static bool ccCalled() { 57 | return _cc; 58 | } 59 | void set(bool ok) { 60 | _wasCalled = true; 61 | _ok = ok; 62 | } 63 | protected: 64 | int _arg; 65 | static bool _wasCalled; 66 | static bool _ok; 67 | static bool _cc; 68 | static int _activeInstances; 69 | }; 70 | 71 | int LifetimeChecker::_activeInstances = 0; 72 | bool LifetimeChecker::_wasCalled; 73 | bool LifetimeChecker::_ok; 74 | bool LifetimeChecker::_cc; 75 | 76 | int lifeCheck(LifetimeChecker lc) { 77 | int arg = lc.getArg(); 78 | int instances = lc.getInstances(); 79 | lc.set(instances == 4); 80 | if (instances != 4) { 81 | printf("Expected 4 instances, got %i\r\n",instances); 82 | } 83 | return arg-1; 84 | } 85 | int lifeCheckR(LifetimeChecker &lc) { 86 | int arg = lc.getArg(); 87 | int instances = lc.getInstances(); 88 | lc.set(instances == 1); 89 | if (instances != 1) { 90 | printf("Expected 1 instances, got %i\r\n",instances); 91 | } 92 | return arg-2; 93 | } 94 | int lifeCheckP(LifetimeChecker *lc) { 95 | int arg = lc->getArg(); 96 | int instances = lc->getInstances(); 97 | lc->set(instances == 1); 98 | if (instances != 1) { 99 | printf("Expected 1 instances, got %i\r\n",instances); 100 | } 101 | return arg-3; 102 | } 103 | 104 | 105 | bool checkLifetime() { 106 | bool passed = true; 107 | int rc; 108 | { 109 | LifetimeChecker::reset(); 110 | LifetimeChecker lc(1); 111 | mbed::util::FunctionPointer1 fp(lifeCheck); 112 | if ((rc = fp(lc)) != 0) { 113 | printf("call error: expected 0, got %i\n", rc); 114 | passed = false; 115 | } 116 | printf("LifetimeChecker : OK = %s, Was Called = %s, Copy Constructed = %s, Instances remaining: %d\r\n", 117 | (lc.isOk()?"true":"false"), (lc.wasCalled()?"true":"false"), (lc.ccCalled()?"true":"false"), lc.getInstances()); 118 | passed = passed && lc.isOk() && lc.wasCalled() && lc.ccCalled() && (lc.getInstances() == 1); 119 | } 120 | { 121 | LifetimeChecker::reset(); 122 | LifetimeChecker lc(2); 123 | mbed::util::FunctionPointer1 fp(lifeCheckR); 124 | if ((rc = fp(lc)) != 0) { 125 | printf("call error: expected 0, got %i\n", rc); 126 | passed = false; 127 | } 128 | printf("LifetimeChecker (R): OK = %s, Was Called = %s, Copy Constructed = %s, Instances remaining: %d\r\n", 129 | (lc.isOk()?"true":"false"), (lc.wasCalled()?"true":"false"), (lc.ccCalled()?"true":"false"), lc.getInstances()); 130 | passed = passed && lc.isOk() && lc.wasCalled() && !lc.ccCalled() && (lc.getInstances() == 1); 131 | } 132 | { 133 | LifetimeChecker::reset(); 134 | LifetimeChecker lc(3); 135 | mbed::util::FunctionPointer1 fp(lifeCheckP); 136 | if ((rc = fp(&lc)) != 0) { 137 | printf("call error: expected 0, got %i\n", rc); 138 | passed = false; 139 | } 140 | printf("LifetimeChecker (P): OK = %s, Was Called = %s, Copy Constructed = %s, Instances remaining: %d\r\n", 141 | (lc.isOk()?"true":"false"), (lc.wasCalled()?"true":"false"), (lc.ccCalled()?"true":"false"), lc.getInstances()); 142 | passed = passed && lc.isOk() && lc.wasCalled() && !lc.ccCalled() && (lc.getInstances() == 1); 143 | } 144 | return passed; 145 | } 146 | -------------------------------------------------------------------------------- /test/FunctionPointer/lifetime.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __CORE_UTIL_TEST_FUNCTIONPOINTER_LIFETIME_H__ 18 | #define __CORE_UTIL_TEST_FUNCTIONPOINTER_LIFETIME_H__ 19 | 20 | bool checkLifetime(); 21 | 22 | #endif // __CORE_UTIL_TEST_FUNCTIONPOINTER_LIFETIME_H__ 23 | -------------------------------------------------------------------------------- /test/FunctionPointer/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "greentea-client/test_env.h" 18 | #include "unity/unity.h" 19 | #include "utest/utest.h" 20 | #include "core-util/FunctionPointer.h" 21 | #include "int_types.hpp" 22 | #include "lifetime.hpp" 23 | #include "side_effects.hpp" 24 | 25 | using namespace utest::v1; 26 | 27 | namespace { 28 | volatile int ebp_flag = 0; 29 | volatile int ecp_flag = 0; 30 | } 31 | 32 | class VTest { 33 | public: 34 | void print() { 35 | ecp_flag = 1; 36 | printf("Class Print\r\n"); 37 | } 38 | 39 | }; 40 | 41 | void bareprint() { 42 | ebp_flag = 1; 43 | printf("Bare Print\r\n"); 44 | } 45 | 46 | void test_function_pointer(void) { 47 | VTest test; 48 | printf("Testing mbed FunctionPointer...\r\n"); 49 | 50 | mbed::util::FunctionPointer ebp(bareprint); 51 | mbed::util::FunctionPointer ecp(&test, &VTest::print); 52 | 53 | size_t ebsize = sizeof(ebp); 54 | size_t ecsize = sizeof(ecp); 55 | printf("sizeof(bp) = %d\r\n", ebsize); 56 | printf("sizeof(cp) = %d\r\n", ecsize); 57 | 58 | bool result = true; 59 | // Test checks 60 | { 61 | ebp.call(); 62 | result = result && ebp_flag; 63 | printf("ebp_flag = %d\r\n", ebp_flag); 64 | 65 | ecp.call(); 66 | result = result && ecp_flag; 67 | printf("ecp_flag = %d\r\n", ecp_flag); 68 | } 69 | 70 | bool iResult = testInts(); 71 | TEST_ASSERT_TRUE_MESSAGE(iResult, "testInts() failed"); 72 | result = result && iResult; 73 | 74 | bool lifeResult = checkLifetime(); 75 | TEST_ASSERT_TRUE_MESSAGE(lifeResult, "checkLifetime() failed"); 76 | result = result && lifeResult; 77 | 78 | bool sideEffectResult = checkSideEffects(); 79 | TEST_ASSERT_TRUE_MESSAGE(sideEffectResult, "checkSideEffects() failed"); 80 | result = result && lifeResult; 81 | 82 | printf("Test Complete\r\n"); 83 | TEST_ASSERT_TRUE(result); 84 | } 85 | 86 | static status_t test_setup(const size_t number_of_cases) { 87 | GREENTEA_SETUP(10, "default_auto"); 88 | 89 | return greentea_test_setup_handler(number_of_cases); 90 | } 91 | 92 | static Case cases[] = { 93 | Case("FunctionPointer - test_function_pointer", test_function_pointer) 94 | }; 95 | 96 | static Specification specification(test_setup, cases, greentea_test_teardown_handler); 97 | 98 | void app_start(int, char**) { 99 | Harness::run(specification); 100 | } 101 | -------------------------------------------------------------------------------- /test/FunctionPointer/side_effects.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include "core-util/FunctionPointer.h" 18 | #include "side_effects.hpp" 19 | 20 | static bool called = false; 21 | 22 | static void vspi(int *pi) 23 | { 24 | called=true; 25 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, *pi); 26 | *pi += 1; 27 | } 28 | static void vsri(int& ri) 29 | { 30 | called=true; 31 | printf("%s called with %i\r\n", __PRETTY_FUNCTION__, ri); 32 | ri += 2; 33 | } 34 | 35 | 36 | bool checkSideEffects() 37 | { 38 | bool passed = true; 39 | { 40 | mbed::util::FunctionPointer1 fp_vspi(vspi); 41 | called = false; 42 | int i = 2; 43 | fp_vspi(&i); 44 | passed = called && passed && (i == 3); 45 | } 46 | { 47 | mbed::util::FunctionPointer1 fp_vsri(vsri); 48 | called = false; 49 | int i = 3; 50 | fp_vsri(i); 51 | passed = called && passed && (i == 5); 52 | } 53 | return passed; 54 | } 55 | -------------------------------------------------------------------------------- /test/FunctionPointer/side_effects.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __CORE_UTIL_TEST_FUNCTIONPOINTER_SIDE_EFFECTS_H__ 18 | #define __CORE_UTIL_TEST_FUNCTIONPOINTER_SIDE_EFFECTS_H__ 19 | 20 | bool checkSideEffects(); 21 | 22 | #endif // __CORE_UTIL_TEST_FUNCTIONPOINTER_SIDE_EFFECTS_H__ 23 | -------------------------------------------------------------------------------- /test/PoolAllocator/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core-util/PoolAllocator.h" 19 | #include "greentea-client/test_env.h" 20 | #include "unity/unity.h" 21 | #include "utest/utest.h" 22 | #include 23 | #include 24 | 25 | using namespace utest::v1; 26 | using namespace mbed::util; 27 | 28 | void test_pool_allocator() { 29 | // Allocate initial space for the pool 30 | const size_t elements = 10, element_size = 6; 31 | const size_t aligned_size = (element_size + MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN - 1) & ~(MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN - 1); 32 | size_t pool_size = PoolAllocator::get_pool_size(elements, element_size); 33 | TEST_ASSERT_EQUAL(elements * aligned_size, pool_size); 34 | 35 | void *start = malloc(pool_size); 36 | TEST_ASSERT_TRUE(start != NULL); 37 | PoolAllocator allocator(start, elements, element_size); 38 | 39 | // Allocate all elements, checking for proper alignment and spacing 40 | void *p, *prev, *first; 41 | for (size_t i = 0; i < elements; i ++) { 42 | p = allocator.alloc(); 43 | TEST_ASSERT_TRUE(p != NULL); 44 | // Check alignment 45 | TEST_ASSERT_EQUAL(0, ((uint32_t)p & (MBED_UTIL_POOL_ALLOC_DEFAULT_ALIGN - 1))); 46 | // Check spacing 47 | if (i > 0) { 48 | TEST_ASSERT_EQUAL(aligned_size, ((uint32_t)p - (uint32_t)prev)); 49 | } else { 50 | first = p; 51 | TEST_ASSERT_EQUAL(start, p); 52 | } 53 | prev = p; 54 | } 55 | 56 | // No more space in the pool, we should get NULL now 57 | TEST_ASSERT_EQUAL(NULL, allocator.alloc()); 58 | 59 | // Free the first element we allocated 60 | allocator.free(first); 61 | 62 | // Verify that we can allocate a single element now, and it has the same address 63 | // as the first element we allocated above 64 | p = allocator.alloc(); 65 | TEST_ASSERT_EQUAL(first, p); 66 | p = allocator.alloc(); 67 | TEST_ASSERT_EQUAL(NULL, p); 68 | } 69 | 70 | static status_t test_setup(const size_t number_of_cases) { 71 | GREENTEA_SETUP(5, "default_auto"); 72 | 73 | return greentea_test_setup_handler(number_of_cases); 74 | } 75 | 76 | static Case cases[] = { 77 | Case("PoolAllocator - test_pool_allocator", test_pool_allocator) 78 | }; 79 | 80 | static Specification specification(test_setup, cases, greentea_test_teardown_handler); 81 | 82 | void app_start(int, char**) { 83 | Harness::run(specification); 84 | } 85 | -------------------------------------------------------------------------------- /test/SharedPointer/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include "greentea-client/test_env.h" 21 | #include "unity/unity.h" 22 | #include "utest/utest.h" 23 | #include "core-util/SharedPointer.h" 24 | 25 | using namespace utest::v1; 26 | using namespace mbed::util; 27 | 28 | static bool globalFlag = false; 29 | 30 | class Number { 31 | public: 32 | Number(int _num): num(_num) { 33 | printf("Number: %d constructed\r\n", num); 34 | } 35 | 36 | ~Number() { 37 | printf("Number: %d destroyed\r\n", num); 38 | globalFlag = false; 39 | } 40 | 41 | int getNum() { 42 | return num; 43 | } 44 | private: 45 | int num; 46 | }; 47 | 48 | 49 | void test_shared_pointer() { 50 | /* Test 1: create SharedPointer from pointer */ 51 | Number* ptr1 = new Number(1); 52 | SharedPointer sharedptr1(ptr1); 53 | 54 | // pointers match 55 | TEST_ASSERT_EQUAL(ptr1, sharedptr1.get()); 56 | 57 | // counter match 58 | TEST_ASSERT_EQUAL(1, sharedptr1.use_count()); 59 | 60 | // dereferencing works 61 | TEST_ASSERT_EQUAL(1, sharedptr1->getNum()); 62 | 63 | /* Test 2: copy pointer */ 64 | { 65 | SharedPointer sharedptr1copy; 66 | 67 | // NULL pointer is NULL 68 | TEST_ASSERT_EQUAL(NULL, sharedptr1copy.get()); 69 | TEST_ASSERT_EQUAL(0, sharedptr1copy.use_count()); 70 | 71 | // copy 72 | sharedptr1copy = sharedptr1; 73 | 74 | // raw pointer is consistent 75 | TEST_ASSERT_EQUAL(ptr1, sharedptr1copy.get()); 76 | TEST_ASSERT_EQUAL(sharedptr1.get(), sharedptr1copy.get()); 77 | 78 | // reference count is accurate 79 | TEST_ASSERT_EQUAL(2, sharedptr1.use_count()); 80 | TEST_ASSERT_EQUAL(2, sharedptr1copy.use_count()); 81 | } 82 | 83 | // sharedptr1copy is destroyed, count is decremented 84 | TEST_ASSERT_EQUAL(1, sharedptr1.use_count()); 85 | 86 | 87 | /* Test 3: object is destroyed */ 88 | { 89 | SharedPointer sharedptr2(new Number(2)); 90 | 91 | // Set global variable. This variable is set to false when any Number is destroyed. 92 | globalFlag = true; 93 | } 94 | 95 | TEST_ASSERT_EQUAL(false, globalFlag); 96 | 97 | /* Test 4: corner cases */ 98 | 99 | // self assignment 100 | TEST_ASSERT_EQUAL(1, sharedptr1.use_count()); 101 | sharedptr1 = sharedptr1; 102 | TEST_ASSERT_EQUAL(1, sharedptr1.use_count()); 103 | 104 | 105 | /* Test 5: basic types */ 106 | { 107 | SharedPointer sharedptr3(new int); 108 | *sharedptr3 = 3; 109 | TEST_ASSERT_EQUAL(3, *sharedptr3); 110 | } 111 | } 112 | 113 | static status_t test_setup(const size_t number_of_cases) { 114 | GREENTEA_SETUP(2, "default_auto"); 115 | 116 | return greentea_test_setup_handler(number_of_cases); 117 | } 118 | 119 | static Case cases[] = { 120 | Case("SharedPointer - test_shared_pointer", test_shared_pointer) 121 | }; 122 | 123 | static Specification specification(test_setup, cases, greentea_test_teardown_handler); 124 | 125 | void app_start(int, char**) { 126 | Harness::run(specification); 127 | } 128 | -------------------------------------------------------------------------------- /test/sbrk-mini/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2015 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include "greentea-client/test_env.h" 21 | #include "core-util/sbrk.h" 22 | 23 | extern void * volatile mbed_sbrk_ptr; 24 | extern volatile uintptr_t mbed_sbrk_diff; 25 | 26 | #define TEST_SMALL sizeof(uint32_t) 27 | #define CHECK_EQ(A,B,P,F,L)\ 28 | ((A) == (B) ? 1 : ((P) = false, (F) = __FILE__, (L) = __LINE__, 0)) 29 | #define CHECK_NEQ(A,B,P,F,L)\ 30 | ((A) != (B) ? 1 : ((P) = false, (F) = __FILE__, (L) = __LINE__, 0)) 31 | 32 | bool runTest(int * line, const char ** file) { 33 | bool tests_pass = true; 34 | 35 | do { 36 | uintptr_t init_sbrk_ptr = (uintptr_t)mbed_sbrk(0); 37 | uintptr_t ptr; 38 | ptr = (uintptr_t) mbed_sbrk(TEST_SMALL); 39 | if(!CHECK_EQ(ptr, (uintptr_t) init_sbrk_ptr, tests_pass, *file, *line)) { 40 | break; 41 | } 42 | 43 | ptr = (uintptr_t) mbed_sbrk(TEST_SMALL); 44 | if(!CHECK_EQ(ptr, init_sbrk_ptr + SBRK_ALIGN, tests_pass, *file, *line)) { 45 | break; 46 | } 47 | 48 | ptr = (uintptr_t) mbed_krbs(TEST_SMALL); 49 | if(!CHECK_EQ(ptr, (uintptr_t) &__mbed_krbs_start - KRBS_ALIGN, tests_pass, *file, *line)) { 50 | break; 51 | } 52 | if(!CHECK_EQ(mbed_sbrk_diff, (ptrdiff_t)&__heap_size - 3*SBRK_ALIGN - (init_sbrk_ptr - (uintptr_t)&__mbed_sbrk_start), tests_pass, *file, *line)) { 53 | break; 54 | } 55 | 56 | 57 | // Test small increments 58 | for (unsigned int i = 0; tests_pass && i < TEST_SMALL; i++) { 59 | ptr = (uintptr_t) mbed_krbs(i); 60 | if(!CHECK_EQ(0, ptr & (KRBS_ALIGN - 1), tests_pass, *file, *line)) { 61 | break; 62 | } 63 | } 64 | for (unsigned int i = 0; tests_pass && i < TEST_SMALL; i++) { 65 | ptr = (uintptr_t) mbed_sbrk(i); 66 | if(!CHECK_EQ(0, (uintptr_t) mbed_sbrk_ptr & (SBRK_ALIGN - 1), tests_pass, *file, *line)) { 67 | break; 68 | } 69 | } 70 | 71 | // Allocate a big block 72 | ptr = (uintptr_t) mbed_sbrk((ptrdiff_t)&__heap_size); 73 | if(!CHECK_EQ((intptr_t)ptr, -1, tests_pass, *file, *line)) { 74 | break; 75 | } 76 | 77 | ptr = (uintptr_t) mbed_krbs((ptrdiff_t)&__heap_size); 78 | if(!CHECK_EQ((intptr_t)ptr, -1, tests_pass, *file, *line)) { 79 | break; 80 | } 81 | 82 | break; 83 | 84 | } while (0); 85 | return tests_pass; 86 | } 87 | 88 | class Test { 89 | public: 90 | Test():_pass(false), _line(0), _file(NULL) 91 | { 92 | _pass = runTest(&_line, &_file); 93 | } 94 | bool passed() {return _pass;} 95 | int line() {return _line;} 96 | const char * file() {return _file;} 97 | private: 98 | bool _pass; 99 | int _line; 100 | const char *_file; 101 | }; 102 | 103 | Test early_test; 104 | 105 | void app_start(int, char*[]) 106 | { 107 | GREENTEA_SETUP(10, "default_auto"); 108 | 109 | if (!early_test.passed()) { 110 | printf("MBED: Failed at %s:%d\r\n", early_test.file(), early_test.line()); 111 | } 112 | 113 | GREENTEA_TESTSUITE_RESULT(early_test.passed()); 114 | return; 115 | } 116 | -------------------------------------------------------------------------------- /test/uninitialized/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PackageLicenseDeclared: Apache-2.0 3 | * Copyright (c) 2016 ARM Limited 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include 18 | #include "cmsis-core/core_generic.h" 19 | #include "greentea-client/test_env.h" 20 | #include "mbed-drivers/mbed.h" 21 | #include "core-util/uninitialized.h" 22 | 23 | #define TEST_C_INIT 0xDEADBEEFUL 24 | #define TEST_MANUAL_INIT 0xACCE55EDUL 25 | 26 | __uninitialized uint32_t g_state = TEST_C_INIT; 27 | 28 | void app_start(int, char*[]) 29 | { 30 | if (g_state == TEST_C_INIT) { 31 | /* First run: Check that the g_state does *not* hold the initialized 32 | * data. */ 33 | GREENTEA_SETUP(5, "default_auto"); 34 | GREENTEA_TESTSUITE_RESULT(false); 35 | } else if (g_state != TEST_MANUAL_INIT) { 36 | /* First or subsequent runs: If this is the first run, initialize the 37 | * state and reset. If this code is run again after the first run it 38 | * means the state is not kept across reboots. Eventually, the test will 39 | * timeout, failing. */ 40 | g_state = TEST_MANUAL_INIT; 41 | NVIC_SystemReset(); 42 | } else { 43 | /* Second run: The data was correctly initialized and kept across a 44 | * system reset. */ 45 | GREENTEA_SETUP(5, "default_auto"); 46 | g_state = 0; 47 | GREENTEA_TESTSUITE_RESULT(true); 48 | } 49 | 50 | return; 51 | } 52 | --------------------------------------------------------------------------------