blob: d71317239da30831aff7aae1c2385f91b2df6bc6 [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
5
6//===----------------------------------------------------------------------===//
7//
8// The LLVM Compiler Infrastructure
9//
10// This file is dual licensed under the MIT and the University of Illinois Open
11// Source Licenses. See LICENSE.txt for details.
12//
13//===----------------------------------------------------------------------===//
14
15
16#ifndef KMP_LOCK_H
17#define KMP_LOCK_H
18
19#include <limits.h> // CHAR_BIT
20#include <stddef.h> // offsetof
21
22#include "kmp_os.h"
23#include "kmp_debug.h"
24
25#ifdef __cplusplus
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +000026#include <atomic>
27
Jim Cownie5e8470a2013-09-27 10:38:44 +000028extern "C" {
29#endif // __cplusplus
30
31// ----------------------------------------------------------------------------
32// Have to copy these definitions from kmp.h because kmp.h cannot be included
33// due to circular dependencies. Will undef these at end of file.
34
35#define KMP_PAD(type, sz) (sizeof(type) + (sz - ((sizeof(type) - 1) % (sz)) - 1))
36#define KMP_GTID_DNE (-2)
37
38// Forward declaration of ident and ident_t
39
40struct ident;
41typedef struct ident ident_t;
42
43// End of copied code.
44// ----------------------------------------------------------------------------
45
46//
47// We need to know the size of the area we can assume that the compiler(s)
48// allocated for obects of type omp_lock_t and omp_nest_lock_t. The Intel
49// compiler always allocates a pointer-sized area, as does visual studio.
50//
51// gcc however, only allocates 4 bytes for regular locks, even on 64-bit
52// intel archs. It allocates at least 8 bytes for nested lock (more on
53// recent versions), but we are bounded by the pointer-sized chunks that
54// the Intel compiler allocates.
55//
56
57#if KMP_OS_LINUX && defined(KMP_GOMP_COMPAT)
58# define OMP_LOCK_T_SIZE sizeof(int)
59# define OMP_NEST_LOCK_T_SIZE sizeof(void *)
60#else
61# define OMP_LOCK_T_SIZE sizeof(void *)
62# define OMP_NEST_LOCK_T_SIZE sizeof(void *)
63#endif
64
65//
66// The Intel compiler allocates a 32-byte chunk for a critical section.
67// Both gcc and visual studio only allocate enough space for a pointer.
68// Sometimes we know that the space was allocated by the Intel compiler.
69//
70#define OMP_CRITICAL_SIZE sizeof(void *)
71#define INTEL_CRITICAL_SIZE 32
72
73//
74// lock flags
75//
76typedef kmp_uint32 kmp_lock_flags_t;
77
78#define kmp_lf_critical_section 1
79
80//
81// When a lock table is used, the indices are of kmp_lock_index_t
82//
83typedef kmp_uint32 kmp_lock_index_t;
84
85//
86// When memory allocated for locks are on the lock pool (free list),
87// it is treated as structs of this type.
88//
89struct kmp_lock_pool {
90 union kmp_user_lock *next;
91 kmp_lock_index_t index;
92};
93
94typedef struct kmp_lock_pool kmp_lock_pool_t;
95
96
97extern void __kmp_validate_locks( void );
98
99
100// ----------------------------------------------------------------------------
101//
102// There are 5 lock implementations:
103//
104// 1. Test and set locks.
105// 2. futex locks (Linux* OS on x86 and Intel(R) Many Integrated Core architecture)
106// 3. Ticket (Lamport bakery) locks.
107// 4. Queuing locks (with separate spin fields).
108// 5. DRPA (Dynamically Reconfigurable Distributed Polling Area) locks
109//
110// and 3 lock purposes:
111//
112// 1. Bootstrap locks -- Used for a few locks available at library startup-shutdown time.
113// These do not require non-negative global thread ID's.
114// 2. Internal RTL locks -- Used everywhere else in the RTL
115// 3. User locks (includes critical sections)
116//
117// ----------------------------------------------------------------------------
118
119
120// ============================================================================
121// Lock implementations.
122// ============================================================================
123
124
125// ----------------------------------------------------------------------------
126// Test and set locks.
127//
128// Non-nested test and set locks differ from the other lock kinds (except
129// futex) in that we use the memory allocated by the compiler for the lock,
130// rather than a pointer to it.
131//
132// On lin32, lin_32e, and win_32, the space allocated may be as small as 4
133// bytes, so we have to use a lock table for nested locks, and avoid accessing
134// the depth_locked field for non-nested locks.
135//
136// Information normally available to the tools, such as lock location,
137// lock usage (normal lock vs. critical section), etc. is not available with
138// test and set locks.
139// ----------------------------------------------------------------------------
140
141struct kmp_base_tas_lock {
142 volatile kmp_int32 poll; // 0 => unlocked
143 // locked: (gtid+1) of owning thread
144 kmp_int32 depth_locked; // depth locked, for nested locks only
145};
146
147typedef struct kmp_base_tas_lock kmp_base_tas_lock_t;
148
149union kmp_tas_lock {
150 kmp_base_tas_lock_t lk;
151 kmp_lock_pool_t pool; // make certain struct is large enough
152 double lk_align; // use worst case alignment
153 // no cache line padding
154};
155
156typedef union kmp_tas_lock kmp_tas_lock_t;
157
158//
159// Static initializer for test and set lock variables. Usage:
160// kmp_tas_lock_t xlock = KMP_TAS_LOCK_INITIALIZER( xlock );
161//
162#define KMP_TAS_LOCK_INITIALIZER( lock ) { { 0, 0 } }
163
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000164extern int __kmp_acquire_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000165extern int __kmp_test_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000166extern int __kmp_release_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000167extern void __kmp_init_tas_lock( kmp_tas_lock_t *lck );
168extern void __kmp_destroy_tas_lock( kmp_tas_lock_t *lck );
169
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000170extern int __kmp_acquire_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000171extern int __kmp_test_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000172extern int __kmp_release_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000173extern void __kmp_init_nested_tas_lock( kmp_tas_lock_t *lck );
174extern void __kmp_destroy_nested_tas_lock( kmp_tas_lock_t *lck );
175
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000176#define KMP_LOCK_RELEASED 1
177#define KMP_LOCK_STILL_HELD 0
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000178#define KMP_LOCK_ACQUIRED_FIRST 1
179#define KMP_LOCK_ACQUIRED_NEXT 0
Jim Cownie5e8470a2013-09-27 10:38:44 +0000180
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000181#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000182
183// ----------------------------------------------------------------------------
184// futex locks. futex locks are only available on Linux* OS.
185//
186// Like non-nested test and set lock, non-nested futex locks use the memory
187// allocated by the compiler for the lock, rather than a pointer to it.
188//
189// Information normally available to the tools, such as lock location,
190// lock usage (normal lock vs. critical section), etc. is not available with
191// test and set locks. With non-nested futex locks, the lock owner is not
192// even available.
193// ----------------------------------------------------------------------------
194
195struct kmp_base_futex_lock {
196 volatile kmp_int32 poll; // 0 => unlocked
197 // 2*(gtid+1) of owning thread, 0 if unlocked
198 // locked: (gtid+1) of owning thread
199 kmp_int32 depth_locked; // depth locked, for nested locks only
200};
201
202typedef struct kmp_base_futex_lock kmp_base_futex_lock_t;
203
204union kmp_futex_lock {
205 kmp_base_futex_lock_t lk;
206 kmp_lock_pool_t pool; // make certain struct is large enough
207 double lk_align; // use worst case alignment
208 // no cache line padding
209};
210
211typedef union kmp_futex_lock kmp_futex_lock_t;
212
213//
214// Static initializer for futex lock variables. Usage:
215// kmp_futex_lock_t xlock = KMP_FUTEX_LOCK_INITIALIZER( xlock );
216//
217#define KMP_FUTEX_LOCK_INITIALIZER( lock ) { { 0, 0 } }
218
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000219extern int __kmp_acquire_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000220extern int __kmp_test_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000221extern int __kmp_release_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000222extern void __kmp_init_futex_lock( kmp_futex_lock_t *lck );
223extern void __kmp_destroy_futex_lock( kmp_futex_lock_t *lck );
224
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000225extern int __kmp_acquire_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000226extern int __kmp_test_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000227extern int __kmp_release_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000228extern void __kmp_init_nested_futex_lock( kmp_futex_lock_t *lck );
229extern void __kmp_destroy_nested_futex_lock( kmp_futex_lock_t *lck );
230
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000231#endif // KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000232
233
234// ----------------------------------------------------------------------------
235// Ticket locks.
236// ----------------------------------------------------------------------------
237
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +0000238#ifdef __cplusplus
239
Jim Cownie5e8470a2013-09-27 10:38:44 +0000240struct kmp_base_ticket_lock {
241 // `initialized' must be the first entry in the lock data structure!
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +0000242 std::atomic<bool> initialized;
243 volatile union kmp_ticket_lock *self; // points to the lock union
244 ident_t const * location; // Source code location of omp_init_lock().
245 std::atomic<unsigned> next_ticket; // ticket number to give to next thread which acquires
246 std::atomic<unsigned> now_serving; // ticket number for thread which holds the lock
247 std::atomic<int> owner_id; // (gtid+1) of owning thread, 0 if unlocked
248 std::atomic<int> depth_locked; // depth locked, for nested locks only
249 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
Jim Cownie5e8470a2013-09-27 10:38:44 +0000250};
251
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +0000252#else // __cplusplus
253
254struct kmp_base_ticket_lock;
255
256#endif // !__cplusplus
257
Jim Cownie5e8470a2013-09-27 10:38:44 +0000258typedef struct kmp_base_ticket_lock kmp_base_ticket_lock_t;
259
260union KMP_ALIGN_CACHE kmp_ticket_lock {
261 kmp_base_ticket_lock_t lk; // This field must be first to allow static initializing.
262 kmp_lock_pool_t pool;
263 double lk_align; // use worst case alignment
264 char lk_pad[ KMP_PAD( kmp_base_ticket_lock_t, CACHE_LINE ) ];
265};
266
267typedef union kmp_ticket_lock kmp_ticket_lock_t;
268
269//
270// Static initializer for simple ticket lock variables. Usage:
271// kmp_ticket_lock_t xlock = KMP_TICKET_LOCK_INITIALIZER( xlock );
272// Note the macro argument. It is important to make var properly initialized.
273//
Paul Osmialowskif7cc6af2016-05-31 20:20:32 +0000274#define KMP_TICKET_LOCK_INITIALIZER( lock ) { { ATOMIC_VAR_INIT(true), \
275 &(lock), \
276 NULL, \
277 ATOMIC_VAR_INIT(0U), \
278 ATOMIC_VAR_INIT(0U), \
279 ATOMIC_VAR_INIT(0), \
280 ATOMIC_VAR_INIT(-1) } }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000281
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000282extern int __kmp_acquire_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000283extern int __kmp_test_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
284extern int __kmp_test_ticket_lock_with_cheks( kmp_ticket_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000285extern int __kmp_release_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000286extern void __kmp_init_ticket_lock( kmp_ticket_lock_t *lck );
287extern void __kmp_destroy_ticket_lock( kmp_ticket_lock_t *lck );
288
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000289extern int __kmp_acquire_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000290extern int __kmp_test_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000291extern int __kmp_release_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000292extern void __kmp_init_nested_ticket_lock( kmp_ticket_lock_t *lck );
293extern void __kmp_destroy_nested_ticket_lock( kmp_ticket_lock_t *lck );
294
295
296// ----------------------------------------------------------------------------
297// Queuing locks.
298// ----------------------------------------------------------------------------
299
300#if KMP_USE_ADAPTIVE_LOCKS
301
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000302struct kmp_adaptive_lock_info;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000303
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000304typedef struct kmp_adaptive_lock_info kmp_adaptive_lock_info_t;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000305
306#if KMP_DEBUG_ADAPTIVE_LOCKS
307
308struct kmp_adaptive_lock_statistics {
309 /* So we can get stats from locks that haven't been destroyed. */
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000310 kmp_adaptive_lock_info_t * next;
311 kmp_adaptive_lock_info_t * prev;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000312
313 /* Other statistics */
314 kmp_uint32 successfulSpeculations;
315 kmp_uint32 hardFailedSpeculations;
316 kmp_uint32 softFailedSpeculations;
317 kmp_uint32 nonSpeculativeAcquires;
318 kmp_uint32 nonSpeculativeAcquireAttempts;
319 kmp_uint32 lemmingYields;
320};
321
322typedef struct kmp_adaptive_lock_statistics kmp_adaptive_lock_statistics_t;
323
324extern void __kmp_print_speculative_stats();
325extern void __kmp_init_speculative_stats();
326
327#endif // KMP_DEBUG_ADAPTIVE_LOCKS
328
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000329struct kmp_adaptive_lock_info
Jim Cownie5e8470a2013-09-27 10:38:44 +0000330{
331 /* Values used for adaptivity.
332 * Although these are accessed from multiple threads we don't access them atomically,
333 * because if we miss updates it probably doesn't matter much. (It just affects our
334 * decision about whether to try speculation on the lock).
335 */
336 kmp_uint32 volatile badness;
337 kmp_uint32 volatile acquire_attempts;
338 /* Parameters of the lock. */
339 kmp_uint32 max_badness;
340 kmp_uint32 max_soft_retries;
341
342#if KMP_DEBUG_ADAPTIVE_LOCKS
343 kmp_adaptive_lock_statistics_t volatile stats;
344#endif
345};
346
347#endif // KMP_USE_ADAPTIVE_LOCKS
348
349
350struct kmp_base_queuing_lock {
351
352 // `initialized' must be the first entry in the lock data structure!
353 volatile union kmp_queuing_lock *initialized; // Points to the lock union if in initialized state.
354
355 ident_t const * location; // Source code location of omp_init_lock().
356
357 KMP_ALIGN( 8 ) // tail_id must be 8-byte aligned!
358
359 volatile kmp_int32 tail_id; // (gtid+1) of thread at tail of wait queue, 0 if empty
360 // Must be no padding here since head/tail used in 8-byte CAS
361 volatile kmp_int32 head_id; // (gtid+1) of thread at head of wait queue, 0 if empty
362 // Decl order assumes little endian
363 // bakery-style lock
364 volatile kmp_uint32 next_ticket; // ticket number to give to next thread which acquires
365 volatile kmp_uint32 now_serving; // ticket number for thread which holds the lock
366 volatile kmp_int32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
367 kmp_int32 depth_locked; // depth locked, for nested locks only
368
369 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
Jim Cownie5e8470a2013-09-27 10:38:44 +0000370};
371
372typedef struct kmp_base_queuing_lock kmp_base_queuing_lock_t;
373
374KMP_BUILD_ASSERT( offsetof( kmp_base_queuing_lock_t, tail_id ) % 8 == 0 );
375
376union KMP_ALIGN_CACHE kmp_queuing_lock {
377 kmp_base_queuing_lock_t lk; // This field must be first to allow static initializing.
378 kmp_lock_pool_t pool;
379 double lk_align; // use worst case alignment
380 char lk_pad[ KMP_PAD( kmp_base_queuing_lock_t, CACHE_LINE ) ];
381};
382
383typedef union kmp_queuing_lock kmp_queuing_lock_t;
384
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000385extern int __kmp_acquire_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000386extern int __kmp_test_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000387extern int __kmp_release_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000388extern void __kmp_init_queuing_lock( kmp_queuing_lock_t *lck );
389extern void __kmp_destroy_queuing_lock( kmp_queuing_lock_t *lck );
390
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000391extern int __kmp_acquire_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000392extern int __kmp_test_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000393extern int __kmp_release_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000394extern void __kmp_init_nested_queuing_lock( kmp_queuing_lock_t *lck );
395extern void __kmp_destroy_nested_queuing_lock( kmp_queuing_lock_t *lck );
396
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000397#if KMP_USE_ADAPTIVE_LOCKS
398
399// ----------------------------------------------------------------------------
400// Adaptive locks.
401// ----------------------------------------------------------------------------
402struct kmp_base_adaptive_lock {
403 kmp_base_queuing_lock qlk;
404 KMP_ALIGN(CACHE_LINE)
405 kmp_adaptive_lock_info_t adaptive; // Information for the speculative adaptive lock
406};
407
408typedef struct kmp_base_adaptive_lock kmp_base_adaptive_lock_t;
409
410union KMP_ALIGN_CACHE kmp_adaptive_lock {
411 kmp_base_adaptive_lock_t lk;
412 kmp_lock_pool_t pool;
413 double lk_align;
414 char lk_pad[ KMP_PAD(kmp_base_adaptive_lock_t, CACHE_LINE) ];
415};
416typedef union kmp_adaptive_lock kmp_adaptive_lock_t;
417
418# define GET_QLK_PTR(l) ((kmp_queuing_lock_t *) & (l)->lk.qlk)
419
420#endif // KMP_USE_ADAPTIVE_LOCKS
Jim Cownie5e8470a2013-09-27 10:38:44 +0000421
422// ----------------------------------------------------------------------------
423// DRDPA ticket locks.
424// ----------------------------------------------------------------------------
425
426struct kmp_base_drdpa_lock {
427 //
428 // All of the fields on the first cache line are only written when
429 // initializing or reconfiguring the lock. These are relatively rare
430 // operations, so data from the first cache line will usually stay
431 // resident in the cache of each thread trying to acquire the lock.
432 //
433 // initialized must be the first entry in the lock data structure!
434 //
435 KMP_ALIGN_CACHE
436
437 volatile union kmp_drdpa_lock * initialized; // points to the lock union if in initialized state
438 ident_t const * location; // Source code location of omp_init_lock().
439 volatile struct kmp_lock_poll {
440 kmp_uint64 poll;
441 } * volatile polls;
442 volatile kmp_uint64 mask; // is 2**num_polls-1 for mod op
443 kmp_uint64 cleanup_ticket; // thread with cleanup ticket
444 volatile struct kmp_lock_poll * old_polls; // will deallocate old_polls
445 kmp_uint32 num_polls; // must be power of 2
446
447 //
448 // next_ticket it needs to exist in a separate cache line, as it is
449 // invalidated every time a thread takes a new ticket.
450 //
451 KMP_ALIGN_CACHE
452
453 volatile kmp_uint64 next_ticket;
454
455 //
456 // now_serving is used to store our ticket value while we hold the lock.
Alp Toker8f2d3f02014-02-24 10:40:15 +0000457 // It has a slightly different meaning in the DRDPA ticket locks (where
Jim Cownie5e8470a2013-09-27 10:38:44 +0000458 // it is written by the acquiring thread) than it does in the simple
459 // ticket locks (where it is written by the releasing thread).
460 //
461 // Since now_serving is only read an written in the critical section,
462 // it is non-volatile, but it needs to exist on a separate cache line,
463 // as it is invalidated at every lock acquire.
464 //
465 // Likewise, the vars used for nested locks (owner_id and depth_locked)
466 // are only written by the thread owning the lock, so they are put in
467 // this cache line. owner_id is read by other threads, so it must be
468 // declared volatile.
469 //
470 KMP_ALIGN_CACHE
471
472 kmp_uint64 now_serving; // doesn't have to be volatile
473 volatile kmp_uint32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
474 kmp_int32 depth_locked; // depth locked
475 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
476};
477
478typedef struct kmp_base_drdpa_lock kmp_base_drdpa_lock_t;
479
480union KMP_ALIGN_CACHE kmp_drdpa_lock {
481 kmp_base_drdpa_lock_t lk; // This field must be first to allow static initializing. */
482 kmp_lock_pool_t pool;
483 double lk_align; // use worst case alignment
484 char lk_pad[ KMP_PAD( kmp_base_drdpa_lock_t, CACHE_LINE ) ];
485};
486
487typedef union kmp_drdpa_lock kmp_drdpa_lock_t;
488
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000489extern int __kmp_acquire_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000490extern int __kmp_test_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000491extern int __kmp_release_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000492extern void __kmp_init_drdpa_lock( kmp_drdpa_lock_t *lck );
493extern void __kmp_destroy_drdpa_lock( kmp_drdpa_lock_t *lck );
494
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000495extern int __kmp_acquire_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000496extern int __kmp_test_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000497extern int __kmp_release_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000498extern void __kmp_init_nested_drdpa_lock( kmp_drdpa_lock_t *lck );
499extern void __kmp_destroy_nested_drdpa_lock( kmp_drdpa_lock_t *lck );
500
501
502// ============================================================================
503// Lock purposes.
504// ============================================================================
505
506
507// ----------------------------------------------------------------------------
508// Bootstrap locks.
509// ----------------------------------------------------------------------------
510
511// Bootstrap locks -- very few locks used at library initialization time.
512// Bootstrap locks are currently implemented as ticket locks.
513// They could also be implemented as test and set lock, but cannot be
514// implemented with other lock kinds as they require gtids which are not
515// available at initialization time.
516
517typedef kmp_ticket_lock_t kmp_bootstrap_lock_t;
518
519#define KMP_BOOTSTRAP_LOCK_INITIALIZER( lock ) KMP_TICKET_LOCK_INITIALIZER( (lock) )
520
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000521static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000522__kmp_acquire_bootstrap_lock( kmp_bootstrap_lock_t *lck )
523{
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000524 return __kmp_acquire_ticket_lock( lck, KMP_GTID_DNE );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000525}
526
Jim Cownie181b4bb2013-12-23 17:28:57 +0000527static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000528__kmp_test_bootstrap_lock( kmp_bootstrap_lock_t *lck )
529{
530 return __kmp_test_ticket_lock( lck, KMP_GTID_DNE );
531}
532
Jim Cownie181b4bb2013-12-23 17:28:57 +0000533static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000534__kmp_release_bootstrap_lock( kmp_bootstrap_lock_t *lck )
535{
536 __kmp_release_ticket_lock( lck, KMP_GTID_DNE );
537}
538
Jim Cownie181b4bb2013-12-23 17:28:57 +0000539static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000540__kmp_init_bootstrap_lock( kmp_bootstrap_lock_t *lck )
541{
542 __kmp_init_ticket_lock( lck );
543}
544
Jim Cownie181b4bb2013-12-23 17:28:57 +0000545static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000546__kmp_destroy_bootstrap_lock( kmp_bootstrap_lock_t *lck )
547{
548 __kmp_destroy_ticket_lock( lck );
549}
550
551
552// ----------------------------------------------------------------------------
553// Internal RTL locks.
554// ----------------------------------------------------------------------------
555
556//
557// Internal RTL locks are also implemented as ticket locks, for now.
558//
559// FIXME - We should go through and figure out which lock kind works best for
Jim Cownie3051f972014-08-07 10:12:54 +0000560// each internal lock, and use the type declaration and function calls for
Jim Cownie5e8470a2013-09-27 10:38:44 +0000561// that explicit lock kind (and get rid of this section).
562//
563
564typedef kmp_ticket_lock_t kmp_lock_t;
565
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000566static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000567__kmp_acquire_lock( kmp_lock_t *lck, kmp_int32 gtid )
568{
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000569 return __kmp_acquire_ticket_lock( lck, gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000570}
571
Jim Cownie181b4bb2013-12-23 17:28:57 +0000572static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000573__kmp_test_lock( kmp_lock_t *lck, kmp_int32 gtid )
574{
575 return __kmp_test_ticket_lock( lck, gtid );
576}
577
Jim Cownie181b4bb2013-12-23 17:28:57 +0000578static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000579__kmp_release_lock( kmp_lock_t *lck, kmp_int32 gtid )
580{
581 __kmp_release_ticket_lock( lck, gtid );
582}
583
Jim Cownie181b4bb2013-12-23 17:28:57 +0000584static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000585__kmp_init_lock( kmp_lock_t *lck )
586{
587 __kmp_init_ticket_lock( lck );
588}
589
Jim Cownie181b4bb2013-12-23 17:28:57 +0000590static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000591__kmp_destroy_lock( kmp_lock_t *lck )
592{
593 __kmp_destroy_ticket_lock( lck );
594}
595
596
597// ----------------------------------------------------------------------------
598// User locks.
599// ----------------------------------------------------------------------------
600
601//
602// Do not allocate objects of type union kmp_user_lock!!!
603// This will waste space unless __kmp_user_lock_kind == lk_drdpa.
604// Instead, check the value of __kmp_user_lock_kind and allocate objects of
605// the type of the appropriate union member, and cast their addresses to
606// kmp_user_lock_p.
607//
608
609enum kmp_lock_kind {
610 lk_default = 0,
611 lk_tas,
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000612#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000613 lk_futex,
614#endif
Jonathan Peytondae13d82015-12-11 21:57:06 +0000615#if KMP_USE_DYNAMIC_LOCK && KMP_USE_TSX
616 lk_hle,
617 lk_rtm,
618#endif
Jim Cownie5e8470a2013-09-27 10:38:44 +0000619 lk_ticket,
620 lk_queuing,
621 lk_drdpa,
622#if KMP_USE_ADAPTIVE_LOCKS
623 lk_adaptive
624#endif // KMP_USE_ADAPTIVE_LOCKS
625};
626
627typedef enum kmp_lock_kind kmp_lock_kind_t;
628
629extern kmp_lock_kind_t __kmp_user_lock_kind;
630
631union kmp_user_lock {
632 kmp_tas_lock_t tas;
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000633#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000634 kmp_futex_lock_t futex;
635#endif
636 kmp_ticket_lock_t ticket;
637 kmp_queuing_lock_t queuing;
638 kmp_drdpa_lock_t drdpa;
639#if KMP_USE_ADAPTIVE_LOCKS
640 kmp_adaptive_lock_t adaptive;
641#endif // KMP_USE_ADAPTIVE_LOCKS
642 kmp_lock_pool_t pool;
643};
644
645typedef union kmp_user_lock *kmp_user_lock_p;
646
Andrey Churbanov5c56fb52015-02-20 18:05:17 +0000647#if ! KMP_USE_DYNAMIC_LOCK
648
Jim Cownie5e8470a2013-09-27 10:38:44 +0000649extern size_t __kmp_base_user_lock_size;
650extern size_t __kmp_user_lock_size;
651
652extern kmp_int32 ( *__kmp_get_user_lock_owner_ )( kmp_user_lock_p lck );
653
Jim Cownie181b4bb2013-12-23 17:28:57 +0000654static inline kmp_int32
Jim Cownie5e8470a2013-09-27 10:38:44 +0000655__kmp_get_user_lock_owner( kmp_user_lock_p lck )
656{
657 KMP_DEBUG_ASSERT( __kmp_get_user_lock_owner_ != NULL );
658 return ( *__kmp_get_user_lock_owner_ )( lck );
659}
660
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000661extern int ( *__kmp_acquire_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000662
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000663#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000664
665#define __kmp_acquire_user_lock_with_checks(lck,gtid) \
666 if (__kmp_user_lock_kind == lk_tas) { \
667 if ( __kmp_env_consistency_check ) { \
668 char const * const func = "omp_set_lock"; \
669 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_LOCK_T_SIZE ) \
670 && lck->tas.lk.depth_locked != -1 ) { \
671 KMP_FATAL( LockNestableUsedAsSimple, func ); \
672 } \
673 if ( ( gtid >= 0 ) && ( lck->tas.lk.poll - 1 == gtid ) ) { \
674 KMP_FATAL( LockIsAlreadyOwned, func ); \
675 } \
676 } \
677 if ( ( lck->tas.lk.poll != 0 ) || \
678 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
679 kmp_uint32 spins; \
680 KMP_FSYNC_PREPARE( lck ); \
681 KMP_INIT_YIELD( spins ); \
682 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
683 KMP_YIELD( TRUE ); \
684 } else { \
685 KMP_YIELD_SPIN( spins ); \
686 } \
687 while ( ( lck->tas.lk.poll != 0 ) || \
688 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
689 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
690 KMP_YIELD( TRUE ); \
691 } else { \
692 KMP_YIELD_SPIN( spins ); \
693 } \
694 } \
695 } \
696 KMP_FSYNC_ACQUIRED( lck ); \
697 } else { \
698 KMP_DEBUG_ASSERT( __kmp_acquire_user_lock_with_checks_ != NULL ); \
699 ( *__kmp_acquire_user_lock_with_checks_ )( lck, gtid ); \
700 }
701
702#else
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000703static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000704__kmp_acquire_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
705{
706 KMP_DEBUG_ASSERT( __kmp_acquire_user_lock_with_checks_ != NULL );
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000707 return ( *__kmp_acquire_user_lock_with_checks_ )( lck, gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000708}
709#endif
710
711extern int ( *__kmp_test_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
712
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000713#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000714
715#include "kmp_i18n.h" /* AC: KMP_FATAL definition */
716extern int __kmp_env_consistency_check; /* AC: copy from kmp.h here */
Jim Cownie181b4bb2013-12-23 17:28:57 +0000717static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000718__kmp_test_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
719{
720 if ( __kmp_user_lock_kind == lk_tas ) {
721 if ( __kmp_env_consistency_check ) {
722 char const * const func = "omp_test_lock";
723 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_LOCK_T_SIZE )
724 && lck->tas.lk.depth_locked != -1 ) {
725 KMP_FATAL( LockNestableUsedAsSimple, func );
726 }
727 }
728 return ( ( lck->tas.lk.poll == 0 ) &&
729 KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) );
730 } else {
731 KMP_DEBUG_ASSERT( __kmp_test_user_lock_with_checks_ != NULL );
732 return ( *__kmp_test_user_lock_with_checks_ )( lck, gtid );
733 }
734}
735#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000736static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000737__kmp_test_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
738{
739 KMP_DEBUG_ASSERT( __kmp_test_user_lock_with_checks_ != NULL );
740 return ( *__kmp_test_user_lock_with_checks_ )( lck, gtid );
741}
742#endif
743
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000744extern int ( *__kmp_release_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000745
Jim Cownie181b4bb2013-12-23 17:28:57 +0000746static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000747__kmp_release_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
748{
749 KMP_DEBUG_ASSERT( __kmp_release_user_lock_with_checks_ != NULL );
750 ( *__kmp_release_user_lock_with_checks_ ) ( lck, gtid );
751}
752
753extern void ( *__kmp_init_user_lock_with_checks_ )( kmp_user_lock_p lck );
754
Jim Cownie181b4bb2013-12-23 17:28:57 +0000755static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000756__kmp_init_user_lock_with_checks( kmp_user_lock_p lck )
757{
758 KMP_DEBUG_ASSERT( __kmp_init_user_lock_with_checks_ != NULL );
759 ( *__kmp_init_user_lock_with_checks_ )( lck );
760}
761
762//
763// We need a non-checking version of destroy lock for when the RTL is
764// doing the cleanup as it can't always tell if the lock is nested or not.
765//
766extern void ( *__kmp_destroy_user_lock_ )( kmp_user_lock_p lck );
767
Jim Cownie181b4bb2013-12-23 17:28:57 +0000768static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000769__kmp_destroy_user_lock( kmp_user_lock_p lck )
770{
771 KMP_DEBUG_ASSERT( __kmp_destroy_user_lock_ != NULL );
772 ( *__kmp_destroy_user_lock_ )( lck );
773}
774
775extern void ( *__kmp_destroy_user_lock_with_checks_ )( kmp_user_lock_p lck );
776
Jim Cownie181b4bb2013-12-23 17:28:57 +0000777static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000778__kmp_destroy_user_lock_with_checks( kmp_user_lock_p lck )
779{
780 KMP_DEBUG_ASSERT( __kmp_destroy_user_lock_with_checks_ != NULL );
781 ( *__kmp_destroy_user_lock_with_checks_ )( lck );
782}
783
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000784extern int ( *__kmp_acquire_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000785
786#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
787
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000788#define __kmp_acquire_nested_user_lock_with_checks(lck,gtid,depth) \
Jim Cownie5e8470a2013-09-27 10:38:44 +0000789 if (__kmp_user_lock_kind == lk_tas) { \
790 if ( __kmp_env_consistency_check ) { \
791 char const * const func = "omp_set_nest_lock"; \
792 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_NEST_LOCK_T_SIZE ) \
793 && lck->tas.lk.depth_locked == -1 ) { \
794 KMP_FATAL( LockSimpleUsedAsNestable, func ); \
795 } \
796 } \
797 if ( lck->tas.lk.poll - 1 == gtid ) { \
798 lck->tas.lk.depth_locked += 1; \
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000799 *depth = KMP_LOCK_ACQUIRED_NEXT; \
Jim Cownie5e8470a2013-09-27 10:38:44 +0000800 } else { \
801 if ( ( lck->tas.lk.poll != 0 ) || \
802 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
803 kmp_uint32 spins; \
804 KMP_FSYNC_PREPARE( lck ); \
805 KMP_INIT_YIELD( spins ); \
806 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
807 KMP_YIELD( TRUE ); \
808 } else { \
809 KMP_YIELD_SPIN( spins ); \
810 } \
811 while ( ( lck->tas.lk.poll != 0 ) || \
812 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
813 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
814 KMP_YIELD( TRUE ); \
815 } else { \
816 KMP_YIELD_SPIN( spins ); \
817 } \
818 } \
819 } \
820 lck->tas.lk.depth_locked = 1; \
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000821 *depth = KMP_LOCK_ACQUIRED_FIRST; \
Jim Cownie5e8470a2013-09-27 10:38:44 +0000822 } \
823 KMP_FSYNC_ACQUIRED( lck ); \
824 } else { \
825 KMP_DEBUG_ASSERT( __kmp_acquire_nested_user_lock_with_checks_ != NULL ); \
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000826 *depth = ( *__kmp_acquire_nested_user_lock_with_checks_ )( lck, gtid ); \
Jim Cownie5e8470a2013-09-27 10:38:44 +0000827 }
828
829#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000830static inline void
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000831__kmp_acquire_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid, int* depth )
Jim Cownie5e8470a2013-09-27 10:38:44 +0000832{
833 KMP_DEBUG_ASSERT( __kmp_acquire_nested_user_lock_with_checks_ != NULL );
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000834 *depth = ( *__kmp_acquire_nested_user_lock_with_checks_ )( lck, gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000835}
836#endif
837
838extern int ( *__kmp_test_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
839
840#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
Jim Cownie181b4bb2013-12-23 17:28:57 +0000841static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000842__kmp_test_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
843{
844 if ( __kmp_user_lock_kind == lk_tas ) {
845 int retval;
846 if ( __kmp_env_consistency_check ) {
847 char const * const func = "omp_test_nest_lock";
848 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_NEST_LOCK_T_SIZE )
849 && lck->tas.lk.depth_locked == -1 ) {
850 KMP_FATAL( LockSimpleUsedAsNestable, func );
851 }
852 }
853 KMP_DEBUG_ASSERT( gtid >= 0 );
854 if ( lck->tas.lk.poll - 1 == gtid ) { /* __kmp_get_tas_lock_owner( lck ) == gtid */
855 return ++lck->tas.lk.depth_locked; /* same owner, depth increased */
856 }
857 retval = ( ( lck->tas.lk.poll == 0 ) &&
858 KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) );
859 if ( retval ) {
860 KMP_MB();
861 lck->tas.lk.depth_locked = 1;
862 }
863 return retval;
864 } else {
865 KMP_DEBUG_ASSERT( __kmp_test_nested_user_lock_with_checks_ != NULL );
866 return ( *__kmp_test_nested_user_lock_with_checks_ )( lck, gtid );
867 }
868}
869#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000870static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000871__kmp_test_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
872{
873 KMP_DEBUG_ASSERT( __kmp_test_nested_user_lock_with_checks_ != NULL );
874 return ( *__kmp_test_nested_user_lock_with_checks_ )( lck, gtid );
875}
876#endif
877
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000878extern int ( *__kmp_release_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000879
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000880static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000881__kmp_release_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
882{
883 KMP_DEBUG_ASSERT( __kmp_release_nested_user_lock_with_checks_ != NULL );
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000884 return ( *__kmp_release_nested_user_lock_with_checks_ )( lck, gtid );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000885}
886
887extern void ( *__kmp_init_nested_user_lock_with_checks_ )( kmp_user_lock_p lck );
888
Jim Cownie181b4bb2013-12-23 17:28:57 +0000889static inline void __kmp_init_nested_user_lock_with_checks( kmp_user_lock_p lck )
Jim Cownie5e8470a2013-09-27 10:38:44 +0000890{
891 KMP_DEBUG_ASSERT( __kmp_init_nested_user_lock_with_checks_ != NULL );
892 ( *__kmp_init_nested_user_lock_with_checks_ )( lck );
893}
894
895extern void ( *__kmp_destroy_nested_user_lock_with_checks_ )( kmp_user_lock_p lck );
896
Jim Cownie181b4bb2013-12-23 17:28:57 +0000897static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000898__kmp_destroy_nested_user_lock_with_checks( kmp_user_lock_p lck )
899{
900 KMP_DEBUG_ASSERT( __kmp_destroy_nested_user_lock_with_checks_ != NULL );
901 ( *__kmp_destroy_nested_user_lock_with_checks_ )( lck );
902}
903
904//
905// user lock functions which do not necessarily exist for all lock kinds.
906//
907// The "set" functions usually have wrapper routines that check for a NULL set
908// function pointer and call it if non-NULL.
909//
910// In some cases, it makes sense to have a "get" wrapper function check for a
911// NULL get function pointer and return NULL / invalid value / error code if
912// the function pointer is NULL.
913//
914// In other cases, the calling code really should differentiate between an
915// unimplemented function and one that is implemented but returning NULL /
916// invalied value. If this is the case, no get function wrapper exists.
917//
918
919extern int ( *__kmp_is_user_lock_initialized_ )( kmp_user_lock_p lck );
920
921// no set function; fields set durining local allocation
922
923extern const ident_t * ( *__kmp_get_user_lock_location_ )( kmp_user_lock_p lck );
924
Jim Cownie181b4bb2013-12-23 17:28:57 +0000925static inline const ident_t *
Jim Cownie5e8470a2013-09-27 10:38:44 +0000926__kmp_get_user_lock_location( kmp_user_lock_p lck )
927{
928 if ( __kmp_get_user_lock_location_ != NULL ) {
929 return ( *__kmp_get_user_lock_location_ )( lck );
930 }
931 else {
932 return NULL;
933 }
934}
935
936extern void ( *__kmp_set_user_lock_location_ )( kmp_user_lock_p lck, const ident_t *loc );
937
Jim Cownie181b4bb2013-12-23 17:28:57 +0000938static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000939__kmp_set_user_lock_location( kmp_user_lock_p lck, const ident_t *loc )
940{
941 if ( __kmp_set_user_lock_location_ != NULL ) {
942 ( *__kmp_set_user_lock_location_ )( lck, loc );
943 }
944}
945
946extern kmp_lock_flags_t ( *__kmp_get_user_lock_flags_ )( kmp_user_lock_p lck );
947
948extern void ( *__kmp_set_user_lock_flags_ )( kmp_user_lock_p lck, kmp_lock_flags_t flags );
949
Jim Cownie181b4bb2013-12-23 17:28:57 +0000950static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000951__kmp_set_user_lock_flags( kmp_user_lock_p lck, kmp_lock_flags_t flags )
952{
953 if ( __kmp_set_user_lock_flags_ != NULL ) {
954 ( *__kmp_set_user_lock_flags_ )( lck, flags );
955 }
956}
957
958//
959// The fuction which sets up all of the vtbl pointers for kmp_user_lock_t.
960//
961extern void __kmp_set_user_lock_vptrs( kmp_lock_kind_t user_lock_kind );
962
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000963//
964// Macros for binding user lock functions.
965//
966#define KMP_BIND_USER_LOCK_TEMPLATE(nest, kind, suffix) { \
Jonathan Peyton0e6d4572015-10-16 16:52:58 +0000967 __kmp_acquire##nest##user_lock_with_checks_ = ( int (*)( kmp_user_lock_p, kmp_int32 ) ) \
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000968 __kmp_acquire##nest##kind##_##suffix; \
Andrey Churbanov8d09fac2015-04-29 15:52:19 +0000969 __kmp_release##nest##user_lock_with_checks_ = ( int (*)( kmp_user_lock_p, kmp_int32 ) ) \
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000970 __kmp_release##nest##kind##_##suffix; \
971 __kmp_test##nest##user_lock_with_checks_ = ( int (*)( kmp_user_lock_p, kmp_int32 ) ) \
972 __kmp_test##nest##kind##_##suffix; \
973 __kmp_init##nest##user_lock_with_checks_ = ( void (*)( kmp_user_lock_p ) ) \
974 __kmp_init##nest##kind##_##suffix; \
975 __kmp_destroy##nest##user_lock_with_checks_ = ( void (*)( kmp_user_lock_p ) ) \
976 __kmp_destroy##nest##kind##_##suffix; \
977}
Jim Cownie5e8470a2013-09-27 10:38:44 +0000978
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000979#define KMP_BIND_USER_LOCK(kind) KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock)
980#define KMP_BIND_USER_LOCK_WITH_CHECKS(kind) KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock_with_checks)
981#define KMP_BIND_NESTED_USER_LOCK(kind) KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock)
982#define KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(kind) KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock_with_checks)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000983
984// ----------------------------------------------------------------------------
985// User lock table & lock allocation
986// ----------------------------------------------------------------------------
987
988/*
989 On 64-bit Linux* OS (and OS X*) GNU compiler allocates only 4 bytems memory for lock variable, which
990 is not enough to store a pointer, so we have to use lock indexes instead of pointers and
991 maintain lock table to map indexes to pointers.
992
993
994 Note: The first element of the table is not a pointer to lock! It is a pointer to previously
995 allocated table (or NULL if it is the first table).
996
997 Usage:
998
999 if ( OMP_LOCK_T_SIZE < sizeof( <lock> ) ) { // or OMP_NEST_LOCK_T_SIZE
1000 Lock table is fully utilized. User locks are indexes, so table is
1001 used on user lock operation.
1002 Note: it may be the case (lin_32) that we don't need to use a lock
1003 table for regular locks, but do need the table for nested locks.
1004 }
1005 else {
1006 Lock table initialized but not actually used.
1007 }
1008*/
1009
1010struct kmp_lock_table {
1011 kmp_lock_index_t used; // Number of used elements
1012 kmp_lock_index_t allocated; // Number of allocated elements
1013 kmp_user_lock_p * table; // Lock table.
1014};
1015
1016typedef struct kmp_lock_table kmp_lock_table_t;
1017
1018extern kmp_lock_table_t __kmp_user_lock_table;
1019extern kmp_user_lock_p __kmp_lock_pool;
1020
1021struct kmp_block_of_locks {
1022 struct kmp_block_of_locks * next_block;
1023 void * locks;
1024};
1025
1026typedef struct kmp_block_of_locks kmp_block_of_locks_t;
1027
1028extern kmp_block_of_locks_t *__kmp_lock_blocks;
1029extern int __kmp_num_locks_in_block;
1030
Jim Cownie181b4bb2013-12-23 17:28:57 +00001031extern kmp_user_lock_p __kmp_user_lock_allocate( void **user_lock, kmp_int32 gtid, kmp_lock_flags_t flags );
Jim Cownie5e8470a2013-09-27 10:38:44 +00001032extern void __kmp_user_lock_free( void **user_lock, kmp_int32 gtid, kmp_user_lock_p lck );
1033extern kmp_user_lock_p __kmp_lookup_user_lock( void **user_lock, char const *func );
1034extern void __kmp_cleanup_user_locks();
1035
1036#define KMP_CHECK_USER_LOCK_INIT() \
1037 { \
1038 if ( ! TCR_4( __kmp_init_user_locks ) ) { \
1039 __kmp_acquire_bootstrap_lock( &__kmp_initz_lock ); \
1040 if ( ! TCR_4( __kmp_init_user_locks ) ) { \
1041 TCW_4( __kmp_init_user_locks, TRUE ); \
1042 } \
1043 __kmp_release_bootstrap_lock( &__kmp_initz_lock ); \
1044 } \
1045 }
1046
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001047#endif // KMP_USE_DYNAMIC_LOCK
1048
Jim Cownie5e8470a2013-09-27 10:38:44 +00001049#undef KMP_PAD
1050#undef KMP_GTID_DNE
1051
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001052#if KMP_USE_DYNAMIC_LOCK
1053
Jonathan Peytonb87b5812015-12-11 22:04:05 +00001054//
1055// KMP_USE_DYNAMIC_LOCK enables dynamic dispatch of lock functions without breaking the current
1056// compatibility. Essential functionality of this new code is dynamic dispatch, but it also
1057// implements (or enables implementation of) hinted user lock and critical section which will be
1058// part of OMP 4.1 soon.
1059//
1060// Lock type can be decided at creation time (i.e., lock initialization), and subsequent lock
1061// function call on the created lock object requires type extraction and call through jump table
1062// using the extracted type. This type information is stored in two different ways depending on
1063// the size of the lock object, and we differentiate lock types by this size requirement - direct
1064// and indirect locks.
1065//
1066// Direct locks:
1067// A direct lock object fits into the space created by the compiler for an omp_lock_t object, and
1068// TAS/Futex lock falls into this category. We use low one byte of the lock object as the storage
1069// for the lock type, and appropriate bit operation is required to access the data meaningful to
1070// the lock algorithms. Also, to differentiate direct lock from indirect lock, 1 is written to LSB
1071// of the lock object. The newly introduced "hle" lock is also a direct lock.
1072//
1073// Indirect locks:
1074// An indirect lock object requires more space than the compiler-generated space, and it should be
1075// allocated from heap. Depending on the size of the compiler-generated space for the lock (i.e.,
1076// size of omp_lock_t), this omp_lock_t object stores either the address of the heap-allocated
1077// indirect lock (void * fits in the object) or an index to the indirect lock table entry that
1078// holds the address. Ticket/Queuing/DRDPA/Adaptive lock falls into this category, and the newly
1079// introduced "rtm" lock is also an indirect lock which was implemented on top of the Queuing lock.
1080// When the omp_lock_t object holds an index (not lock address), 0 is written to LSB to
1081// differentiate the lock from a direct lock, and the remaining part is the actual index to the
1082// indirect lock table.
1083//
1084
1085#include <stdint.h> // for uintptr_t
1086
Jonathan Peytondae13d82015-12-11 21:57:06 +00001087// Shortcuts
1088#define KMP_USE_FUTEX (KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64))
1089#define KMP_USE_INLINED_TAS (KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)) && 1
1090#define KMP_USE_INLINED_FUTEX KMP_USE_FUTEX && 0
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001091
1092// List of lock definitions; all nested locks are indirect locks.
1093// hle lock is xchg lock prefixed with XACQUIRE/XRELEASE.
1094// All nested locks are indirect lock types.
Jonathan Peytondae13d82015-12-11 21:57:06 +00001095#if KMP_USE_TSX
1096# if KMP_USE_FUTEX
1097# define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a) m(hle, a)
1098# define KMP_FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) m(rtm, a) \
1099 m(nested_tas, a) m(nested_futex, a) m(nested_ticket, a) \
1100 m(nested_queuing, a) m(nested_drdpa, a)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001101# else
Jonathan Peytondae13d82015-12-11 21:57:06 +00001102# define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(hle, a)
1103# define KMP_FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) m(rtm, a) \
1104 m(nested_tas, a) m(nested_ticket, a) \
1105 m(nested_queuing, a) m(nested_drdpa, a)
1106# endif // KMP_USE_FUTEX
1107# define KMP_LAST_D_LOCK lockseq_hle
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001108#else
Jonathan Peytondae13d82015-12-11 21:57:06 +00001109# if KMP_USE_FUTEX
1110# define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a)
1111# define KMP_FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(drdpa, a) \
1112 m(nested_tas, a) m(nested_futex, a) m(nested_ticket, a) \
1113 m(nested_queuing, a) m(nested_drdpa, a)
1114# define KMP_LAST_D_LOCK lockseq_futex
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001115# else
Jonathan Peytondae13d82015-12-11 21:57:06 +00001116# define KMP_FOREACH_D_LOCK(m, a) m(tas, a)
1117# define KMP_FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(drdpa, a) \
1118 m(nested_tas, a) m(nested_ticket, a) \
1119 m(nested_queuing, a) m(nested_drdpa, a)
Jonathan Peytona03533d2015-12-11 21:49:08 +00001120# define KMP_LAST_D_LOCK lockseq_tas
Jonathan Peytondae13d82015-12-11 21:57:06 +00001121# endif // KMP_USE_FUTEX
1122#endif // KMP_USE_TSX
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001123
1124// Information used in dynamic dispatch
Jonathan Peytona03533d2015-12-11 21:49:08 +00001125#define KMP_LOCK_SHIFT 8 // number of low bits to be used as tag for direct locks
1126#define KMP_FIRST_D_LOCK lockseq_tas
1127#define KMP_FIRST_I_LOCK lockseq_ticket
1128#define KMP_LAST_I_LOCK lockseq_nested_drdpa
1129#define KMP_NUM_I_LOCKS (locktag_nested_drdpa+1) // number of indirect lock types
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001130
1131// Base type for dynamic locks.
1132typedef kmp_uint32 kmp_dyna_lock_t;
1133
1134// Lock sequence that enumerates all lock kinds.
1135// Always make this enumeration consistent with kmp_lockseq_t in the include directory.
1136typedef enum {
1137 lockseq_indirect = 0,
1138#define expand_seq(l,a) lockseq_##l,
Jonathan Peytona03533d2015-12-11 21:49:08 +00001139 KMP_FOREACH_D_LOCK(expand_seq, 0)
1140 KMP_FOREACH_I_LOCK(expand_seq, 0)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001141#undef expand_seq
1142} kmp_dyna_lockseq_t;
1143
1144// Enumerates indirect lock tags.
1145typedef enum {
1146#define expand_tag(l,a) locktag_##l,
Jonathan Peytona03533d2015-12-11 21:49:08 +00001147 KMP_FOREACH_I_LOCK(expand_tag, 0)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001148#undef expand_tag
1149} kmp_indirect_locktag_t;
1150
1151// Utility macros that extract information from lock sequences.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001152#define KMP_IS_D_LOCK(seq) ((seq) >= KMP_FIRST_D_LOCK && (seq) <= KMP_LAST_D_LOCK)
1153#define KMP_IS_I_LOCK(seq) ((seq) >= KMP_FIRST_I_LOCK && (seq) <= KMP_LAST_I_LOCK)
1154#define KMP_GET_I_TAG(seq) (kmp_indirect_locktag_t)((seq) - KMP_FIRST_I_LOCK)
1155#define KMP_GET_D_TAG(seq) ((seq)<<1 | 1)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001156
1157// Enumerates direct lock tags starting from indirect tag.
1158typedef enum {
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001159#define expand_tag(l,a) locktag_##l = KMP_GET_D_TAG(lockseq_##l),
Jonathan Peytona03533d2015-12-11 21:49:08 +00001160 KMP_FOREACH_D_LOCK(expand_tag, 0)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001161#undef expand_tag
1162} kmp_direct_locktag_t;
1163
1164// Indirect lock type
1165typedef struct {
1166 kmp_user_lock_p lock;
1167 kmp_indirect_locktag_t type;
1168} kmp_indirect_lock_t;
1169
1170// Function tables for direct locks. Set/unset/test differentiate functions with/without consistency checking.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001171extern void (*__kmp_direct_init[])(kmp_dyna_lock_t *, kmp_dyna_lockseq_t);
1172extern void (*__kmp_direct_destroy[])(kmp_dyna_lock_t *);
1173extern void (*(*__kmp_direct_set))(kmp_dyna_lock_t *, kmp_int32);
1174extern int (*(*__kmp_direct_unset))(kmp_dyna_lock_t *, kmp_int32);
1175extern int (*(*__kmp_direct_test))(kmp_dyna_lock_t *, kmp_int32);
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001176
1177// Function tables for indirect locks. Set/unset/test differentiate functions with/withuot consistency checking.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001178extern void (*__kmp_indirect_init[])(kmp_user_lock_p);
1179extern void (*__kmp_indirect_destroy[])(kmp_user_lock_p);
1180extern void (*(*__kmp_indirect_set))(kmp_user_lock_p, kmp_int32);
1181extern int (*(*__kmp_indirect_unset))(kmp_user_lock_p, kmp_int32);
1182extern int (*(*__kmp_indirect_test))(kmp_user_lock_p, kmp_int32);
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001183
1184// Extracts direct lock tag from a user lock pointer
Jonathan Peytona03533d2015-12-11 21:49:08 +00001185#define KMP_EXTRACT_D_TAG(l) (*((kmp_dyna_lock_t *)(l)) & ((1<<KMP_LOCK_SHIFT)-1) & -(*((kmp_dyna_lock_t *)(l)) & 1))
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001186
1187// Extracts indirect lock index from a user lock pointer
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001188#define KMP_EXTRACT_I_INDEX(l) (*(kmp_lock_index_t *)(l) >> 1)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001189
1190// Returns function pointer to the direct lock function with l (kmp_dyna_lock_t *) and op (operation type).
Jonathan Peytona03533d2015-12-11 21:49:08 +00001191#define KMP_D_LOCK_FUNC(l, op) __kmp_direct_##op[KMP_EXTRACT_D_TAG(l)]
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001192
1193// Returns function pointer to the indirect lock function with l (kmp_indirect_lock_t *) and op (operation type).
Jonathan Peytona03533d2015-12-11 21:49:08 +00001194#define KMP_I_LOCK_FUNC(l, op) __kmp_indirect_##op[((kmp_indirect_lock_t *)(l))->type]
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001195
1196// Initializes a direct lock with the given lock pointer and lock sequence.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001197#define KMP_INIT_D_LOCK(l, seq) __kmp_direct_init[KMP_GET_D_TAG(seq)]((kmp_dyna_lock_t *)l, seq)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001198
1199// Initializes an indirect lock with the given lock pointer and lock sequence.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001200#define KMP_INIT_I_LOCK(l, seq) __kmp_direct_init[0]((kmp_dyna_lock_t *)(l), seq)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001201
1202// Returns "free" lock value for the given lock type.
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001203#define KMP_LOCK_FREE(type) (locktag_##type)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001204
1205// Returns "busy" lock value for the given lock teyp.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001206#define KMP_LOCK_BUSY(v, type) ((v)<<KMP_LOCK_SHIFT | locktag_##type)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001207
1208// Returns lock value after removing (shifting) lock tag.
Jonathan Peytona03533d2015-12-11 21:49:08 +00001209#define KMP_LOCK_STRIP(v) ((v)>>KMP_LOCK_SHIFT)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001210
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001211// Initializes global states and data structures for managing dynamic user locks.
1212extern void __kmp_init_dynamic_user_locks();
1213
1214// Allocates and returns an indirect lock with the given indirect lock tag.
1215extern kmp_indirect_lock_t * __kmp_allocate_indirect_lock(void **, kmp_int32, kmp_indirect_locktag_t);
1216
1217// Cleans up global states and data structures for managing dynamic user locks.
1218extern void __kmp_cleanup_indirect_user_locks();
1219
Jonathan Peyton61118492016-05-20 19:03:38 +00001220// Default user lock sequence when not using hinted locks.
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001221extern kmp_dyna_lockseq_t __kmp_user_lock_seq;
1222
1223// Jump table for "set lock location", available only for indirect locks.
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001224extern void (*__kmp_indirect_set_location[KMP_NUM_I_LOCKS])(kmp_user_lock_p, const ident_t *);
1225#define KMP_SET_I_LOCK_LOCATION(lck, loc) { \
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001226 if (__kmp_indirect_set_location[(lck)->type] != NULL) \
1227 __kmp_indirect_set_location[(lck)->type]((lck)->lock, loc); \
1228}
1229
1230// Jump table for "set lock flags", available only for indirect locks.
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001231extern void (*__kmp_indirect_set_flags[KMP_NUM_I_LOCKS])(kmp_user_lock_p, kmp_lock_flags_t);
1232#define KMP_SET_I_LOCK_FLAGS(lck, flag) { \
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001233 if (__kmp_indirect_set_flags[(lck)->type] != NULL) \
1234 __kmp_indirect_set_flags[(lck)->type]((lck)->lock, flag); \
1235}
1236
1237// Jump table for "get lock location", available only for indirect locks.
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001238extern const ident_t * (*__kmp_indirect_get_location[KMP_NUM_I_LOCKS])(kmp_user_lock_p);
1239#define KMP_GET_I_LOCK_LOCATION(lck) ( __kmp_indirect_get_location[(lck)->type] != NULL \
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001240 ? __kmp_indirect_get_location[(lck)->type]((lck)->lock) \
1241 : NULL )
1242
1243// Jump table for "get lock flags", available only for indirect locks.
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001244extern kmp_lock_flags_t (*__kmp_indirect_get_flags[KMP_NUM_I_LOCKS])(kmp_user_lock_p);
1245#define KMP_GET_I_LOCK_FLAGS(lck) ( __kmp_indirect_get_flags[(lck)->type] != NULL \
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001246 ? __kmp_indirect_get_flags[(lck)->type]((lck)->lock) \
1247 : NULL )
1248
Jonathan Peytondae13d82015-12-11 21:57:06 +00001249#define KMP_I_LOCK_CHUNK 1024 // number of kmp_indirect_lock_t objects to be allocated together
1250
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001251// Lock table for indirect locks.
Jonathan Peytondae13d82015-12-11 21:57:06 +00001252typedef struct kmp_indirect_lock_table {
1253 kmp_indirect_lock_t **table; // blocks of indirect locks allocated
1254 kmp_lock_index_t size; // size of the indirect lock table
1255 kmp_lock_index_t next; // index to the next lock to be allocated
1256} kmp_indirect_lock_table_t;
1257
1258extern kmp_indirect_lock_table_t __kmp_i_lock_table;
1259
1260// Returns the indirect lock associated with the given index.
1261#define KMP_GET_I_LOCK(index) (*(__kmp_i_lock_table.table + (index)/KMP_I_LOCK_CHUNK) + (index)%KMP_I_LOCK_CHUNK)
1262
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001263// Number of locks in a lock block, which is fixed to "1" now.
1264// TODO: No lock block implementation now. If we do support, we need to manage lock block data
1265// structure for each indirect lock type.
1266extern int __kmp_num_locks_in_block;
1267
1268// Fast lock table lookup without consistency checking
Jonathan Peytondae13d82015-12-11 21:57:06 +00001269#define KMP_LOOKUP_I_LOCK(l) ( (OMP_LOCK_T_SIZE < sizeof(void *)) \
1270 ? KMP_GET_I_LOCK(KMP_EXTRACT_I_INDEX(l)) \
1271 : *((kmp_indirect_lock_t **)(l)) )
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001272
1273// Used once in kmp_error.c
1274extern kmp_int32
1275__kmp_get_user_lock_owner(kmp_user_lock_p, kmp_uint32);
1276
1277#else // KMP_USE_DYNAMIC_LOCK
1278
Jonathan Peytonf2d119f2015-12-03 19:37:20 +00001279# define KMP_LOCK_BUSY(v, type) (v)
1280# define KMP_LOCK_FREE(type) 0
1281# define KMP_LOCK_STRIP(v) (v)
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001282
1283#endif // KMP_USE_DYNAMIC_LOCK
1284
Jonathan Peyton377aa402016-04-14 16:00:37 +00001285// data structure for using backoff within spin locks.
1286typedef struct {
1287 kmp_uint32 step; // current step
1288 kmp_uint32 max_backoff; // upper bound of outer delay loop
1289 kmp_uint32 min_tick; // size of inner delay loop in ticks (machine-dependent)
1290} kmp_backoff_t;
1291
1292// Runtime's default backoff parameters
1293extern kmp_backoff_t __kmp_spin_backoff_params;
1294
1295// Backoff function
1296extern void __kmp_spin_backoff(kmp_backoff_t *);
1297
Jim Cownie5e8470a2013-09-27 10:38:44 +00001298#ifdef __cplusplus
1299} // extern "C"
1300#endif // __cplusplus
1301
1302#endif /* KMP_LOCK_H */
1303