1 /******************************************************************************
2  * Copyright (c) 2011, Duane Merrill.  All rights reserved.
3  * Copyright (c) 2011-2018, NVIDIA CORPORATION.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the NVIDIA CORPORATION nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  ******************************************************************************/
28 
29 /**
30  * \file
31  * Simple portable mutex
32  */
33 
34 
35 #pragma once
36 
37 #if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
38     #include <mutex>
39 #else
40     #if defined(_WIN32) || defined(_WIN64)
41         #include <intrin.h>
42 
43         #define WIN32_LEAN_AND_MEAN
44         #define NOMINMAX
45         #include <windows.h>
46         #undef WIN32_LEAN_AND_MEAN
47         #undef NOMINMAX
48 
49         /**
50          * Compiler read/write barrier
51          */
52         #pragma intrinsic(_ReadWriteBarrier)
53 
54     #endif
55 #endif
56 
57 #include "../util_namespace.cuh"
58 
59 
60 /// Optional outer namespace(s)
61 THRUST_CUB_NS_PREFIX
62 
63 /// CUB namespace
64 namespace cub {
65 
66 
67 /**
68  * Simple portable mutex
69  *   - Wraps std::mutex when compiled with C++11 or newer (supported on all platforms)
70  *   - Uses GNU/Windows spinlock mechanisms for pre C++11 (supported on x86/x64 when compiled with cl.exe or g++)
71  */
72 struct Mutex
73 {
74 #if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
75 
76     std::mutex mtx;
77 
Lockcub::Mutex78     void Lock()
79     {
80         mtx.lock();
81     }
82 
Unlockcub::Mutex83     void Unlock()
84     {
85         mtx.unlock();
86     }
87 
TryLockcub::Mutex88     void TryLock()
89     {
90         mtx.try_lock();
91     }
92 
93 #else       //__cplusplus > 199711L
94 
95     #if defined(_MSC_VER)
96 
97         // Microsoft VC++
98         typedef long Spinlock;
99 
100     #else
101 
102         // GNU g++
103         typedef int Spinlock;
104 
105         /**
106          * Compiler read/write barrier
107          */
108         __forceinline__ void _ReadWriteBarrier()
109         {
110             __sync_synchronize();
111         }
112 
113         /**
114          * Atomic exchange
115          */
116         __forceinline__ long _InterlockedExchange(volatile int * const Target, const int Value)
117         {
118             // NOTE: __sync_lock_test_and_set would be an acquire barrier, so we force a full barrier
119             _ReadWriteBarrier();
120             return __sync_lock_test_and_set(Target, Value);
121         }
122 
123         /**
124          * Pause instruction to prevent excess processor bus usage
125          */
126         __forceinline__ void YieldProcessor()
127         {
128         }
129 
130     #endif  // defined(_MSC_VER)
131 
132         /// Lock member
133         volatile Spinlock lock;
134 
135         /**
136          * Constructor
137          */
138         Mutex() : lock(0) {}
139 
140         /**
141          * Return when the specified spinlock has been acquired
142          */
143         __forceinline__ void Lock()
144         {
145             while (1)
146             {
147                 if (!_InterlockedExchange(&lock, 1)) return;
148                 while (lock) YieldProcessor();
149             }
150         }
151 
152 
153         /**
154          * Release the specified spinlock
155          */
156         __forceinline__ void Unlock()
157         {
158             _ReadWriteBarrier();
159             lock = 0;
160         }
161 
162 #endif      // __cplusplus > 199711L
163 
164 };
165 
166 
167 
168 
169 }               // CUB namespace
170 THRUST_CUB_NS_POSTFIX  // Optional outer namespace(s)
171 
172