/home/users/khuck/src/hpx-lsu/hpx/lcos/local/spinlock.hpp

Line% of fetchesSource
1  
////////////////////////////////////////////////////////////////////////////////
2  
//  Copyright (c) 2011 Bryce Lelbach
3  
//  Copyright (c) 2011-2016 Hartmut Kaiser
4  
//  Copyright (c) 2014 Thomas Heller
5  
//
6  
//  Copyright (c) 2008 Peter Dimov
7  
//
8  
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
9  
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10  
////////////////////////////////////////////////////////////////////////////////
11  
12  
#if !defined(HPX_B3A83B49_92E0_4150_A551_488F9F5E1113)
13  
#define HPX_B3A83B49_92E0_4150_A551_488F9F5E1113
14  
15  
#include <hpx/config.hpp>
16  
#ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION
17  
#include <hpx/throw_exception.hpp>
18  
#endif
19  
#include <hpx/runtime/threads/thread_helpers.hpp>
20  
#include <hpx/util/itt_notify.hpp>
21  
#include <hpx/util/register_locks.hpp>
22  
23  
#if defined(HPX_WINDOWS)
24  
#  include <boost/smart_ptr/detail/spinlock.hpp>
25  
#  if !defined( BOOST_SP_HAS_SYNC )
26  
#    include <boost/detail/interlocked.hpp>
27  
#  endif
28  
#else
29  
#  if !defined(__ANDROID__) && !defined(ANDROID) && !defined(__arm__)
30  
#    include <boost/smart_ptr/detail/spinlock.hpp>
31  
#    if defined( __ia64__ ) && defined( __INTEL_COMPILER )
32  
#      include <ia64intrin.h>
33  
#    endif
34  
#  endif
35  
#endif
36  
37  
#include <cstddef>
38  
#include <cstdint>
39  
40  
///////////////////////////////////////////////////////////////////////////////
41  
namespace hpx { namespace lcos { namespace local
42  
{
43  
#ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION
44  
    HPX_API_EXPORT extern bool spinlock_break_on_deadlock;
45  
    HPX_API_EXPORT extern std::size_t spinlock_deadlock_detection_limit;
46  
#endif
47  
48  
    /// boost::mutex-compatible spinlock class
49  
    struct spinlock
50  
    {
51  
    private:
52  
        HPX_NON_COPYABLE(spinlock);
53  
54  
    private:
55  
#if defined(__ANDROID__) && defined(ANDROID)
56  
        int v_;
57  
#else
58  
        std::uint64_t v_;
59  
#endif
60  
61  
    public:
62  
        ///////////////////////////////////////////////////////////////////////
63  
        static void yield(std::size_t k)
64  
        {
65  
            if (k < 4) //-V112
66  
            {
67  
            }
68  
#if defined(BOOST_SMT_PAUSE)
69  
            else if(k < 16)
70  
            {
71  
                BOOST_SMT_PAUSE
72  
            }
73  
#endif
74  
            else if(k < 32 || k & 1) //-V112
75  
            {
76  
                if (hpx::threads::get_self_ptr())
77  
                {
78  
                    hpx::this_thread::suspend(hpx::threads::pending,
79  
                        "hpx::lcos::local::spinlock::yield");
80  
                }
81  
                else
82  
                {
83  
#if defined(HPX_WINDOWS)
84  
                    Sleep(0);
85  
#elif defined(BOOST_HAS_PTHREADS)
86  
                    sched_yield();
87  
#else
88  
#endif
89  
                }
90  
            }
91  
            else
92  
            {
93  
#ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION
94  
                if (spinlock_break_on_deadlock &&
95  
                    k > spinlock_deadlock_detection_limit)
96  
                {
97  
                    HPX_THROW_EXCEPTION(deadlock,
98  
                        "hpx::lcos::local::spinlock::yield",
99  
                        "possible deadlock detected");
100  
                }
101  
#endif
102  
103  
                if (hpx::threads::get_self_ptr())
104  
                {
105  
                    hpx::this_thread::suspend(hpx::threads::pending,
106  
                        "hpx::lcos::local::spinlock::yield");
107  
                }
108  
                else
109  
                {
110  
#if defined(HPX_WINDOWS)
111  
                    Sleep(1);
112  
#elif defined(BOOST_HAS_PTHREADS)
113  
                    // g++ -Wextra warns on {} or {0}
114  
                    struct timespec rqtp = { 0, 0 };
115  
116  
                    // POSIX says that timespec has tv_sec and tv_nsec
117  
                    // But it doesn't guarantee order or placement
118  
119  
                    rqtp.tv_sec = 0;
120  
                    rqtp.tv_nsec = 1000;
121  
122  
                    nanosleep( &rqtp, nullptr );
123  
#else
124  
#endif
125  
                }
126  
            }
127  
        }
128  
129  
    public:
130  
        spinlock(char const* const desc = "hpx::lcos::local::spinlock")
131  
          : v_(0)
132  
        {
133  
            HPX_ITT_SYNC_CREATE(this, desc, "");
134  
        }
135  
136  
        ~spinlock()
137  
        {
138  
            HPX_ITT_SYNC_DESTROY(this);
139  
        }
140  
141  
        void lock()
142  
        {
143  
            HPX_ITT_SYNC_PREPARE(this);
144  
145  
            for (std::size_t k = 0; !acquire_lock(); ++k)
146  
            {
147  
                spinlock::yield(k);
148  
            }
149  
150  
            HPX_ITT_SYNC_ACQUIRED(this);
151  
            util::register_lock(this);
152  
        }
153  
154  
        bool try_lock()
155  
        {
156  
            HPX_ITT_SYNC_PREPARE(this);
157  
158  
            bool r = acquire_lock(); //-V707
159  
160  
            if (r) {
161  
                HPX_ITT_SYNC_ACQUIRED(this);
162  
                util::register_lock(this);
163  
                return true;
164  
            }
165  
166  
            HPX_ITT_SYNC_CANCEL(this);
167  
            return false;
168  
        }
169  
170  
        void unlock()
171  
        {
172  
            HPX_ITT_SYNC_RELEASING(this);
173  
174  
            relinquish_lock();
175  
176  
            HPX_ITT_SYNC_RELEASED(this);
177  
            util::unregister_lock(this);
178  
        }
179  
180  
    private:
181  
        // returns whether the mutex has been acquired
182  
        bool acquire_lock()
183  
        {
184  
#if !defined( BOOST_SP_HAS_SYNC )
185  
            std::uint64_t r = BOOST_INTERLOCKED_EXCHANGE(&v_, 1);
186  
            BOOST_COMPILER_FENCE
187  
#else
188 0.5%
            std::uint64_t r = __sync_lock_test_and_set(&v_, 1);
189  
#endif
190  
            return r == 0;
191  
        }
192  
193  
        void relinquish_lock()
194  
        {
195  
#if !defined( BOOST_SP_HAS_SYNC )
196  
            BOOST_COMPILER_FENCE
197  
            *const_cast<std::uint64_t volatile*>(&v_) = 0;
198  
#else
199  
            __sync_lock_release(&v_);
200  
#endif
201  
        }
202  
    };
203  
}}}
204  
205  
#endif // HPX_B3A83B49_92E0_4150_A551_488F9F5E1113
206  
207  

Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.