/src/immer/immer/lock/spinlock_policy.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // immer: immutable data structures for C++ |
3 | | // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente |
4 | | // |
5 | | // This software is distributed under the Boost Software License, Version 1.0. |
6 | | // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt |
7 | | // |
8 | | |
9 | | #pragma once |
10 | | |
11 | | #include <atomic> |
12 | | #include <thread> |
13 | | |
14 | | // This has been shamelessly copied from boost... |
15 | | #if defined(_MSC_VER) && _MSC_VER >= 1310 && \ |
16 | | (defined(_M_IX86) || defined(_M_X64)) && !defined(__c2__) |
17 | | extern "C" void _mm_pause(); |
18 | | #define IMMER_SMT_PAUSE _mm_pause() |
19 | | #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) |
20 | | #define IMMER_SMT_PAUSE __asm__ __volatile__("rep; nop" : : : "memory") |
21 | | #endif |
22 | | |
23 | | namespace immer { |
24 | | |
25 | | // This is an atomic spinlock similar to the one used by boost to provide |
26 | | // "atomic" shared_ptr operations. It also does not differ much from the one |
27 | | // from libc++ or libstdc++... |
28 | | struct spinlock_policy |
29 | | { |
30 | | std::atomic_flag v_{}; |
31 | | |
32 | 0 | bool try_lock() { return !v_.test_and_set(std::memory_order_acquire); } |
33 | | |
34 | | void lock() |
35 | 0 | { |
36 | 0 | for (auto k = 0u; !try_lock(); ++k) { |
37 | 0 | if (k < 4) |
38 | 0 | continue; |
39 | 0 | #ifdef IMMER_SMT_PAUSE |
40 | 0 | else if (k < 16) |
41 | 0 | IMMER_SMT_PAUSE; |
42 | 0 | #endif |
43 | 0 | else |
44 | 0 | std::this_thread::yield(); |
45 | 0 | } |
46 | 0 | } |
47 | | |
48 | 0 | void unlock() { v_.clear(std::memory_order_release); } |
49 | | |
50 | | struct scoped_lock |
51 | | { |
52 | | scoped_lock(const scoped_lock&) = delete; |
53 | | scoped_lock& operator=(const scoped_lock&) = delete; |
54 | | |
55 | | explicit scoped_lock(spinlock_policy& sp) |
56 | | : sp_{sp} |
57 | 0 | { |
58 | 0 | sp.lock(); |
59 | 0 | } |
60 | | |
61 | 0 | ~scoped_lock() { sp_.unlock(); } |
62 | | |
63 | | private: |
64 | | spinlock_policy& sp_; |
65 | | }; |
66 | | }; |
67 | | |
68 | | } // namespace immer |