| 1 | /*
|
|---|
| 2 | * SPDX-FileCopyrightText: 2018 Jaroslav Jindrak
|
|---|
| 3 | *
|
|---|
| 4 | * SPDX-License-Identifier: BSD-3-Clause
|
|---|
| 5 | */
|
|---|
| 6 |
|
|---|
| 7 | #ifndef LIBCPP_BITS_THREAD_MUTEX
|
|---|
| 8 | #define LIBCPP_BITS_THREAD_MUTEX
|
|---|
| 9 |
|
|---|
| 10 | #include <__bits/thread/threading.hpp>
|
|---|
| 11 | #include <functional>
|
|---|
| 12 | #include <thread>
|
|---|
| 13 |
|
|---|
| 14 | namespace std
|
|---|
| 15 | {
|
|---|
| 16 | /**
|
|---|
| 17 | * 20.4.1.2.1, class mutex:
|
|---|
| 18 | */
|
|---|
| 19 |
|
|---|
| 20 | class mutex
|
|---|
| 21 | {
|
|---|
| 22 | public:
|
|---|
| 23 | constexpr mutex() noexcept
|
|---|
| 24 | : mtx_{}
|
|---|
| 25 | {
|
|---|
| 26 | aux::threading::mutex::init(mtx_);
|
|---|
| 27 | }
|
|---|
| 28 |
|
|---|
| 29 | ~mutex() = default;
|
|---|
| 30 |
|
|---|
| 31 | mutex(const mutex&) = delete;
|
|---|
| 32 | mutex& operator=(const mutex&) = delete;
|
|---|
| 33 |
|
|---|
| 34 | void lock();
|
|---|
| 35 | bool try_lock();
|
|---|
| 36 | void unlock();
|
|---|
| 37 |
|
|---|
| 38 | using native_handle_type = aux::mutex_t*;
|
|---|
| 39 | native_handle_type native_handle();
|
|---|
| 40 |
|
|---|
| 41 | private:
|
|---|
| 42 | aux::mutex_t mtx_;
|
|---|
| 43 | };
|
|---|
| 44 |
|
|---|
| 45 | /**
|
|---|
| 46 | * 30.4.1.2.2, class recursive_mutex:
|
|---|
| 47 | */
|
|---|
| 48 |
|
|---|
| 49 | class recursive_mutex
|
|---|
| 50 | {
|
|---|
| 51 | public:
|
|---|
| 52 | constexpr recursive_mutex() noexcept
|
|---|
| 53 | : mtx_{}, lock_level_{}, owner_{}
|
|---|
| 54 | {
|
|---|
| 55 | aux::threading::mutex::init(mtx_);
|
|---|
| 56 | }
|
|---|
| 57 |
|
|---|
| 58 | ~recursive_mutex();
|
|---|
| 59 |
|
|---|
| 60 | recursive_mutex(const recursive_mutex&) = delete;
|
|---|
| 61 | recursive_mutex& operator=(const recursive_mutex&) = delete;
|
|---|
| 62 |
|
|---|
| 63 | void lock();
|
|---|
| 64 | bool try_lock() noexcept;
|
|---|
| 65 | void unlock();
|
|---|
| 66 |
|
|---|
| 67 | using native_handle_type = aux::mutex_t*;
|
|---|
| 68 | native_handle_type native_handle();
|
|---|
| 69 |
|
|---|
| 70 | private:
|
|---|
| 71 | aux::mutex_t mtx_;
|
|---|
| 72 | size_t lock_level_;
|
|---|
| 73 | thread::id owner_;
|
|---|
| 74 | };
|
|---|
| 75 |
|
|---|
| 76 | /**
|
|---|
| 77 | * 30.4.1.3.1, class timed_mutex:
|
|---|
| 78 | */
|
|---|
| 79 |
|
|---|
| 80 | class timed_mutex
|
|---|
| 81 | {
|
|---|
| 82 | public:
|
|---|
| 83 | timed_mutex() noexcept;
|
|---|
| 84 | ~timed_mutex();
|
|---|
| 85 |
|
|---|
| 86 | timed_mutex(const timed_mutex&) = delete;
|
|---|
| 87 | timed_mutex& operator=(const timed_mutex&) = delete;
|
|---|
| 88 |
|
|---|
| 89 | void lock();
|
|---|
| 90 | bool try_lock();
|
|---|
| 91 | void unlock();
|
|---|
| 92 |
|
|---|
| 93 | template<class Rep, class Period>
|
|---|
| 94 | bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
|---|
| 95 | {
|
|---|
| 96 | auto time = aux::threading::time::convert(rel_time);
|
|---|
| 97 |
|
|---|
| 98 | return aux::threading::mutex::try_lock_for(time);
|
|---|
| 99 | }
|
|---|
| 100 |
|
|---|
| 101 | template<class Clock, class Duration>
|
|---|
| 102 | bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
|
|---|
| 103 | {
|
|---|
| 104 | auto dur = (abs_time - Clock::now());
|
|---|
| 105 | auto time = aux::threading::time::convert(dur);
|
|---|
| 106 |
|
|---|
| 107 | return aux::threading::mutex::try_lock_for(time);
|
|---|
| 108 | }
|
|---|
| 109 |
|
|---|
| 110 | using native_handle_type = aux::mutex_t*;
|
|---|
| 111 | native_handle_type native_handle();
|
|---|
| 112 |
|
|---|
| 113 | private:
|
|---|
| 114 | aux::mutex_t mtx_;
|
|---|
| 115 | };
|
|---|
| 116 |
|
|---|
| 117 | /**
|
|---|
| 118 | * 30.4.1.3.2, class recursive_timed_mutex:
|
|---|
| 119 | */
|
|---|
| 120 |
|
|---|
| 121 | class recursive_timed_mutex
|
|---|
| 122 | {
|
|---|
| 123 | public:
|
|---|
| 124 | recursive_timed_mutex() noexcept
|
|---|
| 125 | : mtx_{}, lock_level_{}, owner_{}
|
|---|
| 126 | {
|
|---|
| 127 | aux::threading::mutex::init(mtx_);
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | ~recursive_timed_mutex();
|
|---|
| 131 |
|
|---|
| 132 | recursive_timed_mutex(const recursive_timed_mutex&) = delete;
|
|---|
| 133 | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
|
|---|
| 134 |
|
|---|
| 135 | void lock();
|
|---|
| 136 | bool try_lock() noexcept;
|
|---|
| 137 | void unlock();
|
|---|
| 138 |
|
|---|
| 139 | template<class Rep, class Period>
|
|---|
| 140 | bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
|---|
| 141 | {
|
|---|
| 142 | if (owner_ == this_thread::get_id())
|
|---|
| 143 | return true;
|
|---|
| 144 |
|
|---|
| 145 | auto time = aux::threading::time::convert(rel_time);
|
|---|
| 146 | auto ret = aux::threading::mutex::try_lock_for(time);
|
|---|
| 147 |
|
|---|
| 148 | if (ret)
|
|---|
| 149 | ++lock_level_;
|
|---|
| 150 | return ret;
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|
| 153 | template<class Clock, class Duration>
|
|---|
| 154 | bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
|
|---|
| 155 | {
|
|---|
| 156 | if (owner_ == this_thread::get_id())
|
|---|
| 157 | return true;
|
|---|
| 158 |
|
|---|
| 159 | auto dur = (abs_time - Clock::now());
|
|---|
| 160 | auto time = aux::threading::time::convert(dur);
|
|---|
| 161 | auto ret = aux::threading::mutex::try_lock_for(time);
|
|---|
| 162 |
|
|---|
| 163 | if (ret)
|
|---|
| 164 | ++lock_level_;
|
|---|
| 165 | return ret;
|
|---|
| 166 | }
|
|---|
| 167 |
|
|---|
| 168 | using native_handle_type = aux::mutex_t*;
|
|---|
| 169 | native_handle_type native_handle();
|
|---|
| 170 |
|
|---|
| 171 | private:
|
|---|
| 172 | aux::mutex_t mtx_;
|
|---|
| 173 | size_t lock_level_;
|
|---|
| 174 | thread::id owner_;
|
|---|
| 175 | };
|
|---|
| 176 |
|
|---|
| 177 | struct defer_lock_t
|
|---|
| 178 | { /* DUMMY BODY */ };
|
|---|
| 179 |
|
|---|
| 180 | struct try_to_lock_t
|
|---|
| 181 | { /* DUMMY BODY */ };
|
|---|
| 182 |
|
|---|
| 183 | struct adopt_lock_t
|
|---|
| 184 | { /* DUMMY BODY */ };
|
|---|
| 185 |
|
|---|
| 186 | constexpr defer_lock_t defer_lock
|
|---|
| 187 | { /* DUMMY BODY */ };
|
|---|
| 188 |
|
|---|
| 189 | constexpr try_to_lock_t try_to_lock
|
|---|
| 190 | { /* DUMMY BODY */ };
|
|---|
| 191 |
|
|---|
| 192 | constexpr adopt_lock_t adopt_lock
|
|---|
| 193 | { /* DUMMY BODY */ };
|
|---|
| 194 |
|
|---|
| 195 | /**
|
|---|
| 196 | * 30.4.2.1, class template lock_guard:
|
|---|
| 197 | */
|
|---|
| 198 |
|
|---|
| 199 | template<class Mutex>
|
|---|
| 200 | class lock_guard
|
|---|
| 201 | {
|
|---|
| 202 | public:
|
|---|
| 203 | using mutex_type = Mutex;
|
|---|
| 204 |
|
|---|
| 205 | explicit lock_guard(mutex_type& mtx)
|
|---|
| 206 | : mtx_{mtx}
|
|---|
| 207 | {
|
|---|
| 208 | mtx.lock();
|
|---|
| 209 | }
|
|---|
| 210 |
|
|---|
| 211 | lock_guard(mutex_type& mtx, adopt_lock_t)
|
|---|
| 212 | : mtx_{mtx}
|
|---|
| 213 | { /* DUMMY BODY */ }
|
|---|
| 214 |
|
|---|
| 215 | ~lock_guard()
|
|---|
| 216 | {
|
|---|
| 217 | mtx_.unlock();
|
|---|
| 218 | }
|
|---|
| 219 |
|
|---|
| 220 | lock_guard(const lock_guard&) = delete;
|
|---|
| 221 | lock_guard& operator=(const lock_guard&) = delete;
|
|---|
| 222 |
|
|---|
| 223 | private:
|
|---|
| 224 | mutex_type& mtx_;
|
|---|
| 225 | };
|
|---|
| 226 |
|
|---|
| 227 | template<class Mutex>
|
|---|
| 228 | class unique_lock
|
|---|
| 229 | {
|
|---|
| 230 | public:
|
|---|
| 231 | using mutex_type = Mutex;
|
|---|
| 232 |
|
|---|
| 233 | /**
|
|---|
| 234 | * 30.4.2.2.1, construction/copy/destroy:
|
|---|
| 235 | */
|
|---|
| 236 |
|
|---|
| 237 | unique_lock() noexcept
|
|---|
| 238 | : mtx_{nullptr}, owns_{false}
|
|---|
| 239 | { /* DUMMY BODY */ }
|
|---|
| 240 |
|
|---|
| 241 | explicit unique_lock(mutex_type& mtx)
|
|---|
| 242 | : mtx_{&mtx}, owns_{true}
|
|---|
| 243 | {
|
|---|
| 244 | mtx_->lock();
|
|---|
| 245 | }
|
|---|
| 246 |
|
|---|
| 247 | unique_lock(mutex_type& mtx, defer_lock_t) noexcept
|
|---|
| 248 | : mtx_{&mtx}, owns_{false}
|
|---|
| 249 | { /* DUMMY BODY */ }
|
|---|
| 250 |
|
|---|
| 251 | unique_lock(mutex_type& mtx, try_to_lock_t)
|
|---|
| 252 | : mtx_{&mtx}, owns_{}
|
|---|
| 253 | {
|
|---|
| 254 | owns_ = mtx_->try_lock();
|
|---|
| 255 | }
|
|---|
| 256 |
|
|---|
| 257 | unique_lock(mutex_type& mtx, adopt_lock_t)
|
|---|
| 258 | : mtx_{&mtx}, owns_{true}
|
|---|
| 259 | { /* DUMMY BODY */ }
|
|---|
| 260 |
|
|---|
| 261 | template<class Clock, class Duration>
|
|---|
| 262 | unique_lock(mutex_type& mtx, const chrono::time_point<Clock, Duration>& abs_time)
|
|---|
| 263 | : mtx_{&mtx}, owns_{}
|
|---|
| 264 | {
|
|---|
| 265 | owns_ = mtx_->try_lock_until(abs_time);
|
|---|
| 266 | }
|
|---|
| 267 |
|
|---|
| 268 | template<class Rep, class Period>
|
|---|
| 269 | unique_lock(mutex_type& mtx, const chrono::duration<Rep, Period>& rel_time)
|
|---|
| 270 | : mtx_{&mtx}, owns_{}
|
|---|
| 271 | {
|
|---|
| 272 | owns_ = mtx_->try_lock_for(rel_time);
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | ~unique_lock()
|
|---|
| 276 | {
|
|---|
| 277 | if (owns_)
|
|---|
| 278 | mtx_->unlock();
|
|---|
| 279 | }
|
|---|
| 280 |
|
|---|
| 281 | unique_lock(const unique_lock&) = delete;
|
|---|
| 282 | unique_lock& operator=(const unique_lock&) = delete;
|
|---|
| 283 |
|
|---|
| 284 | unique_lock(unique_lock&& other) noexcept
|
|---|
| 285 | : mtx_{move(other.mtx_)}, owns_{move(other.owns_)}
|
|---|
| 286 | {
|
|---|
| 287 | other.mtx_ = nullptr;
|
|---|
| 288 | other.owns_ = false;
|
|---|
| 289 | }
|
|---|
| 290 |
|
|---|
| 291 | unique_lock& operator=(unique_lock&& other)
|
|---|
| 292 | {
|
|---|
| 293 | if (owns_)
|
|---|
| 294 | mtx_->unlock();
|
|---|
| 295 |
|
|---|
| 296 | mtx_ = move(other.mtx_);
|
|---|
| 297 | owns_ = move(other.owns_);
|
|---|
| 298 |
|
|---|
| 299 | other.mtx_ = nullptr;
|
|---|
| 300 | other.owns_ = false;
|
|---|
| 301 | }
|
|---|
| 302 |
|
|---|
| 303 | /**
|
|---|
| 304 | * 30.4.2.2.2, locking:
|
|---|
| 305 | */
|
|---|
| 306 |
|
|---|
| 307 | void lock()
|
|---|
| 308 | {
|
|---|
| 309 | /**
|
|---|
| 310 | * TODO:
|
|---|
| 311 | * throw system_error operation_not_permitted if mtx_ == nullptr
|
|---|
| 312 | * throw system_error resource_deadlock_would_occur if owns_ == true
|
|---|
| 313 | */
|
|---|
| 314 |
|
|---|
| 315 | mtx_->lock();
|
|---|
| 316 | owns_ = true;
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | bool try_lock()
|
|---|
| 320 | {
|
|---|
| 321 | /**
|
|---|
| 322 | * TODO:
|
|---|
| 323 | * throw system_error operation_not_permitted if mtx_ == nullptr
|
|---|
| 324 | * throw system_error resource_deadlock_would_occur if owns_ == true
|
|---|
| 325 | */
|
|---|
| 326 |
|
|---|
| 327 | owns_ = mtx_->try_lock();
|
|---|
| 328 |
|
|---|
| 329 | return owns_;
|
|---|
| 330 | }
|
|---|
| 331 |
|
|---|
| 332 | template<class Rep, class Period>
|
|---|
| 333 | bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
|---|
| 334 | {
|
|---|
| 335 | /**
|
|---|
| 336 | * TODO:
|
|---|
| 337 | * throw system_error operation_not_permitted if mtx_ == nullptr
|
|---|
| 338 | * throw system_error resource_deadlock_would_occur if owns_ == true
|
|---|
| 339 | */
|
|---|
| 340 |
|
|---|
| 341 | owns_ = mtx_->try_lock_for(rel_time);
|
|---|
| 342 |
|
|---|
| 343 | return owns_;
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | template<class Clock, class Duration>
|
|---|
| 347 | bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
|
|---|
| 348 | {
|
|---|
| 349 | /**
|
|---|
| 350 | * TODO:
|
|---|
| 351 | * throw system_error operation_not_permitted if mtx_ == nullptr
|
|---|
| 352 | * throw system_error resource_deadlock_would_occur if owns_ == true
|
|---|
| 353 | */
|
|---|
| 354 |
|
|---|
| 355 | owns_ = mtx_->try_lock_until(abs_time);
|
|---|
| 356 |
|
|---|
| 357 | return owns_;
|
|---|
| 358 | }
|
|---|
| 359 |
|
|---|
| 360 | void unlock()
|
|---|
| 361 | {
|
|---|
| 362 | /**
|
|---|
| 363 | * TODO:
|
|---|
| 364 | * throw system_error operation_not_permitted if owns_ == false
|
|---|
| 365 | */
|
|---|
| 366 |
|
|---|
| 367 | mtx_->unlock();
|
|---|
| 368 | }
|
|---|
| 369 |
|
|---|
| 370 | /**
|
|---|
| 371 | * 30.4.2.2.3, modifiers:
|
|---|
| 372 | */
|
|---|
| 373 |
|
|---|
| 374 | void swap(unique_lock& other) noexcept
|
|---|
| 375 | {
|
|---|
| 376 | std::swap(mtx_, other.mtx_);
|
|---|
| 377 | std::swap(owns_, other.owns_);
|
|---|
| 378 | }
|
|---|
| 379 |
|
|---|
| 380 | mutex_type* release() noexcept
|
|---|
| 381 | {
|
|---|
| 382 | auto ret = mtx_;
|
|---|
| 383 | mtx_ = nullptr;
|
|---|
| 384 | owns_ = false;
|
|---|
| 385 |
|
|---|
| 386 | return ret;
|
|---|
| 387 | }
|
|---|
| 388 |
|
|---|
| 389 | /**
|
|---|
| 390 | * 30.4.2.2.4, observers:
|
|---|
| 391 | */
|
|---|
| 392 |
|
|---|
| 393 | bool owns_lock() const noexcept
|
|---|
| 394 | {
|
|---|
| 395 | return owns_;
|
|---|
| 396 | }
|
|---|
| 397 |
|
|---|
| 398 | explicit operator bool() const noexcept
|
|---|
| 399 | {
|
|---|
| 400 | return owns_;
|
|---|
| 401 | }
|
|---|
| 402 |
|
|---|
| 403 | mutex_type* mutex() const noexcept
|
|---|
| 404 | {
|
|---|
| 405 | return mtx_;
|
|---|
| 406 | }
|
|---|
| 407 |
|
|---|
| 408 | private:
|
|---|
| 409 | mutex_type* mtx_;
|
|---|
| 410 | bool owns_;
|
|---|
| 411 | };
|
|---|
| 412 |
|
|---|
| 413 | template<class Mutex>
|
|---|
| 414 | void swap(unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs) noexcept
|
|---|
| 415 | {
|
|---|
| 416 | lhs.swap(rhs);
|
|---|
| 417 | }
|
|---|
| 418 |
|
|---|
| 419 | namespace aux
|
|---|
| 420 | {
|
|---|
| 421 | template<class L>
|
|---|
| 422 | int try_lock_tail(int idx, L& l)
|
|---|
| 423 | {
|
|---|
| 424 | if (!l.try_lock())
|
|---|
| 425 | return idx;
|
|---|
| 426 | else
|
|---|
| 427 | return -1;
|
|---|
| 428 | }
|
|---|
| 429 |
|
|---|
| 430 | template<class L1, class... L2>
|
|---|
| 431 | int try_lock_tail(int idx, L1& l1, L2&... ls)
|
|---|
| 432 | {
|
|---|
| 433 | if (!l1.try_lock())
|
|---|
| 434 | return idx;
|
|---|
| 435 |
|
|---|
| 436 | auto ret = try_lock_tail(idx + 1, ls...);
|
|---|
| 437 | if (ret != -1)
|
|---|
| 438 | l1.unlock();
|
|---|
| 439 |
|
|---|
| 440 | return ret;
|
|---|
| 441 | }
|
|---|
| 442 | }
|
|---|
| 443 |
|
|---|
| 444 | template<class L1, class L2, class... L3>
|
|---|
| 445 | int try_lock(L1& l1, L2& l2, L3&... ls)
|
|---|
| 446 | {
|
|---|
| 447 | return aux::try_lock_tail(0, l1, l2, ls...);
|
|---|
| 448 | }
|
|---|
| 449 |
|
|---|
| 450 | namespace aux
|
|---|
| 451 | {
|
|---|
| 452 | template<class L>
|
|---|
| 453 | bool lock_tail(L& l)
|
|---|
| 454 | {
|
|---|
| 455 | return l.try_lock();
|
|---|
| 456 | }
|
|---|
| 457 |
|
|---|
| 458 | template<class L1, class... L2>
|
|---|
| 459 | bool lock_tail(L1& l1, L2&... ls)
|
|---|
| 460 | {
|
|---|
| 461 | if (l1.try_lock())
|
|---|
| 462 | {
|
|---|
| 463 | auto ret = lock_tail(ls...);
|
|---|
| 464 | if (ret)
|
|---|
| 465 | return true;
|
|---|
| 466 |
|
|---|
| 467 | l1.unlock();
|
|---|
| 468 | }
|
|---|
| 469 |
|
|---|
| 470 | return false;
|
|---|
| 471 | }
|
|---|
| 472 | }
|
|---|
| 473 |
|
|---|
| 474 | template<class L1, class L2, class... L3>
|
|---|
| 475 | void lock(L1& l1, L2& l2, L3&... ls)
|
|---|
| 476 | {
|
|---|
| 477 | do
|
|---|
| 478 | {
|
|---|
| 479 | l1.lock();
|
|---|
| 480 |
|
|---|
| 481 | if (aux::lock_tail(l2, ls...))
|
|---|
| 482 | return;
|
|---|
| 483 | l1.unlock();
|
|---|
| 484 | } while (true);
|
|---|
| 485 | }
|
|---|
| 486 |
|
|---|
| 487 | struct once_flag
|
|---|
| 488 | {
|
|---|
| 489 | constexpr once_flag() noexcept
|
|---|
| 490 | : called_{false}, mtx_{}
|
|---|
| 491 | { /* DUMMY BODY */ }
|
|---|
| 492 |
|
|---|
| 493 | once_flag(const once_flag&) = delete;
|
|---|
| 494 | once_flag& operator=(const once_flag&) = delete;
|
|---|
| 495 |
|
|---|
| 496 | private:
|
|---|
| 497 | bool called_;
|
|---|
| 498 | mutex mtx_;
|
|---|
| 499 |
|
|---|
| 500 | template<class Callable, class... Args>
|
|---|
| 501 | friend void call_once(once_flag&, Callable&&, Args&&...);
|
|---|
| 502 | };
|
|---|
| 503 |
|
|---|
| 504 | template<class Callable, class... Args>
|
|---|
| 505 | void call_once(once_flag& flag, Callable&& func, Args&&... args)
|
|---|
| 506 | {
|
|---|
| 507 | flag.mtx_.lock();
|
|---|
| 508 | if (!flag.called_)
|
|---|
| 509 | {
|
|---|
| 510 | // TODO: exception handling
|
|---|
| 511 |
|
|---|
| 512 | aux::INVOKE(forward<Callable>(func), forward<Args>(args)...);
|
|---|
| 513 | flag.called_ = true;
|
|---|
| 514 | }
|
|---|
| 515 | flag.mtx_.unlock();
|
|---|
| 516 | }
|
|---|
| 517 | }
|
|---|
| 518 |
|
|---|
| 519 | #endif
|
|---|