mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 31 06:02:27 2019 +0000
Revision:
1:9db0e321a9f4
updated based on mbed-os5.15.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 1:9db0e321a9f4 1 /* mbed Microcontroller Library
kenjiArai 1:9db0e321a9f4 2 * Copyright (c) 2019 ARM Limited
kenjiArai 1:9db0e321a9f4 3 * SPDX-License-Identifier: Apache-2.0
kenjiArai 1:9db0e321a9f4 4 *
kenjiArai 1:9db0e321a9f4 5 * Licensed under the Apache License, Version 2.0 (the "License");
kenjiArai 1:9db0e321a9f4 6 * you may not use this file except in compliance with the License.
kenjiArai 1:9db0e321a9f4 7 * You may obtain a copy of the License at
kenjiArai 1:9db0e321a9f4 8 *
kenjiArai 1:9db0e321a9f4 9 * http://www.apache.org/licenses/LICENSE-2.0
kenjiArai 1:9db0e321a9f4 10 *
kenjiArai 1:9db0e321a9f4 11 * Unless required by applicable law or agreed to in writing, software
kenjiArai 1:9db0e321a9f4 12 * distributed under the License is distributed on an "AS IS" BASIS,
kenjiArai 1:9db0e321a9f4 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kenjiArai 1:9db0e321a9f4 14 * See the License for the specific language governing permissions and
kenjiArai 1:9db0e321a9f4 15 * limitations under the License.
kenjiArai 1:9db0e321a9f4 16 */
kenjiArai 1:9db0e321a9f4 17 #ifndef MSTD_MUTEX_
kenjiArai 1:9db0e321a9f4 18 #define MSTD_MUTEX_
kenjiArai 1:9db0e321a9f4 19
kenjiArai 1:9db0e321a9f4 20 /* <mstd_mutex>
kenjiArai 1:9db0e321a9f4 21 *
kenjiArai 1:9db0e321a9f4 22 * - includes toolchain's <mutex> (if any)
kenjiArai 1:9db0e321a9f4 23 * - For toolchains not providing them, local implementation of C++11/14 equivalent features:
kenjiArai 1:9db0e321a9f4 24 * - mstd::defer_lock etc
kenjiArai 1:9db0e321a9f4 25 * - mstd::lock_guard
kenjiArai 1:9db0e321a9f4 26 * - mstd::unique_lock
kenjiArai 1:9db0e321a9f4 27 * - mstd::lock
kenjiArai 1:9db0e321a9f4 28 * - mstd::try_lock
kenjiArai 1:9db0e321a9f4 29 * - If not available, local version of:
kenjiArai 1:9db0e321a9f4 30 * - mstd::scoped_lock (C++17)
kenjiArai 1:9db0e321a9f4 31 * - For all toolchains, local implementations:
kenjiArai 1:9db0e321a9f4 32 * - mstd::call_once, mstd::once_flag
kenjiArai 1:9db0e321a9f4 33 * - mstd::mutex, mstd::recursive_mutex
kenjiArai 1:9db0e321a9f4 34 *
kenjiArai 1:9db0e321a9f4 35 * Toolchains will vary greatly in how much is in namespace std, depending on retargetting.
kenjiArai 1:9db0e321a9f4 36 */
kenjiArai 1:9db0e321a9f4 37
kenjiArai 1:9db0e321a9f4 38 #if !defined __CC_ARM && !defined __IAR_SYSTEMS_ICC__
kenjiArai 1:9db0e321a9f4 39 #include <mutex>
kenjiArai 1:9db0e321a9f4 40 #endif
kenjiArai 1:9db0e321a9f4 41
kenjiArai 1:9db0e321a9f4 42 #if MBED_CONF_RTOS_PRESENT
kenjiArai 1:9db0e321a9f4 43 #include "platform/SingletonPtr.h"
kenjiArai 1:9db0e321a9f4 44 #include "rtos/Mutex.h"
kenjiArai 1:9db0e321a9f4 45 #endif
kenjiArai 1:9db0e321a9f4 46
kenjiArai 1:9db0e321a9f4 47 #include <mstd_utility>
kenjiArai 1:9db0e321a9f4 48 #include <mstd_functional>
kenjiArai 1:9db0e321a9f4 49
kenjiArai 1:9db0e321a9f4 50 #include "mbed_atomic.h"
kenjiArai 1:9db0e321a9f4 51 #include "mbed_assert.h"
kenjiArai 1:9db0e321a9f4 52
kenjiArai 1:9db0e321a9f4 53 extern "C" int __cxa_guard_acquire(int *guard_object_p);
kenjiArai 1:9db0e321a9f4 54 extern "C" void __cxa_guard_release(int *guard_object_p);
kenjiArai 1:9db0e321a9f4 55
kenjiArai 1:9db0e321a9f4 56 // IAR does not provide <mutex> at all - it errors on inclusion
kenjiArai 1:9db0e321a9f4 57 // ARMC6 provides it, but it is empty unless _ARM_LIBCPP_EXTERNAL_THREADS is defined
kenjiArai 1:9db0e321a9f4 58 // GCC has it, and only the actual `mutex` types are conditional on _GLIBCXX_HAS_GTHREADS
kenjiArai 1:9db0e321a9f4 59 // So pick up std stuff, unless ARMC5, ICC, or ARMC6-without-threads
kenjiArai 1:9db0e321a9f4 60 namespace mstd {
kenjiArai 1:9db0e321a9f4 61 #if !defined __CC_ARM && !defined __IAR_SYSTEMS_ICC__ && !defined _LIBCPP_HAS_NO_THREADS
kenjiArai 1:9db0e321a9f4 62 using std::defer_lock;
kenjiArai 1:9db0e321a9f4 63 using std::defer_lock_t;
kenjiArai 1:9db0e321a9f4 64 using std::try_to_lock;
kenjiArai 1:9db0e321a9f4 65 using std::try_to_lock_t;
kenjiArai 1:9db0e321a9f4 66 using std::adopt_lock;
kenjiArai 1:9db0e321a9f4 67 using std::adopt_lock_t;
kenjiArai 1:9db0e321a9f4 68
kenjiArai 1:9db0e321a9f4 69 using std::lock_guard;
kenjiArai 1:9db0e321a9f4 70 using std::unique_lock;
kenjiArai 1:9db0e321a9f4 71 using std::try_lock;
kenjiArai 1:9db0e321a9f4 72 using std::lock;
kenjiArai 1:9db0e321a9f4 73 #else
kenjiArai 1:9db0e321a9f4 74 // [thread.lock]
kenjiArai 1:9db0e321a9f4 75 struct defer_lock_t { };
kenjiArai 1:9db0e321a9f4 76 struct try_to_lock_t { };
kenjiArai 1:9db0e321a9f4 77 struct adopt_lock_t { };
kenjiArai 1:9db0e321a9f4 78 constexpr defer_lock_t defer_lock;
kenjiArai 1:9db0e321a9f4 79 constexpr try_to_lock_t try_to_lock;
kenjiArai 1:9db0e321a9f4 80 constexpr adopt_lock_t adopt_lock;
kenjiArai 1:9db0e321a9f4 81
kenjiArai 1:9db0e321a9f4 82 // [thread.lock.guard]
kenjiArai 1:9db0e321a9f4 83 template <class Mutex>
kenjiArai 1:9db0e321a9f4 84 class lock_guard {
kenjiArai 1:9db0e321a9f4 85 Mutex &pm;
kenjiArai 1:9db0e321a9f4 86 public:
kenjiArai 1:9db0e321a9f4 87 using mutex_type = Mutex;
kenjiArai 1:9db0e321a9f4 88 explicit lock_guard(Mutex &m) : pm(m) { m.lock(); }
kenjiArai 1:9db0e321a9f4 89 lock_guard(Mutex &m, adopt_lock_t) noexcept : pm(m) { }
kenjiArai 1:9db0e321a9f4 90 ~lock_guard() { pm.unlock(); }
kenjiArai 1:9db0e321a9f4 91
kenjiArai 1:9db0e321a9f4 92 lock_guard(const lock_guard &) = delete;
kenjiArai 1:9db0e321a9f4 93 lock_guard &operator=(const lock_guard &) = delete;
kenjiArai 1:9db0e321a9f4 94 };
kenjiArai 1:9db0e321a9f4 95
kenjiArai 1:9db0e321a9f4 96
kenjiArai 1:9db0e321a9f4 97 // [thread.lock.unique]
kenjiArai 1:9db0e321a9f4 98 template<class Mutex>
kenjiArai 1:9db0e321a9f4 99 class unique_lock {
kenjiArai 1:9db0e321a9f4 100 public:
kenjiArai 1:9db0e321a9f4 101 using mutex_type = Mutex;
kenjiArai 1:9db0e321a9f4 102
kenjiArai 1:9db0e321a9f4 103 unique_lock() noexcept : pm(nullptr), owns(false) { }
kenjiArai 1:9db0e321a9f4 104 explicit unique_lock(mutex_type &m) : pm(&m), owns(true) { m.lock(); }
kenjiArai 1:9db0e321a9f4 105 unique_lock(mutex_type &m, defer_lock_t) noexcept : pm(&m), owns(false) { }
kenjiArai 1:9db0e321a9f4 106 unique_lock(mutex_type &m, try_to_lock_t) : pm(&m), owns(m.try_lock()) { }
kenjiArai 1:9db0e321a9f4 107 unique_lock(mutex_type &m, adopt_lock_t) : pm(&m), owns(true) { }
kenjiArai 1:9db0e321a9f4 108 #if 0 // disabled until we have functional mstd::chrono for all toolchains
kenjiArai 1:9db0e321a9f4 109 template <class Clock, class Duration>
kenjiArai 1:9db0e321a9f4 110 unique_lock(mutex_type &m, const chrono::time_point<Clock, Duration> &abs_time) : pm(&m), owns(m.try_lock_until(abs_time)) { }
kenjiArai 1:9db0e321a9f4 111 template <class Rep, class Period>
kenjiArai 1:9db0e321a9f4 112 unique_lock(mutex_type &m, const chrono::duration<Rep, Period> &rel_time) : pm(&m), owns(m.try_lock_for(rel_time)) { }
kenjiArai 1:9db0e321a9f4 113 #endif
kenjiArai 1:9db0e321a9f4 114 ~unique_lock() { if (owns) pm->unlock(); }
kenjiArai 1:9db0e321a9f4 115
kenjiArai 1:9db0e321a9f4 116 unique_lock(const unique_lock &) = delete;
kenjiArai 1:9db0e321a9f4 117 unique_lock &operator=(const unique_lock &) = delete;
kenjiArai 1:9db0e321a9f4 118
kenjiArai 1:9db0e321a9f4 119 unique_lock(unique_lock &&u) noexcept : pm(u.pm), owns(u.owns) {
kenjiArai 1:9db0e321a9f4 120 u.pm = nullptr;
kenjiArai 1:9db0e321a9f4 121 u.owns = false;
kenjiArai 1:9db0e321a9f4 122 }
kenjiArai 1:9db0e321a9f4 123
kenjiArai 1:9db0e321a9f4 124 unique_lock &operator=(unique_lock &&u) noexcept {
kenjiArai 1:9db0e321a9f4 125 if (owns) {
kenjiArai 1:9db0e321a9f4 126 pm->unlock();
kenjiArai 1:9db0e321a9f4 127 }
kenjiArai 1:9db0e321a9f4 128 pm = mstd::exchange(u.pm, nullptr);
kenjiArai 1:9db0e321a9f4 129 owns = mstd::exchange(u.owns, false);
kenjiArai 1:9db0e321a9f4 130 return *this;
kenjiArai 1:9db0e321a9f4 131 }
kenjiArai 1:9db0e321a9f4 132
kenjiArai 1:9db0e321a9f4 133 void lock() {
kenjiArai 1:9db0e321a9f4 134 MBED_ASSERT(!owns);
kenjiArai 1:9db0e321a9f4 135 pm->lock();
kenjiArai 1:9db0e321a9f4 136 owns = true;
kenjiArai 1:9db0e321a9f4 137 }
kenjiArai 1:9db0e321a9f4 138
kenjiArai 1:9db0e321a9f4 139 bool try_lock() {
kenjiArai 1:9db0e321a9f4 140 MBED_ASSERT(!owns);
kenjiArai 1:9db0e321a9f4 141 return owns = pm->try_lock();
kenjiArai 1:9db0e321a9f4 142 }
kenjiArai 1:9db0e321a9f4 143
kenjiArai 1:9db0e321a9f4 144 #if 0 // disabled until we have functional mstd::chrono for all toolchains
kenjiArai 1:9db0e321a9f4 145 template <class Clock, class Duration>
kenjiArai 1:9db0e321a9f4 146 bool try_lock_until(const chrono::time_point<Clock, Duration> &abs_time) {
kenjiArai 1:9db0e321a9f4 147 MBED_ASSERT(!owns);
kenjiArai 1:9db0e321a9f4 148 return owns = pm->try_lock_until(abs_time);
kenjiArai 1:9db0e321a9f4 149 }
kenjiArai 1:9db0e321a9f4 150
kenjiArai 1:9db0e321a9f4 151 template <class Rep, class Period>
kenjiArai 1:9db0e321a9f4 152 bool try_lock_for(const chrono::duration<Rep, Period> &rel_time) {
kenjiArai 1:9db0e321a9f4 153 MBED_ASSERT(!owns);
kenjiArai 1:9db0e321a9f4 154 return owns = pm->try_lock_for(rel_time);
kenjiArai 1:9db0e321a9f4 155 }
kenjiArai 1:9db0e321a9f4 156 #endif
kenjiArai 1:9db0e321a9f4 157
kenjiArai 1:9db0e321a9f4 158 void unlock() {
kenjiArai 1:9db0e321a9f4 159 MBED_ASSERT(owns);
kenjiArai 1:9db0e321a9f4 160 pm->unlock();
kenjiArai 1:9db0e321a9f4 161 owns = false;
kenjiArai 1:9db0e321a9f4 162 }
kenjiArai 1:9db0e321a9f4 163
kenjiArai 1:9db0e321a9f4 164 void swap(unique_lock &u) noexcept {
kenjiArai 1:9db0e321a9f4 165 mstd::swap(pm, u.pm);
kenjiArai 1:9db0e321a9f4 166 mstd::swap(owns, u.owns);
kenjiArai 1:9db0e321a9f4 167 }
kenjiArai 1:9db0e321a9f4 168
kenjiArai 1:9db0e321a9f4 169 mutex_type *release() noexcept {
kenjiArai 1:9db0e321a9f4 170 owns = false;
kenjiArai 1:9db0e321a9f4 171 return mstd::exchange(pm, nullptr);
kenjiArai 1:9db0e321a9f4 172 }
kenjiArai 1:9db0e321a9f4 173
kenjiArai 1:9db0e321a9f4 174 bool owns_lock() const noexcept {
kenjiArai 1:9db0e321a9f4 175 return owns;
kenjiArai 1:9db0e321a9f4 176 }
kenjiArai 1:9db0e321a9f4 177
kenjiArai 1:9db0e321a9f4 178 explicit operator bool() const noexcept {
kenjiArai 1:9db0e321a9f4 179 return owns;
kenjiArai 1:9db0e321a9f4 180 }
kenjiArai 1:9db0e321a9f4 181
kenjiArai 1:9db0e321a9f4 182 mutex_type *mutex() const noexcept {
kenjiArai 1:9db0e321a9f4 183 return pm;
kenjiArai 1:9db0e321a9f4 184 }
kenjiArai 1:9db0e321a9f4 185
kenjiArai 1:9db0e321a9f4 186 private:
kenjiArai 1:9db0e321a9f4 187 mutex_type *pm;
kenjiArai 1:9db0e321a9f4 188 bool owns;
kenjiArai 1:9db0e321a9f4 189 };
kenjiArai 1:9db0e321a9f4 190
kenjiArai 1:9db0e321a9f4 191 template<class Mutex>
kenjiArai 1:9db0e321a9f4 192 void swap(unique_lock<Mutex> &x, unique_lock<Mutex> &y) noexcept
kenjiArai 1:9db0e321a9f4 193 {
kenjiArai 1:9db0e321a9f4 194 x.swap(y);
kenjiArai 1:9db0e321a9f4 195 }
kenjiArai 1:9db0e321a9f4 196
kenjiArai 1:9db0e321a9f4 197 // [thread.lock.algorithm]
kenjiArai 1:9db0e321a9f4 198 template <class L1, class L2>
kenjiArai 1:9db0e321a9f4 199 int try_lock(L1 &l1, L2 &l2)
kenjiArai 1:9db0e321a9f4 200 {
kenjiArai 1:9db0e321a9f4 201 unique_lock<L1> u1(l1, try_to_lock);
kenjiArai 1:9db0e321a9f4 202 if (!u1) {
kenjiArai 1:9db0e321a9f4 203 return 0;
kenjiArai 1:9db0e321a9f4 204 }
kenjiArai 1:9db0e321a9f4 205 if (l2.try_lock()) {
kenjiArai 1:9db0e321a9f4 206 u1.release();
kenjiArai 1:9db0e321a9f4 207 return -1;
kenjiArai 1:9db0e321a9f4 208 } else {
kenjiArai 1:9db0e321a9f4 209 return 1;
kenjiArai 1:9db0e321a9f4 210 }
kenjiArai 1:9db0e321a9f4 211 }
kenjiArai 1:9db0e321a9f4 212
kenjiArai 1:9db0e321a9f4 213 template <class L1, class L2, class L3, class... LN>
kenjiArai 1:9db0e321a9f4 214 int try_lock(L1 &l1, L2 &l2, L3 &l3, LN &... ln)
kenjiArai 1:9db0e321a9f4 215 {
kenjiArai 1:9db0e321a9f4 216 unique_lock<L1> u1(l1, try_to_lock);
kenjiArai 1:9db0e321a9f4 217 if (!u1) {
kenjiArai 1:9db0e321a9f4 218 return 0;
kenjiArai 1:9db0e321a9f4 219 }
kenjiArai 1:9db0e321a9f4 220 int result = mstd::try_lock(l2, l3, ln...);
kenjiArai 1:9db0e321a9f4 221 if (result == -1) {
kenjiArai 1:9db0e321a9f4 222 u1.release(); // make u1 release l1 so it remains locked when we return
kenjiArai 1:9db0e321a9f4 223 return -1;
kenjiArai 1:9db0e321a9f4 224 } else {
kenjiArai 1:9db0e321a9f4 225 return result + 1; // u1 unlocks l1 when we return
kenjiArai 1:9db0e321a9f4 226 }
kenjiArai 1:9db0e321a9f4 227 }
kenjiArai 1:9db0e321a9f4 228
kenjiArai 1:9db0e321a9f4 229 // Howard Hinnant's "smart" algorithm from
kenjiArai 1:9db0e321a9f4 230 // http://howardhinnant.github.io/dining_philosophers.html
kenjiArai 1:9db0e321a9f4 231 //
kenjiArai 1:9db0e321a9f4 232 // 1) Lock a mutex
kenjiArai 1:9db0e321a9f4 233 // 2) Try-lock all the rest
kenjiArai 1:9db0e321a9f4 234 // 3) If try-lock fails, retry, but starting with the mutex whose try-lock failed
kenjiArai 1:9db0e321a9f4 235 // (so we expect to block on that lock)
kenjiArai 1:9db0e321a9f4 236 //
kenjiArai 1:9db0e321a9f4 237 // Do not bother with the "polite" yield, as it adds an OS dependency and we
kenjiArai 1:9db0e321a9f4 238 // want to optimise for space, not speed.
kenjiArai 1:9db0e321a9f4 239 // Use of unique_lock is necessary to make the code correct in case of exceptions;
kenjiArai 1:9db0e321a9f4 240 // we don't strictly require this, but stick with the RAII form nevertheless -
kenjiArai 1:9db0e321a9f4 241 // overhead of unique_lock should be minimal with optimisation enabled.
kenjiArai 1:9db0e321a9f4 242 template <class L1, class L2>
kenjiArai 1:9db0e321a9f4 243 void lock(L1 &l1, L2 &l2)
kenjiArai 1:9db0e321a9f4 244 {
kenjiArai 1:9db0e321a9f4 245 for (;;) {
kenjiArai 1:9db0e321a9f4 246 {
kenjiArai 1:9db0e321a9f4 247 unique_lock<L1> u1(l1);
kenjiArai 1:9db0e321a9f4 248 if (l2.try_lock()) {
kenjiArai 1:9db0e321a9f4 249 u1.release(); // make u1 release l1 so it remains locked when we return
kenjiArai 1:9db0e321a9f4 250 return;
kenjiArai 1:9db0e321a9f4 251 }
kenjiArai 1:9db0e321a9f4 252 } // u1 unlocks l1 when we leave scope
kenjiArai 1:9db0e321a9f4 253 {
kenjiArai 1:9db0e321a9f4 254 unique_lock<L2> u2(l2);
kenjiArai 1:9db0e321a9f4 255 if (l1.try_lock()) {
kenjiArai 1:9db0e321a9f4 256 u2.release();
kenjiArai 1:9db0e321a9f4 257 return;
kenjiArai 1:9db0e321a9f4 258 }
kenjiArai 1:9db0e321a9f4 259 } // u2 unlocks l2 when we leave scope
kenjiArai 1:9db0e321a9f4 260 }
kenjiArai 1:9db0e321a9f4 261 }
kenjiArai 1:9db0e321a9f4 262
kenjiArai 1:9db0e321a9f4 263 namespace impl {
kenjiArai 1:9db0e321a9f4 264 template <class L1, class L2, class L3, class... LN>
kenjiArai 1:9db0e321a9f4 265 void lock_from(int first, L1 &l1, L2 &l2, L3 &l3, LN &... ln)
kenjiArai 1:9db0e321a9f4 266 {
kenjiArai 1:9db0e321a9f4 267 for (;;) {
kenjiArai 1:9db0e321a9f4 268 switch (first) {
kenjiArai 1:9db0e321a9f4 269 case 1:
kenjiArai 1:9db0e321a9f4 270 {
kenjiArai 1:9db0e321a9f4 271 unique_lock<L1> u1(l1);
kenjiArai 1:9db0e321a9f4 272 first = mstd::try_lock(l2, l3, ln...);
kenjiArai 1:9db0e321a9f4 273 if (first == -1) {
kenjiArai 1:9db0e321a9f4 274 u1.release();
kenjiArai 1:9db0e321a9f4 275 return;
kenjiArai 1:9db0e321a9f4 276 }
kenjiArai 1:9db0e321a9f4 277 }
kenjiArai 1:9db0e321a9f4 278 first += 2;
kenjiArai 1:9db0e321a9f4 279 break;
kenjiArai 1:9db0e321a9f4 280 case 2:
kenjiArai 1:9db0e321a9f4 281 {
kenjiArai 1:9db0e321a9f4 282 unique_lock<L2> u2(l2);
kenjiArai 1:9db0e321a9f4 283 first = mstd::try_lock(l3, ln..., l1);
kenjiArai 1:9db0e321a9f4 284 if (first == -1) {
kenjiArai 1:9db0e321a9f4 285 u2.release();
kenjiArai 1:9db0e321a9f4 286 return;
kenjiArai 1:9db0e321a9f4 287 }
kenjiArai 1:9db0e321a9f4 288 }
kenjiArai 1:9db0e321a9f4 289 first += 3;
kenjiArai 1:9db0e321a9f4 290 if (first > 3 + sizeof...(LN)) {
kenjiArai 1:9db0e321a9f4 291 first = 1;
kenjiArai 1:9db0e321a9f4 292 }
kenjiArai 1:9db0e321a9f4 293 break;
kenjiArai 1:9db0e321a9f4 294 default:
kenjiArai 1:9db0e321a9f4 295 return impl::lock_from(first - 2, l3, ln..., l1, l2);
kenjiArai 1:9db0e321a9f4 296 }
kenjiArai 1:9db0e321a9f4 297 }
kenjiArai 1:9db0e321a9f4 298 }
kenjiArai 1:9db0e321a9f4 299 }
kenjiArai 1:9db0e321a9f4 300
kenjiArai 1:9db0e321a9f4 301 template <class L1, class L2, class L3, class... LN>
kenjiArai 1:9db0e321a9f4 302 void lock(L1 &l1, L2 &l2, L3 &l3, LN &... ln)
kenjiArai 1:9db0e321a9f4 303 {
kenjiArai 1:9db0e321a9f4 304 impl::lock_from(1, l1, l2, l3, ln...);
kenjiArai 1:9db0e321a9f4 305 }
kenjiArai 1:9db0e321a9f4 306
kenjiArai 1:9db0e321a9f4 307 #endif
kenjiArai 1:9db0e321a9f4 308
kenjiArai 1:9db0e321a9f4 309
kenjiArai 1:9db0e321a9f4 310 #if __cpp_lib_scoped_lock >= 201703
kenjiArai 1:9db0e321a9f4 311 using std::scoped_lock;
kenjiArai 1:9db0e321a9f4 312 #else
kenjiArai 1:9db0e321a9f4 313 // [thread.lock.scoped]
kenjiArai 1:9db0e321a9f4 314 // 2+ locks - use std::lock
kenjiArai 1:9db0e321a9f4 315 template <class... MutexTypes>
kenjiArai 1:9db0e321a9f4 316 class scoped_lock
kenjiArai 1:9db0e321a9f4 317 #if 0 // no definition yet - needs tuple
kenjiArai 1:9db0e321a9f4 318 tuple<MutexTypes &...> pm;
kenjiArai 1:9db0e321a9f4 319 static void ignore(...) { }
kenjiArai 1:9db0e321a9f4 320 public:
kenjiArai 1:9db0e321a9f4 321 explicit scoped_lock(MutexTypes &... m) : pm(tie(m...)) { mstd::lock(m...); }
kenjiArai 1:9db0e321a9f4 322 explicit scoped_lock(adopt_lock_t, MutexTypes &... m) noexcept : pm(mstd::tie(m...)) { }
kenjiArai 1:9db0e321a9f4 323 ~scoped_lock() { mstd::apply([](MutexTypes &... m) { ignore( (void(m.unlock()),0) ...); }, pm); }
kenjiArai 1:9db0e321a9f4 324
kenjiArai 1:9db0e321a9f4 325 scoped_lock(const scoped_lock &) = delete;
kenjiArai 1:9db0e321a9f4 326 scoped_lock &operator=(const scoped_lock &) = delete;
kenjiArai 1:9db0e321a9f4 327 }
kenjiArai 1:9db0e321a9f4 328 #else
kenjiArai 1:9db0e321a9f4 329 ;
kenjiArai 1:9db0e321a9f4 330 #endif
kenjiArai 1:9db0e321a9f4 331
kenjiArai 1:9db0e321a9f4 332 // 0 locks - no-op
kenjiArai 1:9db0e321a9f4 333 template <>
kenjiArai 1:9db0e321a9f4 334 class scoped_lock<> {
kenjiArai 1:9db0e321a9f4 335 public:
kenjiArai 1:9db0e321a9f4 336 explicit scoped_lock() = default;
kenjiArai 1:9db0e321a9f4 337 explicit scoped_lock(adopt_lock_t) noexcept { }
kenjiArai 1:9db0e321a9f4 338 ~scoped_lock() = default;
kenjiArai 1:9db0e321a9f4 339
kenjiArai 1:9db0e321a9f4 340 scoped_lock(const scoped_lock &) = delete;
kenjiArai 1:9db0e321a9f4 341 scoped_lock &operator=(const scoped_lock &) = delete;
kenjiArai 1:9db0e321a9f4 342 };
kenjiArai 1:9db0e321a9f4 343
kenjiArai 1:9db0e321a9f4 344 // 1 lock - simple lock, equivalent to lock_guard<Mutex>
kenjiArai 1:9db0e321a9f4 345 template <class Mutex>
kenjiArai 1:9db0e321a9f4 346 class scoped_lock<Mutex> {
kenjiArai 1:9db0e321a9f4 347 Mutex &pm;
kenjiArai 1:9db0e321a9f4 348 public:
kenjiArai 1:9db0e321a9f4 349 using mutex_type = Mutex;
kenjiArai 1:9db0e321a9f4 350 explicit scoped_lock(Mutex &m) : pm(m) { m.lock(); }
kenjiArai 1:9db0e321a9f4 351 explicit scoped_lock(adopt_lock_t, Mutex &m) noexcept : pm(m) { }
kenjiArai 1:9db0e321a9f4 352 ~scoped_lock() { pm.unlock(); }
kenjiArai 1:9db0e321a9f4 353
kenjiArai 1:9db0e321a9f4 354 scoped_lock(const scoped_lock &) = delete;
kenjiArai 1:9db0e321a9f4 355 scoped_lock &operator=(const scoped_lock &) = delete;
kenjiArai 1:9db0e321a9f4 356 };
kenjiArai 1:9db0e321a9f4 357 #endif
kenjiArai 1:9db0e321a9f4 358
kenjiArai 1:9db0e321a9f4 359 // [thread.once.onceflag]
kenjiArai 1:9db0e321a9f4 360 // Always local implementation - need to investigate GCC + ARMC6 retargetting
kenjiArai 1:9db0e321a9f4 361 struct once_flag {
kenjiArai 1:9db0e321a9f4 362 constexpr once_flag() noexcept : __guard() { }
kenjiArai 1:9db0e321a9f4 363 once_flag(const once_flag &) = delete;
kenjiArai 1:9db0e321a9f4 364 once_flag &operator=(const once_flag &) = delete;
kenjiArai 1:9db0e321a9f4 365 ~once_flag() = default;
kenjiArai 1:9db0e321a9f4 366 private:
kenjiArai 1:9db0e321a9f4 367 template <class Callable, class... Args>
kenjiArai 1:9db0e321a9f4 368 friend void call_once(once_flag &flag, Callable&& f, Args&&... args);
kenjiArai 1:9db0e321a9f4 369 int __guard;
kenjiArai 1:9db0e321a9f4 370 };
kenjiArai 1:9db0e321a9f4 371
kenjiArai 1:9db0e321a9f4 372 // [thread.once.callonce]
kenjiArai 1:9db0e321a9f4 373 template <class Callable, class... Args>
kenjiArai 1:9db0e321a9f4 374 void call_once(once_flag &flag, Callable&& f, Args&&... args)
kenjiArai 1:9db0e321a9f4 375 {
kenjiArai 1:9db0e321a9f4 376 if (!(core_util_atomic_load_explicit((uint8_t *)&flag.__guard, mbed_memory_order_acquire) & 1)) {
kenjiArai 1:9db0e321a9f4 377 if (__cxa_guard_acquire(&flag.__guard)) {
kenjiArai 1:9db0e321a9f4 378 mstd::invoke(mstd::forward<Callable>(f), mstd::forward<Args>(args)...);
kenjiArai 1:9db0e321a9f4 379 __cxa_guard_release(&flag.__guard);
kenjiArai 1:9db0e321a9f4 380 }
kenjiArai 1:9db0e321a9f4 381 }
kenjiArai 1:9db0e321a9f4 382 }
kenjiArai 1:9db0e321a9f4 383
kenjiArai 1:9db0e321a9f4 384 // [thread.mutex.class]
kenjiArai 1:9db0e321a9f4 385 // Always local implementation - need to investigate GCC + ARMC6 retargetting
kenjiArai 1:9db0e321a9f4 386 #if MBED_CONF_RTOS_PRESENT
kenjiArai 1:9db0e321a9f4 387 class _Mutex_base {
kenjiArai 1:9db0e321a9f4 388 // Constructor must be constexpr - we are required to initialise on first use
kenjiArai 1:9db0e321a9f4 389 // not in our constructor. (So that mutex use in static constructors is safe).
kenjiArai 1:9db0e321a9f4 390 SingletonPtr<rtos::Mutex> _pm;
kenjiArai 1:9db0e321a9f4 391 public:
kenjiArai 1:9db0e321a9f4 392 constexpr _Mutex_base() noexcept = default;
kenjiArai 1:9db0e321a9f4 393 ~_Mutex_base();
kenjiArai 1:9db0e321a9f4 394 _Mutex_base(const _Mutex_base &) = delete;
kenjiArai 1:9db0e321a9f4 395 _Mutex_base &operator=(const _Mutex_base &) = delete;
kenjiArai 1:9db0e321a9f4 396 void lock();
kenjiArai 1:9db0e321a9f4 397 bool try_lock();
kenjiArai 1:9db0e321a9f4 398 void unlock();
kenjiArai 1:9db0e321a9f4 399 };
kenjiArai 1:9db0e321a9f4 400 #else
kenjiArai 1:9db0e321a9f4 401 class _Mutex_base {
kenjiArai 1:9db0e321a9f4 402 public:
kenjiArai 1:9db0e321a9f4 403 constexpr _Mutex_base() noexcept = default;
kenjiArai 1:9db0e321a9f4 404 ~_Mutex_base() = default;
kenjiArai 1:9db0e321a9f4 405 _Mutex_base(const _Mutex_base &) = delete;
kenjiArai 1:9db0e321a9f4 406 _Mutex_base &operator=(const _Mutex_base &) = delete;
kenjiArai 1:9db0e321a9f4 407 void lock() { }
kenjiArai 1:9db0e321a9f4 408 bool try_lock() { return true; }
kenjiArai 1:9db0e321a9f4 409 void unlock() { }
kenjiArai 1:9db0e321a9f4 410 };
kenjiArai 1:9db0e321a9f4 411 #endif
kenjiArai 1:9db0e321a9f4 412
kenjiArai 1:9db0e321a9f4 413 // We don't currently distinguish implementations (and aren't required to -
kenjiArai 1:9db0e321a9f4 414 // current thread not owning a non-recursive one is a precondition, we don't
kenjiArai 1:9db0e321a9f4 415 // have to take any special action).
kenjiArai 1:9db0e321a9f4 416 class mutex : public _Mutex_base {
kenjiArai 1:9db0e321a9f4 417 };
kenjiArai 1:9db0e321a9f4 418
kenjiArai 1:9db0e321a9f4 419 // [thread.mutex.recursive]
kenjiArai 1:9db0e321a9f4 420 class recursive_mutex : public _Mutex_base {
kenjiArai 1:9db0e321a9f4 421 };
kenjiArai 1:9db0e321a9f4 422
kenjiArai 1:9db0e321a9f4 423 } // namespace mstd
kenjiArai 1:9db0e321a9f4 424
kenjiArai 1:9db0e321a9f4 425 #endif // MSTD_MUTEX_