blob: 78cf0ccc6271b81d195282f107a741112c90166f [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
2 * kmp_lock.h -- lock header file
Jim Cownie5e8470a2013-09-27 10:38:44 +00003 */
4
Jim Cownie5e8470a2013-09-27 10:38:44 +00005//===----------------------------------------------------------------------===//
6//
7// The LLVM Compiler Infrastructure
8//
9// This file is dual licensed under the MIT and the University of Illinois Open
10// Source Licenses. See LICENSE.txt for details.
11//
12//===----------------------------------------------------------------------===//
13
Jim Cownie5e8470a2013-09-27 10:38:44 +000014#ifndef KMP_LOCK_H
15#define KMP_LOCK_H
16
Jonathan Peyton30419822017-05-12 18:01:32 +000017#include <limits.h> // CHAR_BIT
18#include <stddef.h> // offsetof
Jim Cownie5e8470a2013-09-27 10:38:44 +000019
Jim Cownie5e8470a2013-09-27 10:38:44 +000020#include "kmp_debug.h"
Jonathan Peyton30419822017-05-12 18:01:32 +000021#include "kmp_os.h"
Jim Cownie5e8470a2013-09-27 10:38:44 +000022
23#ifdef __cplusplus
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +000024#include <atomic>
25
Jim Cownie5e8470a2013-09-27 10:38:44 +000026extern "C" {
27#endif // __cplusplus
28
29// ----------------------------------------------------------------------------
30// Have to copy these definitions from kmp.h because kmp.h cannot be included
31// due to circular dependencies. Will undef these at end of file.
32
Jonathan Peyton30419822017-05-12 18:01:32 +000033#define KMP_PAD(type, sz) \
34 (sizeof(type) + (sz - ((sizeof(type) - 1) % (sz)) - 1))
Jim Cownie5e8470a2013-09-27 10:38:44 +000035#define KMP_GTID_DNE (-2)
36
37// Forward declaration of ident and ident_t
38
39struct ident;
40typedef struct ident ident_t;
41
42// End of copied code.
43// ----------------------------------------------------------------------------
44
Jim Cownie5e8470a2013-09-27 10:38:44 +000045// We need to know the size of the area we can assume that the compiler(s)
46// allocated for obects of type omp_lock_t and omp_nest_lock_t. The Intel
47// compiler always allocates a pointer-sized area, as does visual studio.
48//
49// gcc however, only allocates 4 bytes for regular locks, even on 64-bit
50// intel archs. It allocates at least 8 bytes for nested lock (more on
51// recent versions), but we are bounded by the pointer-sized chunks that
52// the Intel compiler allocates.
Jim Cownie5e8470a2013-09-27 10:38:44 +000053
54#if KMP_OS_LINUX && defined(KMP_GOMP_COMPAT)
Jonathan Peyton30419822017-05-12 18:01:32 +000055#define OMP_LOCK_T_SIZE sizeof(int)
56#define OMP_NEST_LOCK_T_SIZE sizeof(void *)
Jim Cownie5e8470a2013-09-27 10:38:44 +000057#else
Jonathan Peyton30419822017-05-12 18:01:32 +000058#define OMP_LOCK_T_SIZE sizeof(void *)
59#define OMP_NEST_LOCK_T_SIZE sizeof(void *)
Jim Cownie5e8470a2013-09-27 10:38:44 +000060#endif
61
Jim Cownie5e8470a2013-09-27 10:38:44 +000062// The Intel compiler allocates a 32-byte chunk for a critical section.
63// Both gcc and visual studio only allocate enough space for a pointer.
64// Sometimes we know that the space was allocated by the Intel compiler.
Jonathan Peyton30419822017-05-12 18:01:32 +000065#define OMP_CRITICAL_SIZE sizeof(void *)
66#define INTEL_CRITICAL_SIZE 32
Jim Cownie5e8470a2013-09-27 10:38:44 +000067
Jim Cownie5e8470a2013-09-27 10:38:44 +000068// lock flags
Jim Cownie5e8470a2013-09-27 10:38:44 +000069typedef kmp_uint32 kmp_lock_flags_t;
70
71#define kmp_lf_critical_section 1
72
Jim Cownie5e8470a2013-09-27 10:38:44 +000073// When a lock table is used, the indices are of kmp_lock_index_t
Jim Cownie5e8470a2013-09-27 10:38:44 +000074typedef kmp_uint32 kmp_lock_index_t;
75
Jim Cownie5e8470a2013-09-27 10:38:44 +000076// When memory allocated for locks are on the lock pool (free list),
77// it is treated as structs of this type.
Jim Cownie5e8470a2013-09-27 10:38:44 +000078struct kmp_lock_pool {
Jonathan Peyton30419822017-05-12 18:01:32 +000079 union kmp_user_lock *next;
80 kmp_lock_index_t index;
Jim Cownie5e8470a2013-09-27 10:38:44 +000081};
82
83typedef struct kmp_lock_pool kmp_lock_pool_t;
84
Jonathan Peyton30419822017-05-12 18:01:32 +000085extern void __kmp_validate_locks(void);
Jim Cownie5e8470a2013-09-27 10:38:44 +000086
87// ----------------------------------------------------------------------------
Jim Cownie5e8470a2013-09-27 10:38:44 +000088// There are 5 lock implementations:
Jim Cownie5e8470a2013-09-27 10:38:44 +000089// 1. Test and set locks.
Jonathan Peyton8c432f22018-01-04 22:56:47 +000090// 2. futex locks (Linux* OS on x86 and
91// Intel(R) Many Integrated Core Architecture)
Jim Cownie5e8470a2013-09-27 10:38:44 +000092// 3. Ticket (Lamport bakery) locks.
93// 4. Queuing locks (with separate spin fields).
94// 5. DRPA (Dynamically Reconfigurable Distributed Polling Area) locks
95//
96// and 3 lock purposes:
Jonathan Peyton30419822017-05-12 18:01:32 +000097// 1. Bootstrap locks -- Used for a few locks available at library
98// startup-shutdown time.
Jim Cownie5e8470a2013-09-27 10:38:44 +000099// These do not require non-negative global thread ID's.
100// 2. Internal RTL locks -- Used everywhere else in the RTL
101// 3. User locks (includes critical sections)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000102// ----------------------------------------------------------------------------
103
Jim Cownie5e8470a2013-09-27 10:38:44 +0000104// ============================================================================
105// Lock implementations.
Jonathan Peyton30419822017-05-12 18:01:32 +0000106//
Jim Cownie5e8470a2013-09-27 10:38:44 +0000107// Test and set locks.
108//
109// Non-nested test and set locks differ from the other lock kinds (except
110// futex) in that we use the memory allocated by the compiler for the lock,
111// rather than a pointer to it.
112//
113// On lin32, lin_32e, and win_32, the space allocated may be as small as 4
114// bytes, so we have to use a lock table for nested locks, and avoid accessing
115// the depth_locked field for non-nested locks.
116//
Jonathan Peyton30419822017-05-12 18:01:32 +0000117// Information normally available to the tools, such as lock location, lock
118// usage (normal lock vs. critical section), etc. is not available with test and
119// set locks.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000120// ----------------------------------------------------------------------------
121
122struct kmp_base_tas_lock {
Jonathan Peytonccfed2e2017-06-06 20:24:41 +0000123 // KMP_LOCK_FREE(tas) => unlocked; locked: (gtid+1) of owning thread
124 volatile kmp_int32 poll;
Jonathan Peyton30419822017-05-12 18:01:32 +0000125 kmp_int32 depth_locked; // depth locked, for nested locks only
Jim Cownie5e8470a2013-09-27 10:38:44 +0000126};
127
128typedef struct kmp_base_tas_lock kmp_base_tas_lock_t;
129
130union kmp_tas_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000131 kmp_base_tas_lock_t lk;
132 kmp_lock_pool_t pool; // make certain struct is large enough
133 double lk_align; // use worst case alignment; no cache line padding
Jim Cownie5e8470a2013-09-27 10:38:44 +0000134};
135
136typedef union kmp_tas_lock kmp_tas_lock_t;
137
Jim Cownie5e8470a2013-09-27 10:38:44 +0000138// Static initializer for test and set lock variables. Usage:
139// kmp_tas_lock_t xlock = KMP_TAS_LOCK_INITIALIZER( xlock );
Jonathan Peyton30419822017-05-12 18:01:32 +0000140#define KMP_TAS_LOCK_INITIALIZER(lock) \
141 { \
Jonathan Peytonccfed2e2017-06-06 20:24:41 +0000142 { KMP_LOCK_FREE(tas), 0 } \
Jonathan Peyton30419822017-05-12 18:01:32 +0000143 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000144
Jonathan Peyton30419822017-05-12 18:01:32 +0000145extern int __kmp_acquire_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
146extern int __kmp_test_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
147extern int __kmp_release_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
148extern void __kmp_init_tas_lock(kmp_tas_lock_t *lck);
149extern void __kmp_destroy_tas_lock(kmp_tas_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000150
Jonathan Peyton30419822017-05-12 18:01:32 +0000151extern int __kmp_acquire_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
152extern int __kmp_test_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
153extern int __kmp_release_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
154extern void __kmp_init_nested_tas_lock(kmp_tas_lock_t *lck);
155extern void __kmp_destroy_nested_tas_lock(kmp_tas_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000156
Jonathan Peyton30419822017-05-12 18:01:32 +0000157#define KMP_LOCK_RELEASED 1
158#define KMP_LOCK_STILL_HELD 0
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000159#define KMP_LOCK_ACQUIRED_FIRST 1
Jonathan Peyton30419822017-05-12 18:01:32 +0000160#define KMP_LOCK_ACQUIRED_NEXT 0
Jonathan Peytonbff8ded2018-01-10 18:24:09 +0000161#ifndef KMP_USE_FUTEX
Jonathan Peyton30419822017-05-12 18:01:32 +0000162#define KMP_USE_FUTEX \
163 (KMP_OS_LINUX && !KMP_OS_CNK && \
164 (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64))
Jonathan Peytonbff8ded2018-01-10 18:24:09 +0000165#endif
Jonathan Peyton9d2412c2016-06-22 16:35:12 +0000166#if KMP_USE_FUTEX
Jim Cownie5e8470a2013-09-27 10:38:44 +0000167
168// ----------------------------------------------------------------------------
169// futex locks. futex locks are only available on Linux* OS.
170//
171// Like non-nested test and set lock, non-nested futex locks use the memory
172// allocated by the compiler for the lock, rather than a pointer to it.
173//
Jonathan Peyton30419822017-05-12 18:01:32 +0000174// Information normally available to the tools, such as lock location, lock
175// usage (normal lock vs. critical section), etc. is not available with test and
176// set locks. With non-nested futex locks, the lock owner is not even available.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000177// ----------------------------------------------------------------------------
178
179struct kmp_base_futex_lock {
Jonathan Peytonccfed2e2017-06-06 20:24:41 +0000180 volatile kmp_int32 poll; // KMP_LOCK_FREE(futex) => unlocked
Jonathan Peyton30419822017-05-12 18:01:32 +0000181 // 2*(gtid+1) of owning thread, 0 if unlocked
182 // locked: (gtid+1) of owning thread
183 kmp_int32 depth_locked; // depth locked, for nested locks only
Jim Cownie5e8470a2013-09-27 10:38:44 +0000184};
185
186typedef struct kmp_base_futex_lock kmp_base_futex_lock_t;
187
188union kmp_futex_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000189 kmp_base_futex_lock_t lk;
190 kmp_lock_pool_t pool; // make certain struct is large enough
191 double lk_align; // use worst case alignment
192 // no cache line padding
Jim Cownie5e8470a2013-09-27 10:38:44 +0000193};
194
195typedef union kmp_futex_lock kmp_futex_lock_t;
196
Jim Cownie5e8470a2013-09-27 10:38:44 +0000197// Static initializer for futex lock variables. Usage:
198// kmp_futex_lock_t xlock = KMP_FUTEX_LOCK_INITIALIZER( xlock );
Jonathan Peyton30419822017-05-12 18:01:32 +0000199#define KMP_FUTEX_LOCK_INITIALIZER(lock) \
200 { \
Jonathan Peytonccfed2e2017-06-06 20:24:41 +0000201 { KMP_LOCK_FREE(futex), 0 } \
Jonathan Peyton30419822017-05-12 18:01:32 +0000202 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000203
Jonathan Peyton30419822017-05-12 18:01:32 +0000204extern int __kmp_acquire_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
205extern int __kmp_test_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
206extern int __kmp_release_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
207extern void __kmp_init_futex_lock(kmp_futex_lock_t *lck);
208extern void __kmp_destroy_futex_lock(kmp_futex_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000209
Jonathan Peyton30419822017-05-12 18:01:32 +0000210extern int __kmp_acquire_nested_futex_lock(kmp_futex_lock_t *lck,
211 kmp_int32 gtid);
212extern int __kmp_test_nested_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
213extern int __kmp_release_nested_futex_lock(kmp_futex_lock_t *lck,
214 kmp_int32 gtid);
215extern void __kmp_init_nested_futex_lock(kmp_futex_lock_t *lck);
216extern void __kmp_destroy_nested_futex_lock(kmp_futex_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000217
Jonathan Peyton9d2412c2016-06-22 16:35:12 +0000218#endif // KMP_USE_FUTEX
Jim Cownie5e8470a2013-09-27 10:38:44 +0000219
Jim Cownie5e8470a2013-09-27 10:38:44 +0000220// ----------------------------------------------------------------------------
221// Ticket locks.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000222
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +0000223#ifdef __cplusplus
224
Hans Wennborg5b89fbc2016-06-09 15:54:43 +0000225#ifdef _MSC_VER
Jonathan Peyton30419822017-05-12 18:01:32 +0000226// MSVC won't allow use of std::atomic<> in a union since it has non-trivial
227// copy constructor.
Hans Wennborg5b89fbc2016-06-09 15:54:43 +0000228
229struct kmp_base_ticket_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000230 // `initialized' must be the first entry in the lock data structure!
231 std::atomic_bool initialized;
232 volatile union kmp_ticket_lock *self; // points to the lock union
233 ident_t const *location; // Source code location of omp_init_lock().
234 std::atomic_uint
235 next_ticket; // ticket number to give to next thread which acquires
236 std::atomic_uint now_serving; // ticket number for thread which holds the lock
237 std::atomic_int owner_id; // (gtid+1) of owning thread, 0 if unlocked
238 std::atomic_int depth_locked; // depth locked, for nested locks only
239 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
Hans Wennborg5b89fbc2016-06-09 15:54:43 +0000240};
241#else
Jim Cownie5e8470a2013-09-27 10:38:44 +0000242struct kmp_base_ticket_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000243 // `initialized' must be the first entry in the lock data structure!
244 std::atomic<bool> initialized;
245 volatile union kmp_ticket_lock *self; // points to the lock union
246 ident_t const *location; // Source code location of omp_init_lock().
247 std::atomic<unsigned>
248 next_ticket; // ticket number to give to next thread which acquires
249 std::atomic<unsigned>
250 now_serving; // ticket number for thread which holds the lock
251 std::atomic<int> owner_id; // (gtid+1) of owning thread, 0 if unlocked
252 std::atomic<int> depth_locked; // depth locked, for nested locks only
253 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
Jim Cownie5e8470a2013-09-27 10:38:44 +0000254};
Hans Wennborg5b89fbc2016-06-09 15:54:43 +0000255#endif
Jim Cownie5e8470a2013-09-27 10:38:44 +0000256
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +0000257#else // __cplusplus
258
259struct kmp_base_ticket_lock;
260
261#endif // !__cplusplus
262
Jim Cownie5e8470a2013-09-27 10:38:44 +0000263typedef struct kmp_base_ticket_lock kmp_base_ticket_lock_t;
264
265union KMP_ALIGN_CACHE kmp_ticket_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000266 kmp_base_ticket_lock_t
267 lk; // This field must be first to allow static initializing.
268 kmp_lock_pool_t pool;
269 double lk_align; // use worst case alignment
270 char lk_pad[KMP_PAD(kmp_base_ticket_lock_t, CACHE_LINE)];
Jim Cownie5e8470a2013-09-27 10:38:44 +0000271};
272
273typedef union kmp_ticket_lock kmp_ticket_lock_t;
274
Jim Cownie5e8470a2013-09-27 10:38:44 +0000275// Static initializer for simple ticket lock variables. Usage:
276// kmp_ticket_lock_t xlock = KMP_TICKET_LOCK_INITIALIZER( xlock );
277// Note the macro argument. It is important to make var properly initialized.
Jonathan Peyton30419822017-05-12 18:01:32 +0000278#define KMP_TICKET_LOCK_INITIALIZER(lock) \
279 { \
280 { \
281 ATOMIC_VAR_INIT(true) \
282 , &(lock), NULL, ATOMIC_VAR_INIT(0U), ATOMIC_VAR_INIT(0U), \
283 ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(-1) \
284 } \
285 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000286
Jonathan Peyton30419822017-05-12 18:01:32 +0000287extern int __kmp_acquire_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid);
288extern int __kmp_test_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid);
289extern int __kmp_test_ticket_lock_with_cheks(kmp_ticket_lock_t *lck,
290 kmp_int32 gtid);
291extern int __kmp_release_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid);
292extern void __kmp_init_ticket_lock(kmp_ticket_lock_t *lck);
293extern void __kmp_destroy_ticket_lock(kmp_ticket_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000294
Jonathan Peyton30419822017-05-12 18:01:32 +0000295extern int __kmp_acquire_nested_ticket_lock(kmp_ticket_lock_t *lck,
296 kmp_int32 gtid);
297extern int __kmp_test_nested_ticket_lock(kmp_ticket_lock_t *lck,
298 kmp_int32 gtid);
299extern int __kmp_release_nested_ticket_lock(kmp_ticket_lock_t *lck,
300 kmp_int32 gtid);
301extern void __kmp_init_nested_ticket_lock(kmp_ticket_lock_t *lck);
302extern void __kmp_destroy_nested_ticket_lock(kmp_ticket_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000303
304// ----------------------------------------------------------------------------
305// Queuing locks.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000306
307#if KMP_USE_ADAPTIVE_LOCKS
308
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000309struct kmp_adaptive_lock_info;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000310
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000311typedef struct kmp_adaptive_lock_info kmp_adaptive_lock_info_t;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000312
313#if KMP_DEBUG_ADAPTIVE_LOCKS
314
315struct kmp_adaptive_lock_statistics {
Jonathan Peyton30419822017-05-12 18:01:32 +0000316 /* So we can get stats from locks that haven't been destroyed. */
317 kmp_adaptive_lock_info_t *next;
318 kmp_adaptive_lock_info_t *prev;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000319
Jonathan Peyton30419822017-05-12 18:01:32 +0000320 /* Other statistics */
321 kmp_uint32 successfulSpeculations;
322 kmp_uint32 hardFailedSpeculations;
323 kmp_uint32 softFailedSpeculations;
324 kmp_uint32 nonSpeculativeAcquires;
325 kmp_uint32 nonSpeculativeAcquireAttempts;
326 kmp_uint32 lemmingYields;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000327};
328
329typedef struct kmp_adaptive_lock_statistics kmp_adaptive_lock_statistics_t;
330
331extern void __kmp_print_speculative_stats();
332extern void __kmp_init_speculative_stats();
333
334#endif // KMP_DEBUG_ADAPTIVE_LOCKS
335
Jonathan Peyton30419822017-05-12 18:01:32 +0000336struct kmp_adaptive_lock_info {
337 /* Values used for adaptivity.
338 Although these are accessed from multiple threads we don't access them
339 atomically, because if we miss updates it probably doesn't matter much. (It
340 just affects our decision about whether to try speculation on the lock). */
341 kmp_uint32 volatile badness;
342 kmp_uint32 volatile acquire_attempts;
343 /* Parameters of the lock. */
344 kmp_uint32 max_badness;
345 kmp_uint32 max_soft_retries;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000346
347#if KMP_DEBUG_ADAPTIVE_LOCKS
Jonathan Peyton30419822017-05-12 18:01:32 +0000348 kmp_adaptive_lock_statistics_t volatile stats;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000349#endif
350};
351
352#endif // KMP_USE_ADAPTIVE_LOCKS
353
Jim Cownie5e8470a2013-09-27 10:38:44 +0000354struct kmp_base_queuing_lock {
355
Jonathan Peyton30419822017-05-12 18:01:32 +0000356 // `initialized' must be the first entry in the lock data structure!
357 volatile union kmp_queuing_lock
358 *initialized; // Points to the lock union if in initialized state.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000359
Jonathan Peyton30419822017-05-12 18:01:32 +0000360 ident_t const *location; // Source code location of omp_init_lock().
Jim Cownie5e8470a2013-09-27 10:38:44 +0000361
Jonathan Peyton30419822017-05-12 18:01:32 +0000362 KMP_ALIGN(8) // tail_id must be 8-byte aligned!
Jim Cownie5e8470a2013-09-27 10:38:44 +0000363
Jonathan Peyton30419822017-05-12 18:01:32 +0000364 volatile kmp_int32
365 tail_id; // (gtid+1) of thread at tail of wait queue, 0 if empty
366 // Must be no padding here since head/tail used in 8-byte CAS
367 volatile kmp_int32
368 head_id; // (gtid+1) of thread at head of wait queue, 0 if empty
369 // Decl order assumes little endian
370 // bakery-style lock
371 volatile kmp_uint32
372 next_ticket; // ticket number to give to next thread which acquires
373 volatile kmp_uint32
374 now_serving; // ticket number for thread which holds the lock
375 volatile kmp_int32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
376 kmp_int32 depth_locked; // depth locked, for nested locks only
Jim Cownie5e8470a2013-09-27 10:38:44 +0000377
Jonathan Peyton30419822017-05-12 18:01:32 +0000378 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
Jim Cownie5e8470a2013-09-27 10:38:44 +0000379};
380
381typedef struct kmp_base_queuing_lock kmp_base_queuing_lock_t;
382
Jonathan Peyton30419822017-05-12 18:01:32 +0000383KMP_BUILD_ASSERT(offsetof(kmp_base_queuing_lock_t, tail_id) % 8 == 0);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000384
385union KMP_ALIGN_CACHE kmp_queuing_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000386 kmp_base_queuing_lock_t
387 lk; // This field must be first to allow static initializing.
388 kmp_lock_pool_t pool;
389 double lk_align; // use worst case alignment
390 char lk_pad[KMP_PAD(kmp_base_queuing_lock_t, CACHE_LINE)];
Jim Cownie5e8470a2013-09-27 10:38:44 +0000391};
392
393typedef union kmp_queuing_lock kmp_queuing_lock_t;
394
Jonathan Peyton30419822017-05-12 18:01:32 +0000395extern int __kmp_acquire_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid);
396extern int __kmp_test_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid);
397extern int __kmp_release_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid);
398extern void __kmp_init_queuing_lock(kmp_queuing_lock_t *lck);
399extern void __kmp_destroy_queuing_lock(kmp_queuing_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000400
Jonathan Peyton30419822017-05-12 18:01:32 +0000401extern int __kmp_acquire_nested_queuing_lock(kmp_queuing_lock_t *lck,
402 kmp_int32 gtid);
403extern int __kmp_test_nested_queuing_lock(kmp_queuing_lock_t *lck,
404 kmp_int32 gtid);
405extern int __kmp_release_nested_queuing_lock(kmp_queuing_lock_t *lck,
406 kmp_int32 gtid);
407extern void __kmp_init_nested_queuing_lock(kmp_queuing_lock_t *lck);
408extern void __kmp_destroy_nested_queuing_lock(kmp_queuing_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000409
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000410#if KMP_USE_ADAPTIVE_LOCKS
411
412// ----------------------------------------------------------------------------
413// Adaptive locks.
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000414struct kmp_base_adaptive_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000415 kmp_base_queuing_lock qlk;
416 KMP_ALIGN(CACHE_LINE)
417 kmp_adaptive_lock_info_t
418 adaptive; // Information for the speculative adaptive lock
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000419};
420
421typedef struct kmp_base_adaptive_lock kmp_base_adaptive_lock_t;
422
423union KMP_ALIGN_CACHE kmp_adaptive_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000424 kmp_base_adaptive_lock_t lk;
425 kmp_lock_pool_t pool;
426 double lk_align;
427 char lk_pad[KMP_PAD(kmp_base_adaptive_lock_t, CACHE_LINE)];
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000428};
429typedef union kmp_adaptive_lock kmp_adaptive_lock_t;
430
Jonathan Peyton30419822017-05-12 18:01:32 +0000431#define GET_QLK_PTR(l) ((kmp_queuing_lock_t *)&(l)->lk.qlk)
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000432
433#endif // KMP_USE_ADAPTIVE_LOCKS
Jim Cownie5e8470a2013-09-27 10:38:44 +0000434
435// ----------------------------------------------------------------------------
436// DRDPA ticket locks.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000437struct kmp_base_drdpa_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000438 // All of the fields on the first cache line are only written when
439 // initializing or reconfiguring the lock. These are relatively rare
440 // operations, so data from the first cache line will usually stay resident in
441 // the cache of each thread trying to acquire the lock.
442 //
443 // initialized must be the first entry in the lock data structure!
444 KMP_ALIGN_CACHE
Jim Cownie5e8470a2013-09-27 10:38:44 +0000445
Jonathan Peyton30419822017-05-12 18:01:32 +0000446 volatile union kmp_drdpa_lock
447 *initialized; // points to the lock union if in initialized state
448 ident_t const *location; // Source code location of omp_init_lock().
449 volatile struct kmp_lock_poll { kmp_uint64 poll; } * volatile polls;
450 volatile kmp_uint64 mask; // is 2**num_polls-1 for mod op
451 kmp_uint64 cleanup_ticket; // thread with cleanup ticket
452 volatile struct kmp_lock_poll *old_polls; // will deallocate old_polls
453 kmp_uint32 num_polls; // must be power of 2
Jim Cownie5e8470a2013-09-27 10:38:44 +0000454
Jonathan Peyton30419822017-05-12 18:01:32 +0000455 // next_ticket it needs to exist in a separate cache line, as it is
456 // invalidated every time a thread takes a new ticket.
457 KMP_ALIGN_CACHE
Jim Cownie5e8470a2013-09-27 10:38:44 +0000458
Jonathan Peyton30419822017-05-12 18:01:32 +0000459 volatile kmp_uint64 next_ticket;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000460
Jonathan Peyton30419822017-05-12 18:01:32 +0000461 // now_serving is used to store our ticket value while we hold the lock. It
462 // has a slightly different meaning in the DRDPA ticket locks (where it is
463 // written by the acquiring thread) than it does in the simple ticket locks
464 // (where it is written by the releasing thread).
465 //
466 // Since now_serving is only read an written in the critical section,
467 // it is non-volatile, but it needs to exist on a separate cache line,
468 // as it is invalidated at every lock acquire.
469 //
470 // Likewise, the vars used for nested locks (owner_id and depth_locked) are
471 // only written by the thread owning the lock, so they are put in this cache
472 // line. owner_id is read by other threads, so it must be declared volatile.
473 KMP_ALIGN_CACHE
474 kmp_uint64 now_serving; // doesn't have to be volatile
475 volatile kmp_uint32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
476 kmp_int32 depth_locked; // depth locked
477 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
Jim Cownie5e8470a2013-09-27 10:38:44 +0000478};
479
480typedef struct kmp_base_drdpa_lock kmp_base_drdpa_lock_t;
481
482union KMP_ALIGN_CACHE kmp_drdpa_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000483 kmp_base_drdpa_lock_t
484 lk; // This field must be first to allow static initializing. */
485 kmp_lock_pool_t pool;
486 double lk_align; // use worst case alignment
487 char lk_pad[KMP_PAD(kmp_base_drdpa_lock_t, CACHE_LINE)];
Jim Cownie5e8470a2013-09-27 10:38:44 +0000488};
489
490typedef union kmp_drdpa_lock kmp_drdpa_lock_t;
491
Jonathan Peyton30419822017-05-12 18:01:32 +0000492extern int __kmp_acquire_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
493extern int __kmp_test_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
494extern int __kmp_release_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
495extern void __kmp_init_drdpa_lock(kmp_drdpa_lock_t *lck);
496extern void __kmp_destroy_drdpa_lock(kmp_drdpa_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000497
Jonathan Peyton30419822017-05-12 18:01:32 +0000498extern int __kmp_acquire_nested_drdpa_lock(kmp_drdpa_lock_t *lck,
499 kmp_int32 gtid);
500extern int __kmp_test_nested_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
501extern int __kmp_release_nested_drdpa_lock(kmp_drdpa_lock_t *lck,
502 kmp_int32 gtid);
503extern void __kmp_init_nested_drdpa_lock(kmp_drdpa_lock_t *lck);
504extern void __kmp_destroy_nested_drdpa_lock(kmp_drdpa_lock_t *lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000505
506// ============================================================================
507// Lock purposes.
508// ============================================================================
509
Jim Cownie5e8470a2013-09-27 10:38:44 +0000510// Bootstrap locks.
Jonathan Peyton30419822017-05-12 18:01:32 +0000511//
Jim Cownie5e8470a2013-09-27 10:38:44 +0000512// Bootstrap locks -- very few locks used at library initialization time.
513// Bootstrap locks are currently implemented as ticket locks.
514// They could also be implemented as test and set lock, but cannot be
515// implemented with other lock kinds as they require gtids which are not
516// available at initialization time.
517
518typedef kmp_ticket_lock_t kmp_bootstrap_lock_t;
519
Jonathan Peyton30419822017-05-12 18:01:32 +0000520#define KMP_BOOTSTRAP_LOCK_INITIALIZER(lock) KMP_TICKET_LOCK_INITIALIZER((lock))
Jim Cownie5e8470a2013-09-27 10:38:44 +0000521
Jonathan Peyton30419822017-05-12 18:01:32 +0000522static inline int __kmp_acquire_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
523 return __kmp_acquire_ticket_lock(lck, KMP_GTID_DNE);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000524}
525
Jonathan Peyton30419822017-05-12 18:01:32 +0000526static inline int __kmp_test_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
527 return __kmp_test_ticket_lock(lck, KMP_GTID_DNE);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000528}
529
Jonathan Peyton30419822017-05-12 18:01:32 +0000530static inline void __kmp_release_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
531 __kmp_release_ticket_lock(lck, KMP_GTID_DNE);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000532}
533
Jonathan Peyton30419822017-05-12 18:01:32 +0000534static inline void __kmp_init_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
535 __kmp_init_ticket_lock(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000536}
537
Jonathan Peyton30419822017-05-12 18:01:32 +0000538static inline void __kmp_destroy_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
539 __kmp_destroy_ticket_lock(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000540}
541
Jim Cownie5e8470a2013-09-27 10:38:44 +0000542// Internal RTL locks.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000543//
544// Internal RTL locks are also implemented as ticket locks, for now.
545//
546// FIXME - We should go through and figure out which lock kind works best for
Jim Cownie3051f972014-08-07 10:12:54 +0000547// each internal lock, and use the type declaration and function calls for
Jim Cownie5e8470a2013-09-27 10:38:44 +0000548// that explicit lock kind (and get rid of this section).
Jim Cownie5e8470a2013-09-27 10:38:44 +0000549
550typedef kmp_ticket_lock_t kmp_lock_t;
551
Jonathan Peyton30419822017-05-12 18:01:32 +0000552static inline int __kmp_acquire_lock(kmp_lock_t *lck, kmp_int32 gtid) {
553 return __kmp_acquire_ticket_lock(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000554}
555
Jonathan Peyton30419822017-05-12 18:01:32 +0000556static inline int __kmp_test_lock(kmp_lock_t *lck, kmp_int32 gtid) {
557 return __kmp_test_ticket_lock(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000558}
559
Jonathan Peyton30419822017-05-12 18:01:32 +0000560static inline void __kmp_release_lock(kmp_lock_t *lck, kmp_int32 gtid) {
561 __kmp_release_ticket_lock(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000562}
563
Jonathan Peyton30419822017-05-12 18:01:32 +0000564static inline void __kmp_init_lock(kmp_lock_t *lck) {
565 __kmp_init_ticket_lock(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000566}
567
Jonathan Peyton30419822017-05-12 18:01:32 +0000568static inline void __kmp_destroy_lock(kmp_lock_t *lck) {
569 __kmp_destroy_ticket_lock(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000570}
571
Jim Cownie5e8470a2013-09-27 10:38:44 +0000572// User locks.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000573//
Jonathan Peyton30419822017-05-12 18:01:32 +0000574// Do not allocate objects of type union kmp_user_lock!!! This will waste space
575// unless __kmp_user_lock_kind == lk_drdpa. Instead, check the value of
576// __kmp_user_lock_kind and allocate objects of the type of the appropriate
577// union member, and cast their addresses to kmp_user_lock_p.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000578
579enum kmp_lock_kind {
Jonathan Peyton30419822017-05-12 18:01:32 +0000580 lk_default = 0,
581 lk_tas,
Jonathan Peyton9d2412c2016-06-22 16:35:12 +0000582#if KMP_USE_FUTEX
Jonathan Peyton30419822017-05-12 18:01:32 +0000583 lk_futex,
Jim Cownie5e8470a2013-09-27 10:38:44 +0000584#endif
Jonathan Peytondae13d82015-12-11 21:57:06 +0000585#if KMP_USE_DYNAMIC_LOCK && KMP_USE_TSX
Jonathan Peyton30419822017-05-12 18:01:32 +0000586 lk_hle,
587 lk_rtm,
Jonathan Peytondae13d82015-12-11 21:57:06 +0000588#endif
Jonathan Peyton30419822017-05-12 18:01:32 +0000589 lk_ticket,
590 lk_queuing,
591 lk_drdpa,
Jim Cownie5e8470a2013-09-27 10:38:44 +0000592#if KMP_USE_ADAPTIVE_LOCKS
Jonathan Peyton30419822017-05-12 18:01:32 +0000593 lk_adaptive
Jim Cownie5e8470a2013-09-27 10:38:44 +0000594#endif // KMP_USE_ADAPTIVE_LOCKS
595};
596
597typedef enum kmp_lock_kind kmp_lock_kind_t;
598
599extern kmp_lock_kind_t __kmp_user_lock_kind;
600
601union kmp_user_lock {
Jonathan Peyton30419822017-05-12 18:01:32 +0000602 kmp_tas_lock_t tas;
Jonathan Peyton9d2412c2016-06-22 16:35:12 +0000603#if KMP_USE_FUTEX
Jonathan Peyton30419822017-05-12 18:01:32 +0000604 kmp_futex_lock_t futex;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000605#endif
Jonathan Peyton30419822017-05-12 18:01:32 +0000606 kmp_ticket_lock_t ticket;
607 kmp_queuing_lock_t queuing;
608 kmp_drdpa_lock_t drdpa;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000609#if KMP_USE_ADAPTIVE_LOCKS
Jonathan Peyton30419822017-05-12 18:01:32 +0000610 kmp_adaptive_lock_t adaptive;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000611#endif // KMP_USE_ADAPTIVE_LOCKS
Jonathan Peyton30419822017-05-12 18:01:32 +0000612 kmp_lock_pool_t pool;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000613};
614
615typedef union kmp_user_lock *kmp_user_lock_p;
616
Jonathan Peyton30419822017-05-12 18:01:32 +0000617#if !KMP_USE_DYNAMIC_LOCK
Andrey Churbanov5c56fb52015-02-20 18:05:17 +0000618
Jim Cownie5e8470a2013-09-27 10:38:44 +0000619extern size_t __kmp_base_user_lock_size;
620extern size_t __kmp_user_lock_size;
621
Jonathan Peyton30419822017-05-12 18:01:32 +0000622extern kmp_int32 (*__kmp_get_user_lock_owner_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000623
Jonathan Peyton30419822017-05-12 18:01:32 +0000624static inline kmp_int32 __kmp_get_user_lock_owner(kmp_user_lock_p lck) {
625 KMP_DEBUG_ASSERT(__kmp_get_user_lock_owner_ != NULL);
626 return (*__kmp_get_user_lock_owner_)(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000627}
628
Jonathan Peyton30419822017-05-12 18:01:32 +0000629extern int (*__kmp_acquire_user_lock_with_checks_)(kmp_user_lock_p lck,
630 kmp_int32 gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000631
Jonathan Peyton30419822017-05-12 18:01:32 +0000632#if KMP_OS_LINUX && \
633 (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000634
Jonathan Peyton30419822017-05-12 18:01:32 +0000635#define __kmp_acquire_user_lock_with_checks(lck, gtid) \
636 if (__kmp_user_lock_kind == lk_tas) { \
637 if (__kmp_env_consistency_check) { \
638 char const *const func = "omp_set_lock"; \
639 if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) && \
640 lck->tas.lk.depth_locked != -1) { \
641 KMP_FATAL(LockNestableUsedAsSimple, func); \
642 } \
643 if ((gtid >= 0) && (lck->tas.lk.poll - 1 == gtid)) { \
644 KMP_FATAL(LockIsAlreadyOwned, func); \
645 } \
646 } \
647 if ((lck->tas.lk.poll != 0) || \
648 (!KMP_COMPARE_AND_STORE_ACQ32(&(lck->tas.lk.poll), 0, gtid + 1))) { \
649 kmp_uint32 spins; \
650 KMP_FSYNC_PREPARE(lck); \
651 KMP_INIT_YIELD(spins); \
652 if (TCR_4(__kmp_nth) > \
653 (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) { \
654 KMP_YIELD(TRUE); \
655 } else { \
656 KMP_YIELD_SPIN(spins); \
657 } \
658 while ( \
659 (lck->tas.lk.poll != 0) || \
660 (!KMP_COMPARE_AND_STORE_ACQ32(&(lck->tas.lk.poll), 0, gtid + 1))) { \
661 if (TCR_4(__kmp_nth) > \
662 (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) { \
663 KMP_YIELD(TRUE); \
664 } else { \
665 KMP_YIELD_SPIN(spins); \
666 } \
667 } \
668 } \
669 KMP_FSYNC_ACQUIRED(lck); \
670 } else { \
671 KMP_DEBUG_ASSERT(__kmp_acquire_user_lock_with_checks_ != NULL); \
672 (*__kmp_acquire_user_lock_with_checks_)(lck, gtid); \
673 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000674
675#else
Jonathan Peyton30419822017-05-12 18:01:32 +0000676static inline int __kmp_acquire_user_lock_with_checks(kmp_user_lock_p lck,
677 kmp_int32 gtid) {
678 KMP_DEBUG_ASSERT(__kmp_acquire_user_lock_with_checks_ != NULL);
679 return (*__kmp_acquire_user_lock_with_checks_)(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000680}
681#endif
682
Jonathan Peyton30419822017-05-12 18:01:32 +0000683extern int (*__kmp_test_user_lock_with_checks_)(kmp_user_lock_p lck,
684 kmp_int32 gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000685
Jonathan Peyton30419822017-05-12 18:01:32 +0000686#if KMP_OS_LINUX && \
687 (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000688
Jonathan Peyton30419822017-05-12 18:01:32 +0000689#include "kmp_i18n.h" /* AC: KMP_FATAL definition */
690extern int __kmp_env_consistency_check; /* AC: copy from kmp.h here */
691static inline int __kmp_test_user_lock_with_checks(kmp_user_lock_p lck,
692 kmp_int32 gtid) {
693 if (__kmp_user_lock_kind == lk_tas) {
694 if (__kmp_env_consistency_check) {
695 char const *const func = "omp_test_lock";
696 if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) &&
697 lck->tas.lk.depth_locked != -1) {
698 KMP_FATAL(LockNestableUsedAsSimple, func);
699 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000700 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000701 return ((lck->tas.lk.poll == 0) &&
702 KMP_COMPARE_AND_STORE_ACQ32(&(lck->tas.lk.poll), 0, gtid + 1));
703 } else {
704 KMP_DEBUG_ASSERT(__kmp_test_user_lock_with_checks_ != NULL);
705 return (*__kmp_test_user_lock_with_checks_)(lck, gtid);
706 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000707}
708#else
Jonathan Peyton30419822017-05-12 18:01:32 +0000709static inline int __kmp_test_user_lock_with_checks(kmp_user_lock_p lck,
710 kmp_int32 gtid) {
711 KMP_DEBUG_ASSERT(__kmp_test_user_lock_with_checks_ != NULL);
712 return (*__kmp_test_user_lock_with_checks_)(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000713}
714#endif
715
Jonathan Peyton30419822017-05-12 18:01:32 +0000716extern int (*__kmp_release_user_lock_with_checks_)(kmp_user_lock_p lck,
717 kmp_int32 gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000718
Jonathan Peyton30419822017-05-12 18:01:32 +0000719static inline void __kmp_release_user_lock_with_checks(kmp_user_lock_p lck,
720 kmp_int32 gtid) {
721 KMP_DEBUG_ASSERT(__kmp_release_user_lock_with_checks_ != NULL);
722 (*__kmp_release_user_lock_with_checks_)(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000723}
724
Jonathan Peyton30419822017-05-12 18:01:32 +0000725extern void (*__kmp_init_user_lock_with_checks_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000726
Jonathan Peyton30419822017-05-12 18:01:32 +0000727static inline void __kmp_init_user_lock_with_checks(kmp_user_lock_p lck) {
728 KMP_DEBUG_ASSERT(__kmp_init_user_lock_with_checks_ != NULL);
729 (*__kmp_init_user_lock_with_checks_)(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000730}
731
Jim Cownie5e8470a2013-09-27 10:38:44 +0000732// We need a non-checking version of destroy lock for when the RTL is
733// doing the cleanup as it can't always tell if the lock is nested or not.
Jonathan Peyton30419822017-05-12 18:01:32 +0000734extern void (*__kmp_destroy_user_lock_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000735
Jonathan Peyton30419822017-05-12 18:01:32 +0000736static inline void __kmp_destroy_user_lock(kmp_user_lock_p lck) {
737 KMP_DEBUG_ASSERT(__kmp_destroy_user_lock_ != NULL);
738 (*__kmp_destroy_user_lock_)(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000739}
740
Jonathan Peyton30419822017-05-12 18:01:32 +0000741extern void (*__kmp_destroy_user_lock_with_checks_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000742
Jonathan Peyton30419822017-05-12 18:01:32 +0000743static inline void __kmp_destroy_user_lock_with_checks(kmp_user_lock_p lck) {
744 KMP_DEBUG_ASSERT(__kmp_destroy_user_lock_with_checks_ != NULL);
745 (*__kmp_destroy_user_lock_with_checks_)(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000746}
747
Jonathan Peyton30419822017-05-12 18:01:32 +0000748extern int (*__kmp_acquire_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
749 kmp_int32 gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000750
751#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
752
Jonathan Peyton30419822017-05-12 18:01:32 +0000753#define __kmp_acquire_nested_user_lock_with_checks(lck, gtid, depth) \
754 if (__kmp_user_lock_kind == lk_tas) { \
755 if (__kmp_env_consistency_check) { \
756 char const *const func = "omp_set_nest_lock"; \
757 if ((sizeof(kmp_tas_lock_t) <= OMP_NEST_LOCK_T_SIZE) && \
758 lck->tas.lk.depth_locked == -1) { \
759 KMP_FATAL(LockSimpleUsedAsNestable, func); \
760 } \
761 } \
762 if (lck->tas.lk.poll - 1 == gtid) { \
763 lck->tas.lk.depth_locked += 1; \
764 *depth = KMP_LOCK_ACQUIRED_NEXT; \
765 } else { \
766 if ((lck->tas.lk.poll != 0) || \
767 (!KMP_COMPARE_AND_STORE_ACQ32(&(lck->tas.lk.poll), 0, gtid + 1))) { \
768 kmp_uint32 spins; \
769 KMP_FSYNC_PREPARE(lck); \
770 KMP_INIT_YIELD(spins); \
771 if (TCR_4(__kmp_nth) > \
772 (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) { \
773 KMP_YIELD(TRUE); \
774 } else { \
775 KMP_YIELD_SPIN(spins); \
776 } \
777 while ((lck->tas.lk.poll != 0) || \
778 (!KMP_COMPARE_AND_STORE_ACQ32(&(lck->tas.lk.poll), 0, \
779 gtid + 1))) { \
780 if (TCR_4(__kmp_nth) > \
781 (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) { \
782 KMP_YIELD(TRUE); \
783 } else { \
784 KMP_YIELD_SPIN(spins); \
785 } \
786 } \
787 } \
788 lck->tas.lk.depth_locked = 1; \
789 *depth = KMP_LOCK_ACQUIRED_FIRST; \
790 } \
791 KMP_FSYNC_ACQUIRED(lck); \
792 } else { \
793 KMP_DEBUG_ASSERT(__kmp_acquire_nested_user_lock_with_checks_ != NULL); \
794 *depth = (*__kmp_acquire_nested_user_lock_with_checks_)(lck, gtid); \
795 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000796
797#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000798static inline void
Jonathan Peyton30419822017-05-12 18:01:32 +0000799__kmp_acquire_nested_user_lock_with_checks(kmp_user_lock_p lck, kmp_int32 gtid,
800 int *depth) {
801 KMP_DEBUG_ASSERT(__kmp_acquire_nested_user_lock_with_checks_ != NULL);
802 *depth = (*__kmp_acquire_nested_user_lock_with_checks_)(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000803}
804#endif
805
Jonathan Peyton30419822017-05-12 18:01:32 +0000806extern int (*__kmp_test_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
807 kmp_int32 gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000808
809#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
Jonathan Peyton30419822017-05-12 18:01:32 +0000810static inline int __kmp_test_nested_user_lock_with_checks(kmp_user_lock_p lck,
811 kmp_int32 gtid) {
812 if (__kmp_user_lock_kind == lk_tas) {
813 int retval;
814 if (__kmp_env_consistency_check) {
815 char const *const func = "omp_test_nest_lock";
816 if ((sizeof(kmp_tas_lock_t) <= OMP_NEST_LOCK_T_SIZE) &&
817 lck->tas.lk.depth_locked == -1) {
818 KMP_FATAL(LockSimpleUsedAsNestable, func);
819 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000820 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000821 KMP_DEBUG_ASSERT(gtid >= 0);
822 if (lck->tas.lk.poll - 1 ==
823 gtid) { /* __kmp_get_tas_lock_owner( lck ) == gtid */
824 return ++lck->tas.lk.depth_locked; /* same owner, depth increased */
825 }
826 retval = ((lck->tas.lk.poll == 0) &&
827 KMP_COMPARE_AND_STORE_ACQ32(&(lck->tas.lk.poll), 0, gtid + 1));
828 if (retval) {
829 KMP_MB();
830 lck->tas.lk.depth_locked = 1;
831 }
832 return retval;
833 } else {
834 KMP_DEBUG_ASSERT(__kmp_test_nested_user_lock_with_checks_ != NULL);
835 return (*__kmp_test_nested_user_lock_with_checks_)(lck, gtid);
836 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000837}
838#else
Jonathan Peyton30419822017-05-12 18:01:32 +0000839static inline int __kmp_test_nested_user_lock_with_checks(kmp_user_lock_p lck,
840 kmp_int32 gtid) {
841 KMP_DEBUG_ASSERT(__kmp_test_nested_user_lock_with_checks_ != NULL);
842 return (*__kmp_test_nested_user_lock_with_checks_)(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000843}
844#endif
845
Jonathan Peyton30419822017-05-12 18:01:32 +0000846extern int (*__kmp_release_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
847 kmp_int32 gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000848
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000849static inline int
Jonathan Peyton30419822017-05-12 18:01:32 +0000850__kmp_release_nested_user_lock_with_checks(kmp_user_lock_p lck,
851 kmp_int32 gtid) {
852 KMP_DEBUG_ASSERT(__kmp_release_nested_user_lock_with_checks_ != NULL);
853 return (*__kmp_release_nested_user_lock_with_checks_)(lck, gtid);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000854}
855
Jonathan Peyton30419822017-05-12 18:01:32 +0000856extern void (*__kmp_init_nested_user_lock_with_checks_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000857
Jim Cownie181b4bb2013-12-23 17:28:57 +0000858static inline void
Jonathan Peyton30419822017-05-12 18:01:32 +0000859__kmp_init_nested_user_lock_with_checks(kmp_user_lock_p lck) {
860 KMP_DEBUG_ASSERT(__kmp_init_nested_user_lock_with_checks_ != NULL);
861 (*__kmp_init_nested_user_lock_with_checks_)(lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000862}
863
Jonathan Peyton30419822017-05-12 18:01:32 +0000864extern void (*__kmp_destroy_nested_user_lock_with_checks_)(kmp_user_lock_p lck);
865
866static inline void
867__kmp_destroy_nested_user_lock_with_checks(kmp_user_lock_p lck) {
868 KMP_DEBUG_ASSERT(__kmp_destroy_nested_user_lock_with_checks_ != NULL);
869 (*__kmp_destroy_nested_user_lock_with_checks_)(lck);
870}
871
Jim Cownie5e8470a2013-09-27 10:38:44 +0000872// user lock functions which do not necessarily exist for all lock kinds.
873//
874// The "set" functions usually have wrapper routines that check for a NULL set
875// function pointer and call it if non-NULL.
876//
877// In some cases, it makes sense to have a "get" wrapper function check for a
878// NULL get function pointer and return NULL / invalid value / error code if
879// the function pointer is NULL.
880//
881// In other cases, the calling code really should differentiate between an
882// unimplemented function and one that is implemented but returning NULL /
883// invalied value. If this is the case, no get function wrapper exists.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000884
Jonathan Peyton30419822017-05-12 18:01:32 +0000885extern int (*__kmp_is_user_lock_initialized_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000886
887// no set function; fields set durining local allocation
888
Jonathan Peyton30419822017-05-12 18:01:32 +0000889extern const ident_t *(*__kmp_get_user_lock_location_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000890
Jonathan Peyton30419822017-05-12 18:01:32 +0000891static inline const ident_t *__kmp_get_user_lock_location(kmp_user_lock_p lck) {
892 if (__kmp_get_user_lock_location_ != NULL) {
893 return (*__kmp_get_user_lock_location_)(lck);
894 } else {
895 return NULL;
896 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000897}
898
Jonathan Peyton30419822017-05-12 18:01:32 +0000899extern void (*__kmp_set_user_lock_location_)(kmp_user_lock_p lck,
900 const ident_t *loc);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000901
Jonathan Peyton30419822017-05-12 18:01:32 +0000902static inline void __kmp_set_user_lock_location(kmp_user_lock_p lck,
903 const ident_t *loc) {
904 if (__kmp_set_user_lock_location_ != NULL) {
905 (*__kmp_set_user_lock_location_)(lck, loc);
906 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000907}
908
Jonathan Peyton30419822017-05-12 18:01:32 +0000909extern kmp_lock_flags_t (*__kmp_get_user_lock_flags_)(kmp_user_lock_p lck);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000910
Jonathan Peyton30419822017-05-12 18:01:32 +0000911extern void (*__kmp_set_user_lock_flags_)(kmp_user_lock_p lck,
912 kmp_lock_flags_t flags);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000913
Jonathan Peyton30419822017-05-12 18:01:32 +0000914static inline void __kmp_set_user_lock_flags(kmp_user_lock_p lck,
915 kmp_lock_flags_t flags) {
916 if (__kmp_set_user_lock_flags_ != NULL) {
917 (*__kmp_set_user_lock_flags_)(lck, flags);
918 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000919}
920
Jim Cownie5e8470a2013-09-27 10:38:44 +0000921// The fuction which sets up all of the vtbl pointers for kmp_user_lock_t.
Jonathan Peyton30419822017-05-12 18:01:32 +0000922extern void __kmp_set_user_lock_vptrs(kmp_lock_kind_t user_lock_kind);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000923
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000924// Macros for binding user lock functions.
Jonathan Peyton30419822017-05-12 18:01:32 +0000925#define KMP_BIND_USER_LOCK_TEMPLATE(nest, kind, suffix) \
926 { \
927 __kmp_acquire##nest##user_lock_with_checks_ = (int (*)( \
928 kmp_user_lock_p, kmp_int32))__kmp_acquire##nest##kind##_##suffix; \
929 __kmp_release##nest##user_lock_with_checks_ = (int (*)( \
930 kmp_user_lock_p, kmp_int32))__kmp_release##nest##kind##_##suffix; \
931 __kmp_test##nest##user_lock_with_checks_ = (int (*)( \
932 kmp_user_lock_p, kmp_int32))__kmp_test##nest##kind##_##suffix; \
933 __kmp_init##nest##user_lock_with_checks_ = \
934 (void (*)(kmp_user_lock_p))__kmp_init##nest##kind##_##suffix; \
935 __kmp_destroy##nest##user_lock_with_checks_ = \
936 (void (*)(kmp_user_lock_p))__kmp_destroy##nest##kind##_##suffix; \
937 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000938
Jonathan Peyton30419822017-05-12 18:01:32 +0000939#define KMP_BIND_USER_LOCK(kind) KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock)
940#define KMP_BIND_USER_LOCK_WITH_CHECKS(kind) \
941 KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock_with_checks)
942#define KMP_BIND_NESTED_USER_LOCK(kind) \
943 KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock)
944#define KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(kind) \
945 KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock_with_checks)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000946
Jim Cownie5e8470a2013-09-27 10:38:44 +0000947// User lock table & lock allocation
Jonathan Peyton30419822017-05-12 18:01:32 +0000948/* On 64-bit Linux* OS (and OS X*) GNU compiler allocates only 4 bytems memory
949 for lock variable, which is not enough to store a pointer, so we have to use
950 lock indexes instead of pointers and maintain lock table to map indexes to
951 pointers.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000952
953
Jonathan Peyton30419822017-05-12 18:01:32 +0000954 Note: The first element of the table is not a pointer to lock! It is a
955 pointer to previously allocated table (or NULL if it is the first table).
Jim Cownie5e8470a2013-09-27 10:38:44 +0000956
Jonathan Peyton30419822017-05-12 18:01:32 +0000957 Usage:
Jim Cownie5e8470a2013-09-27 10:38:44 +0000958
Jonathan Peyton30419822017-05-12 18:01:32 +0000959 if ( OMP_LOCK_T_SIZE < sizeof( <lock> ) ) { // or OMP_NEST_LOCK_T_SIZE
960 Lock table is fully utilized. User locks are indexes, so table is used on
961 user lock operation.
962 Note: it may be the case (lin_32) that we don't need to use a lock
963 table for regular locks, but do need the table for nested locks.
964 }
965 else {
966 Lock table initialized but not actually used.
967 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000968*/
969
970struct kmp_lock_table {
Jonathan Peyton30419822017-05-12 18:01:32 +0000971 kmp_lock_index_t used; // Number of used elements
972 kmp_lock_index_t allocated; // Number of allocated elements
973 kmp_user_lock_p *table; // Lock table.
Jim Cownie5e8470a2013-09-27 10:38:44 +0000974};
975
976typedef struct kmp_lock_table kmp_lock_table_t;
977
978extern kmp_lock_table_t __kmp_user_lock_table;
979extern kmp_user_lock_p __kmp_lock_pool;
980
981struct kmp_block_of_locks {
Jonathan Peyton30419822017-05-12 18:01:32 +0000982 struct kmp_block_of_locks *next_block;
983 void *locks;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000984};
985
986typedef struct kmp_block_of_locks kmp_block_of_locks_t;
987
988extern kmp_block_of_locks_t *__kmp_lock_blocks;
989extern int __kmp_num_locks_in_block;
990
Jonathan Peyton30419822017-05-12 18:01:32 +0000991extern kmp_user_lock_p __kmp_user_lock_allocate(void **user_lock,
992 kmp_int32 gtid,
993 kmp_lock_flags_t flags);
994extern void __kmp_user_lock_free(void **user_lock, kmp_int32 gtid,
995 kmp_user_lock_p lck);
996extern kmp_user_lock_p __kmp_lookup_user_lock(void **user_lock,
997 char const *func);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000998extern void __kmp_cleanup_user_locks();
999
Jonathan Peyton30419822017-05-12 18:01:32 +00001000#define KMP_CHECK_USER_LOCK_INIT() \
1001 { \
1002 if (!TCR_4(__kmp_init_user_locks)) { \
1003 __kmp_acquire_bootstrap_lock(&__kmp_initz_lock); \
1004 if (!TCR_4(__kmp_init_user_locks)) { \
1005 TCW_4(__kmp_init_user_locks, TRUE); \
1006 } \
1007 __kmp_release_bootstrap_lock(&__kmp_initz_lock); \
1008 } \
1009 }
Jim Cownie5e8470a2013-09-27 10:38:44 +00001010
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001011#endif // KMP_USE_DYNAMIC_LOCK
1012
Jim Cownie5e8470a2013-09-27 10:38:44 +00001013#undef KMP_PAD
1014#undef KMP_GTID_DNE
1015
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001016#if KMP_USE_DYNAMIC_LOCK
Jonathan Peyton30419822017-05-12 18:01:32 +00001017// KMP_USE_DYNAMIC_LOCK enables dynamic dispatch of lock functions without
1018// breaking the current compatibility. Essential functionality of this new code
1019// is dynamic dispatch, but it also implements (or enables implementation of)
1020// hinted user lock and critical section which will be part of OMP 4.5 soon.
Jonathan Peytonb87b5812015-12-11 22:04:05 +00001021//
Jonathan Peyton30419822017-05-12 18:01:32 +00001022// Lock type can be decided at creation time (i.e., lock initialization), and
1023// subsequent lock function call on the created lock object requires type
1024// extraction and call through jump table using the extracted type. This type
1025// information is stored in two different ways depending on the size of the lock
1026// object, and we differentiate lock types by this size requirement - direct and
1027// indirect locks.
Jonathan Peytonb87b5812015-12-11 22:04:05 +00001028//
1029// Direct locks:
Jonathan Peyton30419822017-05-12 18:01:32 +00001030// A direct lock object fits into the space created by the compiler for an
1031// omp_lock_t object, and TAS/Futex lock falls into this category. We use low
1032// one byte of the lock object as the storage for the lock type, and appropriate
1033// bit operation is required to access the data meaningful to the lock
1034// algorithms. Also, to differentiate direct lock from indirect lock, 1 is
1035// written to LSB of the lock object. The newly introduced "hle" lock is also a
1036// direct lock.
Jonathan Peytonb87b5812015-12-11 22:04:05 +00001037//
1038// Indirect locks:
Jonathan Peyton30419822017-05-12 18:01:32 +00001039// An indirect lock object requires more space than the compiler-generated
1040// space, and it should be allocated from heap. Depending on the size of the
1041// compiler-generated space for the lock (i.e., size of omp_lock_t), this
1042// omp_lock_t object stores either the address of the heap-allocated indirect
1043// lock (void * fits in the object) or an index to the indirect lock table entry
1044// that holds the address. Ticket/Queuing/DRDPA/Adaptive lock falls into this
1045// category, and the newly introduced "rtm" lock is also an indirect lock which
1046// was implemented on top of the Queuing lock. When the omp_lock_t object holds
1047// an index (not lock address), 0 is written to LSB to differentiate the lock
1048// from a direct lock, and the remaining part is the actual index to the
Jonathan Peytonb87b5812015-12-11 22:04:05 +00001049// indirect lock table.
Jonathan Peytonb87b5812015-12-11 22:04:05 +00001050
1051#include <stdint.h> // for uintptr_t
1052
Jonathan Peytondae13d82015-12-11 21:57:06 +00001053// Shortcuts
Jonathan Peyton30419822017-05-12 18:01:32 +00001054#define KMP_USE_INLINED_TAS \
1055 (KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)) && 1
Jonathan Peyton9d2412c2016-06-22 16:35:12 +00001056#define KMP_USE_INLINED_FUTEX KMP_USE_FUTEX && 0
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001057
1058// List of lock definitions; all nested locks are indirect locks.
1059// hle lock is xchg lock prefixed with XACQUIRE/XRELEASE.
1060// All nested locks are indirect lock types.
Jonathan Peytondae13d82015-12-11 21:57:06 +00001061#if KMP_USE_TSX
Jonathan Peyton30419822017-05-12 18:01:32 +00001062#if KMP_USE_FUTEX
1063#define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a) m(hle, a)
1064#define KMP_FOREACH_I_LOCK(m, a) \
1065 m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) m(rtm, a) \
1066 m(nested_tas, a) m(nested_futex, a) m(nested_ticket, a) \
1067 m(nested_queuing, a) m(nested_drdpa, a)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001068#else
Jonathan Peyton30419822017-05-12 18:01:32 +00001069#define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(hle, a)
1070#define KMP_FOREACH_I_LOCK(m, a) \
1071 m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) m(rtm, a) \
1072 m(nested_tas, a) m(nested_ticket, a) m(nested_queuing, a) \
1073 m(nested_drdpa, a)
1074#endif // KMP_USE_FUTEX
1075#define KMP_LAST_D_LOCK lockseq_hle
1076#else
1077#if KMP_USE_FUTEX
1078#define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a)
1079#define KMP_FOREACH_I_LOCK(m, a) \
1080 m(ticket, a) m(queuing, a) m(drdpa, a) m(nested_tas, a) m(nested_futex, a) \
1081 m(nested_ticket, a) m(nested_queuing, a) m(nested_drdpa, a)
1082#define KMP_LAST_D_LOCK lockseq_futex
1083#else
1084#define KMP_FOREACH_D_LOCK(m, a) m(tas, a)
1085#define KMP_FOREACH_I_LOCK(m, a) \
1086 m(ticket, a) m(queuing, a) m(drdpa, a) m(nested_tas, a) m(nested_ticket, a) \
1087 m(nested_queuing, a) m(nested_drdpa, a)
1088#define KMP_LAST_D_LOCK lockseq_tas
1089#endif // KMP_USE_FUTEX
Jonathan Peytondae13d82015-12-11 21:57:06 +00001090#endif // KMP_USE_TSX
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001091
1092// Information used in dynamic dispatch
Jonathan Peyton30419822017-05-12 18:01:32 +00001093#define KMP_LOCK_SHIFT \
1094 8 // number of low bits to be used as tag for direct locks
Jonathan Peytona03533d2015-12-11 21:49:08 +00001095#define KMP_FIRST_D_LOCK lockseq_tas
1096#define KMP_FIRST_I_LOCK lockseq_ticket
Jonathan Peyton30419822017-05-12 18:01:32 +00001097#define KMP_LAST_I_LOCK lockseq_nested_drdpa
1098#define KMP_NUM_I_LOCKS \
1099 (locktag_nested_drdpa + 1) // number of indirect lock types
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001100
1101// Base type for dynamic locks.
1102typedef kmp_uint32 kmp_dyna_lock_t;
1103
Jonathan Peyton30419822017-05-12 18:01:32 +00001104// Lock sequence that enumerates all lock kinds. Always make this enumeration
1105// consistent with kmp_lockseq_t in the include directory.
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001106typedef enum {
Jonathan Peyton30419822017-05-12 18:01:32 +00001107 lockseq_indirect = 0,
1108#define expand_seq(l, a) lockseq_##l,
1109 KMP_FOREACH_D_LOCK(expand_seq, 0) KMP_FOREACH_I_LOCK(expand_seq, 0)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001110#undef expand_seq
1111} kmp_dyna_lockseq_t;
1112
1113// Enumerates indirect lock tags.
1114typedef enum {
Jonathan Peyton30419822017-05-12 18:01:32 +00001115#define expand_tag(l, a) locktag_##l,
1116 KMP_FOREACH_I_LOCK(expand_tag, 0)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001117#undef expand_tag
1118} kmp_indirect_locktag_t;
1119
1120// Utility macros that extract information from lock sequences.
Jonathan Peyton30419822017-05-12 18:01:32 +00001121#define KMP_IS_D_LOCK(seq) \
1122 ((seq) >= KMP_FIRST_D_LOCK && (seq) <= KMP_LAST_D_LOCK)
1123#define KMP_IS_I_LOCK(seq) \
1124 ((seq) >= KMP_FIRST_I_LOCK && (seq) <= KMP_LAST_I_LOCK)
1125#define KMP_GET_I_TAG(seq) (kmp_indirect_locktag_t)((seq)-KMP_FIRST_I_LOCK)
1126#define KMP_GET_D_TAG(seq) ((seq) << 1 | 1)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001127
1128// Enumerates direct lock tags starting from indirect tag.
1129typedef enum {
Jonathan Peyton30419822017-05-12 18:01:32 +00001130#define expand_tag(l, a) locktag_##l = KMP_GET_D_TAG(lockseq_##l),
1131 KMP_FOREACH_D_LOCK(expand_tag, 0)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001132#undef expand_tag
1133} kmp_direct_locktag_t;
1134
1135// Indirect lock type
1136typedef struct {
Jonathan Peyton30419822017-05-12 18:01:32 +00001137 kmp_user_lock_p lock;
1138 kmp_indirect_locktag_t type;
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001139} kmp_indirect_lock_t;
1140
Jonathan Peyton30419822017-05-12 18:01:32 +00001141// Function tables for direct locks. Set/unset/test differentiate functions
1142// with/without consistency checking.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001143extern void (*__kmp_direct_init[])(kmp_dyna_lock_t *, kmp_dyna_lockseq_t);
1144extern void (*__kmp_direct_destroy[])(kmp_dyna_lock_t *);
Joachim Protze82e94a52017-11-01 10:08:30 +00001145extern int (*(*__kmp_direct_set))(kmp_dyna_lock_t *, kmp_int32);
Jonathan Peyton30419822017-05-12 18:01:32 +00001146extern int (*(*__kmp_direct_unset))(kmp_dyna_lock_t *, kmp_int32);
1147extern int (*(*__kmp_direct_test))(kmp_dyna_lock_t *, kmp_int32);
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001148
Jonathan Peyton30419822017-05-12 18:01:32 +00001149// Function tables for indirect locks. Set/unset/test differentiate functions
1150// with/withuot consistency checking.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001151extern void (*__kmp_indirect_init[])(kmp_user_lock_p);
1152extern void (*__kmp_indirect_destroy[])(kmp_user_lock_p);
Joachim Protze82e94a52017-11-01 10:08:30 +00001153extern int (*(*__kmp_indirect_set))(kmp_user_lock_p, kmp_int32);
Jonathan Peyton30419822017-05-12 18:01:32 +00001154extern int (*(*__kmp_indirect_unset))(kmp_user_lock_p, kmp_int32);
1155extern int (*(*__kmp_indirect_test))(kmp_user_lock_p, kmp_int32);
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001156
1157// Extracts direct lock tag from a user lock pointer
Jonathan Peyton30419822017-05-12 18:01:32 +00001158#define KMP_EXTRACT_D_TAG(l) \
1159 (*((kmp_dyna_lock_t *)(l)) & ((1 << KMP_LOCK_SHIFT) - 1) & \
1160 -(*((kmp_dyna_lock_t *)(l)) & 1))
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001161
1162// Extracts indirect lock index from a user lock pointer
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001163#define KMP_EXTRACT_I_INDEX(l) (*(kmp_lock_index_t *)(l) >> 1)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001164
Jonathan Peyton30419822017-05-12 18:01:32 +00001165// Returns function pointer to the direct lock function with l (kmp_dyna_lock_t
1166// *) and op (operation type).
Jonathan Peytona03533d2015-12-11 21:49:08 +00001167#define KMP_D_LOCK_FUNC(l, op) __kmp_direct_##op[KMP_EXTRACT_D_TAG(l)]
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001168
Jonathan Peyton30419822017-05-12 18:01:32 +00001169// Returns function pointer to the indirect lock function with l
1170// (kmp_indirect_lock_t *) and op (operation type).
1171#define KMP_I_LOCK_FUNC(l, op) \
1172 __kmp_indirect_##op[((kmp_indirect_lock_t *)(l))->type]
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001173
1174// Initializes a direct lock with the given lock pointer and lock sequence.
Jonathan Peyton30419822017-05-12 18:01:32 +00001175#define KMP_INIT_D_LOCK(l, seq) \
1176 __kmp_direct_init[KMP_GET_D_TAG(seq)]((kmp_dyna_lock_t *)l, seq)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001177
1178// Initializes an indirect lock with the given lock pointer and lock sequence.
Jonathan Peyton30419822017-05-12 18:01:32 +00001179#define KMP_INIT_I_LOCK(l, seq) \
1180 __kmp_direct_init[0]((kmp_dyna_lock_t *)(l), seq)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001181
1182// Returns "free" lock value for the given lock type.
Jonathan Peyton30419822017-05-12 18:01:32 +00001183#define KMP_LOCK_FREE(type) (locktag_##type)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001184
1185// Returns "busy" lock value for the given lock teyp.
Jonathan Peyton30419822017-05-12 18:01:32 +00001186#define KMP_LOCK_BUSY(v, type) ((v) << KMP_LOCK_SHIFT | locktag_##type)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001187
1188// Returns lock value after removing (shifting) lock tag.
Jonathan Peyton30419822017-05-12 18:01:32 +00001189#define KMP_LOCK_STRIP(v) ((v) >> KMP_LOCK_SHIFT)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001190
Jonathan Peyton30419822017-05-12 18:01:32 +00001191// Initializes global states and data structures for managing dynamic user
1192// locks.
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001193extern void __kmp_init_dynamic_user_locks();
1194
1195// Allocates and returns an indirect lock with the given indirect lock tag.
Jonathan Peyton30419822017-05-12 18:01:32 +00001196extern kmp_indirect_lock_t *
1197__kmp_allocate_indirect_lock(void **, kmp_int32, kmp_indirect_locktag_t);
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001198
1199// Cleans up global states and data structures for managing dynamic user locks.
1200extern void __kmp_cleanup_indirect_user_locks();
1201
Jonathan Peyton61118492016-05-20 19:03:38 +00001202// Default user lock sequence when not using hinted locks.
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001203extern kmp_dyna_lockseq_t __kmp_user_lock_seq;
1204
1205// Jump table for "set lock location", available only for indirect locks.
Jonathan Peyton30419822017-05-12 18:01:32 +00001206extern void (*__kmp_indirect_set_location[KMP_NUM_I_LOCKS])(kmp_user_lock_p,
1207 const ident_t *);
1208#define KMP_SET_I_LOCK_LOCATION(lck, loc) \
1209 { \
1210 if (__kmp_indirect_set_location[(lck)->type] != NULL) \
1211 __kmp_indirect_set_location[(lck)->type]((lck)->lock, loc); \
1212 }
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001213
1214// Jump table for "set lock flags", available only for indirect locks.
Jonathan Peyton30419822017-05-12 18:01:32 +00001215extern void (*__kmp_indirect_set_flags[KMP_NUM_I_LOCKS])(kmp_user_lock_p,
1216 kmp_lock_flags_t);
1217#define KMP_SET_I_LOCK_FLAGS(lck, flag) \
1218 { \
1219 if (__kmp_indirect_set_flags[(lck)->type] != NULL) \
1220 __kmp_indirect_set_flags[(lck)->type]((lck)->lock, flag); \
1221 }
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001222
1223// Jump table for "get lock location", available only for indirect locks.
Jonathan Peyton30419822017-05-12 18:01:32 +00001224extern const ident_t *(*__kmp_indirect_get_location[KMP_NUM_I_LOCKS])(
1225 kmp_user_lock_p);
1226#define KMP_GET_I_LOCK_LOCATION(lck) \
1227 (__kmp_indirect_get_location[(lck)->type] != NULL \
1228 ? __kmp_indirect_get_location[(lck)->type]((lck)->lock) \
1229 : NULL)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001230
1231// Jump table for "get lock flags", available only for indirect locks.
Jonathan Peyton30419822017-05-12 18:01:32 +00001232extern kmp_lock_flags_t (*__kmp_indirect_get_flags[KMP_NUM_I_LOCKS])(
1233 kmp_user_lock_p);
1234#define KMP_GET_I_LOCK_FLAGS(lck) \
1235 (__kmp_indirect_get_flags[(lck)->type] != NULL \
1236 ? __kmp_indirect_get_flags[(lck)->type]((lck)->lock) \
1237 : NULL)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001238
Jonathan Peyton30419822017-05-12 18:01:32 +00001239#define KMP_I_LOCK_CHUNK \
1240 1024 // number of kmp_indirect_lock_t objects to be allocated together
Jonathan Peytondae13d82015-12-11 21:57:06 +00001241
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001242// Lock table for indirect locks.
Jonathan Peytondae13d82015-12-11 21:57:06 +00001243typedef struct kmp_indirect_lock_table {
Jonathan Peyton30419822017-05-12 18:01:32 +00001244 kmp_indirect_lock_t **table; // blocks of indirect locks allocated
1245 kmp_lock_index_t size; // size of the indirect lock table
1246 kmp_lock_index_t next; // index to the next lock to be allocated
Jonathan Peytondae13d82015-12-11 21:57:06 +00001247} kmp_indirect_lock_table_t;
1248
1249extern kmp_indirect_lock_table_t __kmp_i_lock_table;
1250
1251// Returns the indirect lock associated with the given index.
Jonathan Peyton30419822017-05-12 18:01:32 +00001252#define KMP_GET_I_LOCK(index) \
1253 (*(__kmp_i_lock_table.table + (index) / KMP_I_LOCK_CHUNK) + \
1254 (index) % KMP_I_LOCK_CHUNK)
Jonathan Peytondae13d82015-12-11 21:57:06 +00001255
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001256// Number of locks in a lock block, which is fixed to "1" now.
Jonathan Peyton30419822017-05-12 18:01:32 +00001257// TODO: No lock block implementation now. If we do support, we need to manage
1258// lock block data structure for each indirect lock type.
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001259extern int __kmp_num_locks_in_block;
1260
1261// Fast lock table lookup without consistency checking
Jonathan Peyton30419822017-05-12 18:01:32 +00001262#define KMP_LOOKUP_I_LOCK(l) \
1263 ((OMP_LOCK_T_SIZE < sizeof(void *)) ? KMP_GET_I_LOCK(KMP_EXTRACT_I_INDEX(l)) \
1264 : *((kmp_indirect_lock_t **)(l)))
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001265
Jonathan Peytonde4749b2016-12-14 23:01:24 +00001266// Used once in kmp_error.cpp
Jonathan Peyton30419822017-05-12 18:01:32 +00001267extern kmp_int32 __kmp_get_user_lock_owner(kmp_user_lock_p, kmp_uint32);
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001268
1269#else // KMP_USE_DYNAMIC_LOCK
1270
Jonathan Peyton30419822017-05-12 18:01:32 +00001271#define KMP_LOCK_BUSY(v, type) (v)
1272#define KMP_LOCK_FREE(type) 0
1273#define KMP_LOCK_STRIP(v) (v)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001274
1275#endif // KMP_USE_DYNAMIC_LOCK
1276
Jonathan Peyton377aa402016-04-14 16:00:37 +00001277// data structure for using backoff within spin locks.
1278typedef struct {
Jonathan Peyton30419822017-05-12 18:01:32 +00001279 kmp_uint32 step; // current step
1280 kmp_uint32 max_backoff; // upper bound of outer delay loop
1281 kmp_uint32 min_tick; // size of inner delay loop in ticks (machine-dependent)
Jonathan Peyton377aa402016-04-14 16:00:37 +00001282} kmp_backoff_t;
1283
1284// Runtime's default backoff parameters
1285extern kmp_backoff_t __kmp_spin_backoff_params;
1286
1287// Backoff function
1288extern void __kmp_spin_backoff(kmp_backoff_t *);
1289
Jim Cownie5e8470a2013-09-27 10:38:44 +00001290#ifdef __cplusplus
1291} // extern "C"
1292#endif // __cplusplus
1293
1294#endif /* KMP_LOCK_H */