xref: /freebsd/contrib/llvm-project/openmp/runtime/src/kmp_lock.h (revision 489b1cf2ecf5b9b4a394857987014bfb09067726)
10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric  * kmp_lock.h -- lock header file
30b57cec5SDimitry Andric  */
40b57cec5SDimitry Andric 
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef KMP_LOCK_H
140b57cec5SDimitry Andric #define KMP_LOCK_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include <limits.h> // CHAR_BIT
170b57cec5SDimitry Andric #include <stddef.h> // offsetof
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "kmp_debug.h"
200b57cec5SDimitry Andric #include "kmp_os.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #ifdef __cplusplus
230b57cec5SDimitry Andric #include <atomic>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric extern "C" {
260b57cec5SDimitry Andric #endif // __cplusplus
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric // ----------------------------------------------------------------------------
290b57cec5SDimitry Andric // Have to copy these definitions from kmp.h because kmp.h cannot be included
300b57cec5SDimitry Andric // due to circular dependencies.  Will undef these at end of file.
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric #define KMP_PAD(type, sz)                                                      \
330b57cec5SDimitry Andric   (sizeof(type) + (sz - ((sizeof(type) - 1) % (sz)) - 1))
340b57cec5SDimitry Andric #define KMP_GTID_DNE (-2)
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric // Forward declaration of ident and ident_t
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric struct ident;
390b57cec5SDimitry Andric typedef struct ident ident_t;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric // End of copied code.
420b57cec5SDimitry Andric // ----------------------------------------------------------------------------
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric // We need to know the size of the area we can assume that the compiler(s)
450b57cec5SDimitry Andric // allocated for obects of type omp_lock_t and omp_nest_lock_t.  The Intel
460b57cec5SDimitry Andric // compiler always allocates a pointer-sized area, as does visual studio.
470b57cec5SDimitry Andric //
480b57cec5SDimitry Andric // gcc however, only allocates 4 bytes for regular locks, even on 64-bit
490b57cec5SDimitry Andric // intel archs.  It allocates at least 8 bytes for nested lock (more on
500b57cec5SDimitry Andric // recent versions), but we are bounded by the pointer-sized chunks that
510b57cec5SDimitry Andric // the Intel compiler allocates.
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric #if KMP_OS_LINUX && defined(KMP_GOMP_COMPAT)
540b57cec5SDimitry Andric #define OMP_LOCK_T_SIZE sizeof(int)
550b57cec5SDimitry Andric #define OMP_NEST_LOCK_T_SIZE sizeof(void *)
560b57cec5SDimitry Andric #else
570b57cec5SDimitry Andric #define OMP_LOCK_T_SIZE sizeof(void *)
580b57cec5SDimitry Andric #define OMP_NEST_LOCK_T_SIZE sizeof(void *)
590b57cec5SDimitry Andric #endif
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric // The Intel compiler allocates a 32-byte chunk for a critical section.
620b57cec5SDimitry Andric // Both gcc and visual studio only allocate enough space for a pointer.
630b57cec5SDimitry Andric // Sometimes we know that the space was allocated by the Intel compiler.
640b57cec5SDimitry Andric #define OMP_CRITICAL_SIZE sizeof(void *)
650b57cec5SDimitry Andric #define INTEL_CRITICAL_SIZE 32
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric // lock flags
680b57cec5SDimitry Andric typedef kmp_uint32 kmp_lock_flags_t;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric #define kmp_lf_critical_section 1
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric // When a lock table is used, the indices are of kmp_lock_index_t
730b57cec5SDimitry Andric typedef kmp_uint32 kmp_lock_index_t;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric // When memory allocated for locks are on the lock pool (free list),
760b57cec5SDimitry Andric // it is treated as structs of this type.
770b57cec5SDimitry Andric struct kmp_lock_pool {
780b57cec5SDimitry Andric   union kmp_user_lock *next;
790b57cec5SDimitry Andric   kmp_lock_index_t index;
800b57cec5SDimitry Andric };
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric typedef struct kmp_lock_pool kmp_lock_pool_t;
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric extern void __kmp_validate_locks(void);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric // ----------------------------------------------------------------------------
870b57cec5SDimitry Andric //  There are 5 lock implementations:
880b57cec5SDimitry Andric //       1. Test and set locks.
890b57cec5SDimitry Andric //       2. futex locks (Linux* OS on x86 and
900b57cec5SDimitry Andric //          Intel(R) Many Integrated Core Architecture)
910b57cec5SDimitry Andric //       3. Ticket (Lamport bakery) locks.
920b57cec5SDimitry Andric //       4. Queuing locks (with separate spin fields).
930b57cec5SDimitry Andric //       5. DRPA (Dynamically Reconfigurable Distributed Polling Area) locks
940b57cec5SDimitry Andric //
950b57cec5SDimitry Andric //   and 3 lock purposes:
960b57cec5SDimitry Andric //       1. Bootstrap locks -- Used for a few locks available at library
970b57cec5SDimitry Andric //       startup-shutdown time.
980b57cec5SDimitry Andric //          These do not require non-negative global thread ID's.
990b57cec5SDimitry Andric //       2. Internal RTL locks -- Used everywhere else in the RTL
1000b57cec5SDimitry Andric //       3. User locks (includes critical sections)
1010b57cec5SDimitry Andric // ----------------------------------------------------------------------------
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric // ============================================================================
1040b57cec5SDimitry Andric // Lock implementations.
1050b57cec5SDimitry Andric //
1060b57cec5SDimitry Andric // Test and set locks.
1070b57cec5SDimitry Andric //
1080b57cec5SDimitry Andric // Non-nested test and set locks differ from the other lock kinds (except
1090b57cec5SDimitry Andric // futex) in that we use the memory allocated by the compiler for the lock,
1100b57cec5SDimitry Andric // rather than a pointer to it.
1110b57cec5SDimitry Andric //
1120b57cec5SDimitry Andric // On lin32, lin_32e, and win_32, the space allocated may be as small as 4
1130b57cec5SDimitry Andric // bytes, so we have to use a lock table for nested locks, and avoid accessing
1140b57cec5SDimitry Andric // the depth_locked field for non-nested locks.
1150b57cec5SDimitry Andric //
1160b57cec5SDimitry Andric // Information normally available to the tools, such as lock location, lock
1170b57cec5SDimitry Andric // usage (normal lock vs. critical section), etc. is not available with test and
1180b57cec5SDimitry Andric // set locks.
1190b57cec5SDimitry Andric // ----------------------------------------------------------------------------
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric struct kmp_base_tas_lock {
1220b57cec5SDimitry Andric   // KMP_LOCK_FREE(tas) => unlocked; locked: (gtid+1) of owning thread
1230b57cec5SDimitry Andric   std::atomic<kmp_int32> poll;
1240b57cec5SDimitry Andric   kmp_int32 depth_locked; // depth locked, for nested locks only
1250b57cec5SDimitry Andric };
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric typedef struct kmp_base_tas_lock kmp_base_tas_lock_t;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric union kmp_tas_lock {
1300b57cec5SDimitry Andric   kmp_base_tas_lock_t lk;
1310b57cec5SDimitry Andric   kmp_lock_pool_t pool; // make certain struct is large enough
1320b57cec5SDimitry Andric   double lk_align; // use worst case alignment; no cache line padding
1330b57cec5SDimitry Andric };
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric typedef union kmp_tas_lock kmp_tas_lock_t;
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric // Static initializer for test and set lock variables. Usage:
1380b57cec5SDimitry Andric //    kmp_tas_lock_t xlock = KMP_TAS_LOCK_INITIALIZER( xlock );
1390b57cec5SDimitry Andric #define KMP_TAS_LOCK_INITIALIZER(lock)                                         \
1400b57cec5SDimitry Andric   {                                                                            \
1410b57cec5SDimitry Andric     { ATOMIC_VAR_INIT(KMP_LOCK_FREE(tas)), 0 }                                 \
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric extern int __kmp_acquire_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
1450b57cec5SDimitry Andric extern int __kmp_test_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
1460b57cec5SDimitry Andric extern int __kmp_release_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
1470b57cec5SDimitry Andric extern void __kmp_init_tas_lock(kmp_tas_lock_t *lck);
1480b57cec5SDimitry Andric extern void __kmp_destroy_tas_lock(kmp_tas_lock_t *lck);
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric extern int __kmp_acquire_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
1510b57cec5SDimitry Andric extern int __kmp_test_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
1520b57cec5SDimitry Andric extern int __kmp_release_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid);
1530b57cec5SDimitry Andric extern void __kmp_init_nested_tas_lock(kmp_tas_lock_t *lck);
1540b57cec5SDimitry Andric extern void __kmp_destroy_nested_tas_lock(kmp_tas_lock_t *lck);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric #define KMP_LOCK_RELEASED 1
1570b57cec5SDimitry Andric #define KMP_LOCK_STILL_HELD 0
1580b57cec5SDimitry Andric #define KMP_LOCK_ACQUIRED_FIRST 1
1590b57cec5SDimitry Andric #define KMP_LOCK_ACQUIRED_NEXT 0
1600b57cec5SDimitry Andric #ifndef KMP_USE_FUTEX
1610b57cec5SDimitry Andric #define KMP_USE_FUTEX                                                          \
1620b57cec5SDimitry Andric   (KMP_OS_LINUX && !KMP_OS_CNK &&                                              \
1630b57cec5SDimitry Andric    (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64))
1640b57cec5SDimitry Andric #endif
1650b57cec5SDimitry Andric #if KMP_USE_FUTEX
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric // ----------------------------------------------------------------------------
1680b57cec5SDimitry Andric // futex locks.  futex locks are only available on Linux* OS.
1690b57cec5SDimitry Andric //
1700b57cec5SDimitry Andric // Like non-nested test and set lock, non-nested futex locks use the memory
1710b57cec5SDimitry Andric // allocated by the compiler for the lock, rather than a pointer to it.
1720b57cec5SDimitry Andric //
1730b57cec5SDimitry Andric // Information normally available to the tools, such as lock location, lock
1740b57cec5SDimitry Andric // usage (normal lock vs. critical section), etc. is not available with test and
1750b57cec5SDimitry Andric // set locks. With non-nested futex locks, the lock owner is not even available.
1760b57cec5SDimitry Andric // ----------------------------------------------------------------------------
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric struct kmp_base_futex_lock {
1790b57cec5SDimitry Andric   volatile kmp_int32 poll; // KMP_LOCK_FREE(futex) => unlocked
1800b57cec5SDimitry Andric   // 2*(gtid+1) of owning thread, 0 if unlocked
1810b57cec5SDimitry Andric   // locked: (gtid+1) of owning thread
1820b57cec5SDimitry Andric   kmp_int32 depth_locked; // depth locked, for nested locks only
1830b57cec5SDimitry Andric };
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric typedef struct kmp_base_futex_lock kmp_base_futex_lock_t;
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric union kmp_futex_lock {
1880b57cec5SDimitry Andric   kmp_base_futex_lock_t lk;
1890b57cec5SDimitry Andric   kmp_lock_pool_t pool; // make certain struct is large enough
1900b57cec5SDimitry Andric   double lk_align; // use worst case alignment
1910b57cec5SDimitry Andric   // no cache line padding
1920b57cec5SDimitry Andric };
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric typedef union kmp_futex_lock kmp_futex_lock_t;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric // Static initializer for futex lock variables. Usage:
1970b57cec5SDimitry Andric //    kmp_futex_lock_t xlock = KMP_FUTEX_LOCK_INITIALIZER( xlock );
1980b57cec5SDimitry Andric #define KMP_FUTEX_LOCK_INITIALIZER(lock)                                       \
1990b57cec5SDimitry Andric   {                                                                            \
2000b57cec5SDimitry Andric     { KMP_LOCK_FREE(futex), 0 }                                                \
2010b57cec5SDimitry Andric   }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric extern int __kmp_acquire_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
2040b57cec5SDimitry Andric extern int __kmp_test_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
2050b57cec5SDimitry Andric extern int __kmp_release_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
2060b57cec5SDimitry Andric extern void __kmp_init_futex_lock(kmp_futex_lock_t *lck);
2070b57cec5SDimitry Andric extern void __kmp_destroy_futex_lock(kmp_futex_lock_t *lck);
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric extern int __kmp_acquire_nested_futex_lock(kmp_futex_lock_t *lck,
2100b57cec5SDimitry Andric                                            kmp_int32 gtid);
2110b57cec5SDimitry Andric extern int __kmp_test_nested_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid);
2120b57cec5SDimitry Andric extern int __kmp_release_nested_futex_lock(kmp_futex_lock_t *lck,
2130b57cec5SDimitry Andric                                            kmp_int32 gtid);
2140b57cec5SDimitry Andric extern void __kmp_init_nested_futex_lock(kmp_futex_lock_t *lck);
2150b57cec5SDimitry Andric extern void __kmp_destroy_nested_futex_lock(kmp_futex_lock_t *lck);
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric #endif // KMP_USE_FUTEX
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric // ----------------------------------------------------------------------------
2200b57cec5SDimitry Andric // Ticket locks.
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric #ifdef __cplusplus
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric #ifdef _MSC_VER
2250b57cec5SDimitry Andric // MSVC won't allow use of std::atomic<> in a union since it has non-trivial
2260b57cec5SDimitry Andric // copy constructor.
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric struct kmp_base_ticket_lock {
2290b57cec5SDimitry Andric   // `initialized' must be the first entry in the lock data structure!
2300b57cec5SDimitry Andric   std::atomic_bool initialized;
2310b57cec5SDimitry Andric   volatile union kmp_ticket_lock *self; // points to the lock union
2320b57cec5SDimitry Andric   ident_t const *location; // Source code location of omp_init_lock().
2330b57cec5SDimitry Andric   std::atomic_uint
2340b57cec5SDimitry Andric       next_ticket; // ticket number to give to next thread which acquires
2350b57cec5SDimitry Andric   std::atomic_uint now_serving; // ticket number for thread which holds the lock
2360b57cec5SDimitry Andric   std::atomic_int owner_id; // (gtid+1) of owning thread, 0 if unlocked
2370b57cec5SDimitry Andric   std::atomic_int depth_locked; // depth locked, for nested locks only
2380b57cec5SDimitry Andric   kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
2390b57cec5SDimitry Andric };
2400b57cec5SDimitry Andric #else
2410b57cec5SDimitry Andric struct kmp_base_ticket_lock {
2420b57cec5SDimitry Andric   // `initialized' must be the first entry in the lock data structure!
2430b57cec5SDimitry Andric   std::atomic<bool> initialized;
2440b57cec5SDimitry Andric   volatile union kmp_ticket_lock *self; // points to the lock union
2450b57cec5SDimitry Andric   ident_t const *location; // Source code location of omp_init_lock().
2460b57cec5SDimitry Andric   std::atomic<unsigned>
2470b57cec5SDimitry Andric       next_ticket; // ticket number to give to next thread which acquires
2480b57cec5SDimitry Andric   std::atomic<unsigned>
2490b57cec5SDimitry Andric       now_serving; // ticket number for thread which holds the lock
2500b57cec5SDimitry Andric   std::atomic<int> owner_id; // (gtid+1) of owning thread, 0 if unlocked
2510b57cec5SDimitry Andric   std::atomic<int> depth_locked; // depth locked, for nested locks only
2520b57cec5SDimitry Andric   kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
2530b57cec5SDimitry Andric };
2540b57cec5SDimitry Andric #endif
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric #else // __cplusplus
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric struct kmp_base_ticket_lock;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric #endif // !__cplusplus
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric typedef struct kmp_base_ticket_lock kmp_base_ticket_lock_t;
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric union KMP_ALIGN_CACHE kmp_ticket_lock {
2650b57cec5SDimitry Andric   kmp_base_ticket_lock_t
2660b57cec5SDimitry Andric       lk; // This field must be first to allow static initializing.
2670b57cec5SDimitry Andric   kmp_lock_pool_t pool;
2680b57cec5SDimitry Andric   double lk_align; // use worst case alignment
2690b57cec5SDimitry Andric   char lk_pad[KMP_PAD(kmp_base_ticket_lock_t, CACHE_LINE)];
2700b57cec5SDimitry Andric };
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric typedef union kmp_ticket_lock kmp_ticket_lock_t;
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric // Static initializer for simple ticket lock variables. Usage:
2750b57cec5SDimitry Andric //    kmp_ticket_lock_t xlock = KMP_TICKET_LOCK_INITIALIZER( xlock );
2760b57cec5SDimitry Andric // Note the macro argument. It is important to make var properly initialized.
2770b57cec5SDimitry Andric #define KMP_TICKET_LOCK_INITIALIZER(lock)                                      \
2780b57cec5SDimitry Andric   {                                                                            \
2790b57cec5SDimitry Andric     {                                                                          \
2800b57cec5SDimitry Andric       ATOMIC_VAR_INIT(true)                                                    \
2810b57cec5SDimitry Andric       , &(lock), NULL, ATOMIC_VAR_INIT(0U), ATOMIC_VAR_INIT(0U),               \
2820b57cec5SDimitry Andric           ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(-1)                              \
2830b57cec5SDimitry Andric     }                                                                          \
2840b57cec5SDimitry Andric   }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric extern int __kmp_acquire_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid);
2870b57cec5SDimitry Andric extern int __kmp_test_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid);
2880b57cec5SDimitry Andric extern int __kmp_test_ticket_lock_with_cheks(kmp_ticket_lock_t *lck,
2890b57cec5SDimitry Andric                                              kmp_int32 gtid);
2900b57cec5SDimitry Andric extern int __kmp_release_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid);
2910b57cec5SDimitry Andric extern void __kmp_init_ticket_lock(kmp_ticket_lock_t *lck);
2920b57cec5SDimitry Andric extern void __kmp_destroy_ticket_lock(kmp_ticket_lock_t *lck);
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric extern int __kmp_acquire_nested_ticket_lock(kmp_ticket_lock_t *lck,
2950b57cec5SDimitry Andric                                             kmp_int32 gtid);
2960b57cec5SDimitry Andric extern int __kmp_test_nested_ticket_lock(kmp_ticket_lock_t *lck,
2970b57cec5SDimitry Andric                                          kmp_int32 gtid);
2980b57cec5SDimitry Andric extern int __kmp_release_nested_ticket_lock(kmp_ticket_lock_t *lck,
2990b57cec5SDimitry Andric                                             kmp_int32 gtid);
3000b57cec5SDimitry Andric extern void __kmp_init_nested_ticket_lock(kmp_ticket_lock_t *lck);
3010b57cec5SDimitry Andric extern void __kmp_destroy_nested_ticket_lock(kmp_ticket_lock_t *lck);
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric // ----------------------------------------------------------------------------
3040b57cec5SDimitry Andric // Queuing locks.
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric struct kmp_adaptive_lock_info;
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric typedef struct kmp_adaptive_lock_info kmp_adaptive_lock_info_t;
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric #if KMP_DEBUG_ADAPTIVE_LOCKS
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric struct kmp_adaptive_lock_statistics {
3150b57cec5SDimitry Andric   /* So we can get stats from locks that haven't been destroyed. */
3160b57cec5SDimitry Andric   kmp_adaptive_lock_info_t *next;
3170b57cec5SDimitry Andric   kmp_adaptive_lock_info_t *prev;
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   /* Other statistics */
3200b57cec5SDimitry Andric   kmp_uint32 successfulSpeculations;
3210b57cec5SDimitry Andric   kmp_uint32 hardFailedSpeculations;
3220b57cec5SDimitry Andric   kmp_uint32 softFailedSpeculations;
3230b57cec5SDimitry Andric   kmp_uint32 nonSpeculativeAcquires;
3240b57cec5SDimitry Andric   kmp_uint32 nonSpeculativeAcquireAttempts;
3250b57cec5SDimitry Andric   kmp_uint32 lemmingYields;
3260b57cec5SDimitry Andric };
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric typedef struct kmp_adaptive_lock_statistics kmp_adaptive_lock_statistics_t;
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric extern void __kmp_print_speculative_stats();
3310b57cec5SDimitry Andric extern void __kmp_init_speculative_stats();
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric #endif // KMP_DEBUG_ADAPTIVE_LOCKS
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric struct kmp_adaptive_lock_info {
3360b57cec5SDimitry Andric   /* Values used for adaptivity.
3370b57cec5SDimitry Andric      Although these are accessed from multiple threads we don't access them
3380b57cec5SDimitry Andric      atomically, because if we miss updates it probably doesn't matter much. (It
3390b57cec5SDimitry Andric      just affects our decision about whether to try speculation on the lock). */
3400b57cec5SDimitry Andric   kmp_uint32 volatile badness;
3410b57cec5SDimitry Andric   kmp_uint32 volatile acquire_attempts;
3420b57cec5SDimitry Andric   /* Parameters of the lock. */
3430b57cec5SDimitry Andric   kmp_uint32 max_badness;
3440b57cec5SDimitry Andric   kmp_uint32 max_soft_retries;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric #if KMP_DEBUG_ADAPTIVE_LOCKS
3470b57cec5SDimitry Andric   kmp_adaptive_lock_statistics_t volatile stats;
3480b57cec5SDimitry Andric #endif
3490b57cec5SDimitry Andric };
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric #endif // KMP_USE_ADAPTIVE_LOCKS
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric struct kmp_base_queuing_lock {
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   //  `initialized' must be the first entry in the lock data structure!
3560b57cec5SDimitry Andric   volatile union kmp_queuing_lock
3570b57cec5SDimitry Andric       *initialized; // Points to the lock union if in initialized state.
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   ident_t const *location; // Source code location of omp_init_lock().
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   KMP_ALIGN(8) // tail_id  must be 8-byte aligned!
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric   volatile kmp_int32
3640b57cec5SDimitry Andric       tail_id; // (gtid+1) of thread at tail of wait queue, 0 if empty
3650b57cec5SDimitry Andric   // Must be no padding here since head/tail used in 8-byte CAS
3660b57cec5SDimitry Andric   volatile kmp_int32
3670b57cec5SDimitry Andric       head_id; // (gtid+1) of thread at head of wait queue, 0 if empty
3680b57cec5SDimitry Andric   // Decl order assumes little endian
3690b57cec5SDimitry Andric   // bakery-style lock
3700b57cec5SDimitry Andric   volatile kmp_uint32
3710b57cec5SDimitry Andric       next_ticket; // ticket number to give to next thread which acquires
3720b57cec5SDimitry Andric   volatile kmp_uint32
3730b57cec5SDimitry Andric       now_serving; // ticket number for thread which holds the lock
3740b57cec5SDimitry Andric   volatile kmp_int32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
3750b57cec5SDimitry Andric   kmp_int32 depth_locked; // depth locked, for nested locks only
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric   kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
3780b57cec5SDimitry Andric };
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric typedef struct kmp_base_queuing_lock kmp_base_queuing_lock_t;
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric KMP_BUILD_ASSERT(offsetof(kmp_base_queuing_lock_t, tail_id) % 8 == 0);
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric union KMP_ALIGN_CACHE kmp_queuing_lock {
3850b57cec5SDimitry Andric   kmp_base_queuing_lock_t
3860b57cec5SDimitry Andric       lk; // This field must be first to allow static initializing.
3870b57cec5SDimitry Andric   kmp_lock_pool_t pool;
3880b57cec5SDimitry Andric   double lk_align; // use worst case alignment
3890b57cec5SDimitry Andric   char lk_pad[KMP_PAD(kmp_base_queuing_lock_t, CACHE_LINE)];
3900b57cec5SDimitry Andric };
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric typedef union kmp_queuing_lock kmp_queuing_lock_t;
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric extern int __kmp_acquire_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid);
3950b57cec5SDimitry Andric extern int __kmp_test_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid);
3960b57cec5SDimitry Andric extern int __kmp_release_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid);
3970b57cec5SDimitry Andric extern void __kmp_init_queuing_lock(kmp_queuing_lock_t *lck);
3980b57cec5SDimitry Andric extern void __kmp_destroy_queuing_lock(kmp_queuing_lock_t *lck);
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric extern int __kmp_acquire_nested_queuing_lock(kmp_queuing_lock_t *lck,
4010b57cec5SDimitry Andric                                              kmp_int32 gtid);
4020b57cec5SDimitry Andric extern int __kmp_test_nested_queuing_lock(kmp_queuing_lock_t *lck,
4030b57cec5SDimitry Andric                                           kmp_int32 gtid);
4040b57cec5SDimitry Andric extern int __kmp_release_nested_queuing_lock(kmp_queuing_lock_t *lck,
4050b57cec5SDimitry Andric                                              kmp_int32 gtid);
4060b57cec5SDimitry Andric extern void __kmp_init_nested_queuing_lock(kmp_queuing_lock_t *lck);
4070b57cec5SDimitry Andric extern void __kmp_destroy_nested_queuing_lock(kmp_queuing_lock_t *lck);
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric // ----------------------------------------------------------------------------
4120b57cec5SDimitry Andric // Adaptive locks.
4130b57cec5SDimitry Andric struct kmp_base_adaptive_lock {
4140b57cec5SDimitry Andric   kmp_base_queuing_lock qlk;
4150b57cec5SDimitry Andric   KMP_ALIGN(CACHE_LINE)
4160b57cec5SDimitry Andric   kmp_adaptive_lock_info_t
4170b57cec5SDimitry Andric       adaptive; // Information for the speculative adaptive lock
4180b57cec5SDimitry Andric };
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric typedef struct kmp_base_adaptive_lock kmp_base_adaptive_lock_t;
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric union KMP_ALIGN_CACHE kmp_adaptive_lock {
4230b57cec5SDimitry Andric   kmp_base_adaptive_lock_t lk;
4240b57cec5SDimitry Andric   kmp_lock_pool_t pool;
4250b57cec5SDimitry Andric   double lk_align;
4260b57cec5SDimitry Andric   char lk_pad[KMP_PAD(kmp_base_adaptive_lock_t, CACHE_LINE)];
4270b57cec5SDimitry Andric };
4280b57cec5SDimitry Andric typedef union kmp_adaptive_lock kmp_adaptive_lock_t;
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric #define GET_QLK_PTR(l) ((kmp_queuing_lock_t *)&(l)->lk.qlk)
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric #endif // KMP_USE_ADAPTIVE_LOCKS
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric // ----------------------------------------------------------------------------
4350b57cec5SDimitry Andric // DRDPA ticket locks.
4360b57cec5SDimitry Andric struct kmp_base_drdpa_lock {
4370b57cec5SDimitry Andric   // All of the fields on the first cache line are only written when
4380b57cec5SDimitry Andric   // initializing or reconfiguring the lock.  These are relatively rare
4390b57cec5SDimitry Andric   // operations, so data from the first cache line will usually stay resident in
4400b57cec5SDimitry Andric   // the cache of each thread trying to acquire the lock.
4410b57cec5SDimitry Andric   //
4420b57cec5SDimitry Andric   // initialized must be the first entry in the lock data structure!
4430b57cec5SDimitry Andric   KMP_ALIGN_CACHE
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   volatile union kmp_drdpa_lock
4460b57cec5SDimitry Andric       *initialized; // points to the lock union if in initialized state
4470b57cec5SDimitry Andric   ident_t const *location; // Source code location of omp_init_lock().
4480b57cec5SDimitry Andric   std::atomic<std::atomic<kmp_uint64> *> polls;
4490b57cec5SDimitry Andric   std::atomic<kmp_uint64> mask; // is 2**num_polls-1 for mod op
4500b57cec5SDimitry Andric   kmp_uint64 cleanup_ticket; // thread with cleanup ticket
4510b57cec5SDimitry Andric   std::atomic<kmp_uint64> *old_polls; // will deallocate old_polls
4520b57cec5SDimitry Andric   kmp_uint32 num_polls; // must be power of 2
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   // next_ticket it needs to exist in a separate cache line, as it is
4550b57cec5SDimitry Andric   // invalidated every time a thread takes a new ticket.
4560b57cec5SDimitry Andric   KMP_ALIGN_CACHE
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric   std::atomic<kmp_uint64> next_ticket;
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   // now_serving is used to store our ticket value while we hold the lock. It
4610b57cec5SDimitry Andric   // has a slightly different meaning in the DRDPA ticket locks (where it is
4620b57cec5SDimitry Andric   // written by the acquiring thread) than it does in the simple ticket locks
4630b57cec5SDimitry Andric   // (where it is written by the releasing thread).
4640b57cec5SDimitry Andric   //
4650b57cec5SDimitry Andric   // Since now_serving is only read an written in the critical section,
4660b57cec5SDimitry Andric   // it is non-volatile, but it needs to exist on a separate cache line,
4670b57cec5SDimitry Andric   // as it is invalidated at every lock acquire.
4680b57cec5SDimitry Andric   //
4690b57cec5SDimitry Andric   // Likewise, the vars used for nested locks (owner_id and depth_locked) are
4700b57cec5SDimitry Andric   // only written by the thread owning the lock, so they are put in this cache
4710b57cec5SDimitry Andric   // line.  owner_id is read by other threads, so it must be declared volatile.
4720b57cec5SDimitry Andric   KMP_ALIGN_CACHE
4730b57cec5SDimitry Andric   kmp_uint64 now_serving; // doesn't have to be volatile
4740b57cec5SDimitry Andric   volatile kmp_uint32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
4750b57cec5SDimitry Andric   kmp_int32 depth_locked; // depth locked
4760b57cec5SDimitry Andric   kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
4770b57cec5SDimitry Andric };
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric typedef struct kmp_base_drdpa_lock kmp_base_drdpa_lock_t;
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric union KMP_ALIGN_CACHE kmp_drdpa_lock {
4820b57cec5SDimitry Andric   kmp_base_drdpa_lock_t
4830b57cec5SDimitry Andric       lk; // This field must be first to allow static initializing. */
4840b57cec5SDimitry Andric   kmp_lock_pool_t pool;
4850b57cec5SDimitry Andric   double lk_align; // use worst case alignment
4860b57cec5SDimitry Andric   char lk_pad[KMP_PAD(kmp_base_drdpa_lock_t, CACHE_LINE)];
4870b57cec5SDimitry Andric };
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric typedef union kmp_drdpa_lock kmp_drdpa_lock_t;
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric extern int __kmp_acquire_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
4920b57cec5SDimitry Andric extern int __kmp_test_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
4930b57cec5SDimitry Andric extern int __kmp_release_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
4940b57cec5SDimitry Andric extern void __kmp_init_drdpa_lock(kmp_drdpa_lock_t *lck);
4950b57cec5SDimitry Andric extern void __kmp_destroy_drdpa_lock(kmp_drdpa_lock_t *lck);
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric extern int __kmp_acquire_nested_drdpa_lock(kmp_drdpa_lock_t *lck,
4980b57cec5SDimitry Andric                                            kmp_int32 gtid);
4990b57cec5SDimitry Andric extern int __kmp_test_nested_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid);
5000b57cec5SDimitry Andric extern int __kmp_release_nested_drdpa_lock(kmp_drdpa_lock_t *lck,
5010b57cec5SDimitry Andric                                            kmp_int32 gtid);
5020b57cec5SDimitry Andric extern void __kmp_init_nested_drdpa_lock(kmp_drdpa_lock_t *lck);
5030b57cec5SDimitry Andric extern void __kmp_destroy_nested_drdpa_lock(kmp_drdpa_lock_t *lck);
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric // ============================================================================
5060b57cec5SDimitry Andric // Lock purposes.
5070b57cec5SDimitry Andric // ============================================================================
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric // Bootstrap locks.
5100b57cec5SDimitry Andric //
5110b57cec5SDimitry Andric // Bootstrap locks -- very few locks used at library initialization time.
5120b57cec5SDimitry Andric // Bootstrap locks are currently implemented as ticket locks.
5130b57cec5SDimitry Andric // They could also be implemented as test and set lock, but cannot be
5140b57cec5SDimitry Andric // implemented with other lock kinds as they require gtids which are not
5150b57cec5SDimitry Andric // available at initialization time.
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric typedef kmp_ticket_lock_t kmp_bootstrap_lock_t;
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric #define KMP_BOOTSTRAP_LOCK_INITIALIZER(lock) KMP_TICKET_LOCK_INITIALIZER((lock))
5200b57cec5SDimitry Andric #define KMP_BOOTSTRAP_LOCK_INIT(lock)                                          \
5210b57cec5SDimitry Andric   kmp_bootstrap_lock_t lock = KMP_TICKET_LOCK_INITIALIZER(lock)
5220b57cec5SDimitry Andric 
5230b57cec5SDimitry Andric static inline int __kmp_acquire_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
5240b57cec5SDimitry Andric   return __kmp_acquire_ticket_lock(lck, KMP_GTID_DNE);
5250b57cec5SDimitry Andric }
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric static inline int __kmp_test_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
5280b57cec5SDimitry Andric   return __kmp_test_ticket_lock(lck, KMP_GTID_DNE);
5290b57cec5SDimitry Andric }
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric static inline void __kmp_release_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
5320b57cec5SDimitry Andric   __kmp_release_ticket_lock(lck, KMP_GTID_DNE);
5330b57cec5SDimitry Andric }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric static inline void __kmp_init_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
5360b57cec5SDimitry Andric   __kmp_init_ticket_lock(lck);
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric static inline void __kmp_destroy_bootstrap_lock(kmp_bootstrap_lock_t *lck) {
5400b57cec5SDimitry Andric   __kmp_destroy_ticket_lock(lck);
5410b57cec5SDimitry Andric }
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric // Internal RTL locks.
5440b57cec5SDimitry Andric //
5450b57cec5SDimitry Andric // Internal RTL locks are also implemented as ticket locks, for now.
5460b57cec5SDimitry Andric //
5470b57cec5SDimitry Andric // FIXME - We should go through and figure out which lock kind works best for
5480b57cec5SDimitry Andric // each internal lock, and use the type declaration and function calls for
5490b57cec5SDimitry Andric // that explicit lock kind (and get rid of this section).
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric typedef kmp_ticket_lock_t kmp_lock_t;
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric #define KMP_LOCK_INIT(lock) kmp_lock_t lock = KMP_TICKET_LOCK_INITIALIZER(lock)
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric static inline int __kmp_acquire_lock(kmp_lock_t *lck, kmp_int32 gtid) {
5560b57cec5SDimitry Andric   return __kmp_acquire_ticket_lock(lck, gtid);
5570b57cec5SDimitry Andric }
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric static inline int __kmp_test_lock(kmp_lock_t *lck, kmp_int32 gtid) {
5600b57cec5SDimitry Andric   return __kmp_test_ticket_lock(lck, gtid);
5610b57cec5SDimitry Andric }
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric static inline void __kmp_release_lock(kmp_lock_t *lck, kmp_int32 gtid) {
5640b57cec5SDimitry Andric   __kmp_release_ticket_lock(lck, gtid);
5650b57cec5SDimitry Andric }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric static inline void __kmp_init_lock(kmp_lock_t *lck) {
5680b57cec5SDimitry Andric   __kmp_init_ticket_lock(lck);
5690b57cec5SDimitry Andric }
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric static inline void __kmp_destroy_lock(kmp_lock_t *lck) {
5720b57cec5SDimitry Andric   __kmp_destroy_ticket_lock(lck);
5730b57cec5SDimitry Andric }
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric // User locks.
5760b57cec5SDimitry Andric //
5770b57cec5SDimitry Andric // Do not allocate objects of type union kmp_user_lock!!! This will waste space
5780b57cec5SDimitry Andric // unless __kmp_user_lock_kind == lk_drdpa. Instead, check the value of
5790b57cec5SDimitry Andric // __kmp_user_lock_kind and allocate objects of the type of the appropriate
5800b57cec5SDimitry Andric // union member, and cast their addresses to kmp_user_lock_p.
5810b57cec5SDimitry Andric 
5820b57cec5SDimitry Andric enum kmp_lock_kind {
5830b57cec5SDimitry Andric   lk_default = 0,
5840b57cec5SDimitry Andric   lk_tas,
5850b57cec5SDimitry Andric #if KMP_USE_FUTEX
5860b57cec5SDimitry Andric   lk_futex,
5870b57cec5SDimitry Andric #endif
5880b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK && KMP_USE_TSX
5890b57cec5SDimitry Andric   lk_hle,
5900b57cec5SDimitry Andric   lk_rtm,
5910b57cec5SDimitry Andric #endif
5920b57cec5SDimitry Andric   lk_ticket,
5930b57cec5SDimitry Andric   lk_queuing,
5940b57cec5SDimitry Andric   lk_drdpa,
5950b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
5960b57cec5SDimitry Andric   lk_adaptive
5970b57cec5SDimitry Andric #endif // KMP_USE_ADAPTIVE_LOCKS
5980b57cec5SDimitry Andric };
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric typedef enum kmp_lock_kind kmp_lock_kind_t;
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric extern kmp_lock_kind_t __kmp_user_lock_kind;
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric union kmp_user_lock {
6050b57cec5SDimitry Andric   kmp_tas_lock_t tas;
6060b57cec5SDimitry Andric #if KMP_USE_FUTEX
6070b57cec5SDimitry Andric   kmp_futex_lock_t futex;
6080b57cec5SDimitry Andric #endif
6090b57cec5SDimitry Andric   kmp_ticket_lock_t ticket;
6100b57cec5SDimitry Andric   kmp_queuing_lock_t queuing;
6110b57cec5SDimitry Andric   kmp_drdpa_lock_t drdpa;
6120b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
6130b57cec5SDimitry Andric   kmp_adaptive_lock_t adaptive;
6140b57cec5SDimitry Andric #endif // KMP_USE_ADAPTIVE_LOCKS
6150b57cec5SDimitry Andric   kmp_lock_pool_t pool;
6160b57cec5SDimitry Andric };
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric typedef union kmp_user_lock *kmp_user_lock_p;
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric #if !KMP_USE_DYNAMIC_LOCK
6210b57cec5SDimitry Andric 
6220b57cec5SDimitry Andric extern size_t __kmp_base_user_lock_size;
6230b57cec5SDimitry Andric extern size_t __kmp_user_lock_size;
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric extern kmp_int32 (*__kmp_get_user_lock_owner_)(kmp_user_lock_p lck);
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric static inline kmp_int32 __kmp_get_user_lock_owner(kmp_user_lock_p lck) {
6280b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_get_user_lock_owner_ != NULL);
6290b57cec5SDimitry Andric   return (*__kmp_get_user_lock_owner_)(lck);
6300b57cec5SDimitry Andric }
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric extern int (*__kmp_acquire_user_lock_with_checks_)(kmp_user_lock_p lck,
6330b57cec5SDimitry Andric                                                    kmp_int32 gtid);
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric #if KMP_OS_LINUX &&                                                            \
6360b57cec5SDimitry Andric     (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric #define __kmp_acquire_user_lock_with_checks(lck, gtid)                         \
6390b57cec5SDimitry Andric   if (__kmp_user_lock_kind == lk_tas) {                                        \
6400b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {                                         \
6410b57cec5SDimitry Andric       char const *const func = "omp_set_lock";                                 \
6420b57cec5SDimitry Andric       if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) &&                       \
6430b57cec5SDimitry Andric           lck->tas.lk.depth_locked != -1) {                                    \
6440b57cec5SDimitry Andric         KMP_FATAL(LockNestableUsedAsSimple, func);                             \
6450b57cec5SDimitry Andric       }                                                                        \
6460b57cec5SDimitry Andric       if ((gtid >= 0) && (lck->tas.lk.poll - 1 == gtid)) {                     \
6470b57cec5SDimitry Andric         KMP_FATAL(LockIsAlreadyOwned, func);                                   \
6480b57cec5SDimitry Andric       }                                                                        \
6490b57cec5SDimitry Andric     }                                                                          \
6500b57cec5SDimitry Andric     if (lck->tas.lk.poll != 0 ||                                               \
6510b57cec5SDimitry Andric         !__kmp_atomic_compare_store_acq(&lck->tas.lk.poll, 0, gtid + 1)) {     \
6520b57cec5SDimitry Andric       kmp_uint32 spins;                                                        \
6530b57cec5SDimitry Andric       KMP_FSYNC_PREPARE(lck);                                                  \
6540b57cec5SDimitry Andric       KMP_INIT_YIELD(spins);                                                   \
6550b57cec5SDimitry Andric       do {                                                                     \
6560b57cec5SDimitry Andric         KMP_YIELD_OVERSUB_ELSE_SPIN(spins);                                    \
6570b57cec5SDimitry Andric       } while (                                                                \
6580b57cec5SDimitry Andric           lck->tas.lk.poll != 0 ||                                             \
6590b57cec5SDimitry Andric           !__kmp_atomic_compare_store_acq(&lck->tas.lk.poll, 0, gtid + 1));    \
6600b57cec5SDimitry Andric     }                                                                          \
6610b57cec5SDimitry Andric     KMP_FSYNC_ACQUIRED(lck);                                                   \
6620b57cec5SDimitry Andric   } else {                                                                     \
6630b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(__kmp_acquire_user_lock_with_checks_ != NULL);            \
6640b57cec5SDimitry Andric     (*__kmp_acquire_user_lock_with_checks_)(lck, gtid);                        \
6650b57cec5SDimitry Andric   }
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric #else
6680b57cec5SDimitry Andric static inline int __kmp_acquire_user_lock_with_checks(kmp_user_lock_p lck,
6690b57cec5SDimitry Andric                                                       kmp_int32 gtid) {
6700b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_acquire_user_lock_with_checks_ != NULL);
6710b57cec5SDimitry Andric   return (*__kmp_acquire_user_lock_with_checks_)(lck, gtid);
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric #endif
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric extern int (*__kmp_test_user_lock_with_checks_)(kmp_user_lock_p lck,
6760b57cec5SDimitry Andric                                                 kmp_int32 gtid);
6770b57cec5SDimitry Andric 
6780b57cec5SDimitry Andric #if KMP_OS_LINUX &&                                                            \
6790b57cec5SDimitry Andric     (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric #include "kmp_i18n.h" /* AC: KMP_FATAL definition */
6820b57cec5SDimitry Andric extern int __kmp_env_consistency_check; /* AC: copy from kmp.h here */
6830b57cec5SDimitry Andric static inline int __kmp_test_user_lock_with_checks(kmp_user_lock_p lck,
6840b57cec5SDimitry Andric                                                    kmp_int32 gtid) {
6850b57cec5SDimitry Andric   if (__kmp_user_lock_kind == lk_tas) {
6860b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
6870b57cec5SDimitry Andric       char const *const func = "omp_test_lock";
6880b57cec5SDimitry Andric       if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) &&
6890b57cec5SDimitry Andric           lck->tas.lk.depth_locked != -1) {
6900b57cec5SDimitry Andric         KMP_FATAL(LockNestableUsedAsSimple, func);
6910b57cec5SDimitry Andric       }
6920b57cec5SDimitry Andric     }
6930b57cec5SDimitry Andric     return ((lck->tas.lk.poll == 0) &&
6940b57cec5SDimitry Andric             __kmp_atomic_compare_store_acq(&lck->tas.lk.poll, 0, gtid + 1));
6950b57cec5SDimitry Andric   } else {
6960b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(__kmp_test_user_lock_with_checks_ != NULL);
6970b57cec5SDimitry Andric     return (*__kmp_test_user_lock_with_checks_)(lck, gtid);
6980b57cec5SDimitry Andric   }
6990b57cec5SDimitry Andric }
7000b57cec5SDimitry Andric #else
7010b57cec5SDimitry Andric static inline int __kmp_test_user_lock_with_checks(kmp_user_lock_p lck,
7020b57cec5SDimitry Andric                                                    kmp_int32 gtid) {
7030b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_test_user_lock_with_checks_ != NULL);
7040b57cec5SDimitry Andric   return (*__kmp_test_user_lock_with_checks_)(lck, gtid);
7050b57cec5SDimitry Andric }
7060b57cec5SDimitry Andric #endif
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric extern int (*__kmp_release_user_lock_with_checks_)(kmp_user_lock_p lck,
7090b57cec5SDimitry Andric                                                    kmp_int32 gtid);
7100b57cec5SDimitry Andric 
7110b57cec5SDimitry Andric static inline void __kmp_release_user_lock_with_checks(kmp_user_lock_p lck,
7120b57cec5SDimitry Andric                                                        kmp_int32 gtid) {
7130b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_release_user_lock_with_checks_ != NULL);
7140b57cec5SDimitry Andric   (*__kmp_release_user_lock_with_checks_)(lck, gtid);
7150b57cec5SDimitry Andric }
7160b57cec5SDimitry Andric 
7170b57cec5SDimitry Andric extern void (*__kmp_init_user_lock_with_checks_)(kmp_user_lock_p lck);
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric static inline void __kmp_init_user_lock_with_checks(kmp_user_lock_p lck) {
7200b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_user_lock_with_checks_ != NULL);
7210b57cec5SDimitry Andric   (*__kmp_init_user_lock_with_checks_)(lck);
7220b57cec5SDimitry Andric }
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric // We need a non-checking version of destroy lock for when the RTL is
7250b57cec5SDimitry Andric // doing the cleanup as it can't always tell if the lock is nested or not.
7260b57cec5SDimitry Andric extern void (*__kmp_destroy_user_lock_)(kmp_user_lock_p lck);
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric static inline void __kmp_destroy_user_lock(kmp_user_lock_p lck) {
7290b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_destroy_user_lock_ != NULL);
7300b57cec5SDimitry Andric   (*__kmp_destroy_user_lock_)(lck);
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric extern void (*__kmp_destroy_user_lock_with_checks_)(kmp_user_lock_p lck);
7340b57cec5SDimitry Andric 
7350b57cec5SDimitry Andric static inline void __kmp_destroy_user_lock_with_checks(kmp_user_lock_p lck) {
7360b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_destroy_user_lock_with_checks_ != NULL);
7370b57cec5SDimitry Andric   (*__kmp_destroy_user_lock_with_checks_)(lck);
7380b57cec5SDimitry Andric }
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric extern int (*__kmp_acquire_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
7410b57cec5SDimitry Andric                                                           kmp_int32 gtid);
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric #if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
7440b57cec5SDimitry Andric 
7450b57cec5SDimitry Andric #define __kmp_acquire_nested_user_lock_with_checks(lck, gtid, depth)           \
7460b57cec5SDimitry Andric   if (__kmp_user_lock_kind == lk_tas) {                                        \
7470b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {                                         \
7480b57cec5SDimitry Andric       char const *const func = "omp_set_nest_lock";                            \
7490b57cec5SDimitry Andric       if ((sizeof(kmp_tas_lock_t) <= OMP_NEST_LOCK_T_SIZE) &&                  \
7500b57cec5SDimitry Andric           lck->tas.lk.depth_locked == -1) {                                    \
7510b57cec5SDimitry Andric         KMP_FATAL(LockSimpleUsedAsNestable, func);                             \
7520b57cec5SDimitry Andric       }                                                                        \
7530b57cec5SDimitry Andric     }                                                                          \
7540b57cec5SDimitry Andric     if (lck->tas.lk.poll - 1 == gtid) {                                        \
7550b57cec5SDimitry Andric       lck->tas.lk.depth_locked += 1;                                           \
7560b57cec5SDimitry Andric       *depth = KMP_LOCK_ACQUIRED_NEXT;                                         \
7570b57cec5SDimitry Andric     } else {                                                                   \
7580b57cec5SDimitry Andric       if ((lck->tas.lk.poll != 0) ||                                           \
7590b57cec5SDimitry Andric           !__kmp_atomic_compare_store_acq(&lck->tas.lk.poll, 0, gtid + 1)) {   \
7600b57cec5SDimitry Andric         kmp_uint32 spins;                                                      \
7610b57cec5SDimitry Andric         KMP_FSYNC_PREPARE(lck);                                                \
7620b57cec5SDimitry Andric         KMP_INIT_YIELD(spins);                                                 \
7630b57cec5SDimitry Andric         do {                                                                   \
7640b57cec5SDimitry Andric           KMP_YIELD_OVERSUB_ELSE_SPIN(spins);                                  \
7650b57cec5SDimitry Andric         } while (                                                              \
7660b57cec5SDimitry Andric             (lck->tas.lk.poll != 0) ||                                         \
7670b57cec5SDimitry Andric             !__kmp_atomic_compare_store_acq(&lck->tas.lk.poll, 0, gtid + 1));  \
7680b57cec5SDimitry Andric       }                                                                        \
7690b57cec5SDimitry Andric       lck->tas.lk.depth_locked = 1;                                            \
7700b57cec5SDimitry Andric       *depth = KMP_LOCK_ACQUIRED_FIRST;                                        \
7710b57cec5SDimitry Andric     }                                                                          \
7720b57cec5SDimitry Andric     KMP_FSYNC_ACQUIRED(lck);                                                   \
7730b57cec5SDimitry Andric   } else {                                                                     \
7740b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(__kmp_acquire_nested_user_lock_with_checks_ != NULL);     \
7750b57cec5SDimitry Andric     *depth = (*__kmp_acquire_nested_user_lock_with_checks_)(lck, gtid);        \
7760b57cec5SDimitry Andric   }
7770b57cec5SDimitry Andric 
7780b57cec5SDimitry Andric #else
7790b57cec5SDimitry Andric static inline void
7800b57cec5SDimitry Andric __kmp_acquire_nested_user_lock_with_checks(kmp_user_lock_p lck, kmp_int32 gtid,
7810b57cec5SDimitry Andric                                            int *depth) {
7820b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_acquire_nested_user_lock_with_checks_ != NULL);
7830b57cec5SDimitry Andric   *depth = (*__kmp_acquire_nested_user_lock_with_checks_)(lck, gtid);
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric #endif
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric extern int (*__kmp_test_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
7880b57cec5SDimitry Andric                                                        kmp_int32 gtid);
7890b57cec5SDimitry Andric 
7900b57cec5SDimitry Andric #if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
7910b57cec5SDimitry Andric static inline int __kmp_test_nested_user_lock_with_checks(kmp_user_lock_p lck,
7920b57cec5SDimitry Andric                                                           kmp_int32 gtid) {
7930b57cec5SDimitry Andric   if (__kmp_user_lock_kind == lk_tas) {
7940b57cec5SDimitry Andric     int retval;
7950b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
7960b57cec5SDimitry Andric       char const *const func = "omp_test_nest_lock";
7970b57cec5SDimitry Andric       if ((sizeof(kmp_tas_lock_t) <= OMP_NEST_LOCK_T_SIZE) &&
7980b57cec5SDimitry Andric           lck->tas.lk.depth_locked == -1) {
7990b57cec5SDimitry Andric         KMP_FATAL(LockSimpleUsedAsNestable, func);
8000b57cec5SDimitry Andric       }
8010b57cec5SDimitry Andric     }
8020b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(gtid >= 0);
8030b57cec5SDimitry Andric     if (lck->tas.lk.poll - 1 ==
8040b57cec5SDimitry Andric         gtid) { /* __kmp_get_tas_lock_owner( lck ) == gtid */
8050b57cec5SDimitry Andric       return ++lck->tas.lk.depth_locked; /* same owner, depth increased */
8060b57cec5SDimitry Andric     }
8070b57cec5SDimitry Andric     retval = ((lck->tas.lk.poll == 0) &&
8080b57cec5SDimitry Andric               __kmp_atomic_compare_store_acq(&lck->tas.lk.poll, 0, gtid + 1));
8090b57cec5SDimitry Andric     if (retval) {
8100b57cec5SDimitry Andric       KMP_MB();
8110b57cec5SDimitry Andric       lck->tas.lk.depth_locked = 1;
8120b57cec5SDimitry Andric     }
8130b57cec5SDimitry Andric     return retval;
8140b57cec5SDimitry Andric   } else {
8150b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(__kmp_test_nested_user_lock_with_checks_ != NULL);
8160b57cec5SDimitry Andric     return (*__kmp_test_nested_user_lock_with_checks_)(lck, gtid);
8170b57cec5SDimitry Andric   }
8180b57cec5SDimitry Andric }
8190b57cec5SDimitry Andric #else
8200b57cec5SDimitry Andric static inline int __kmp_test_nested_user_lock_with_checks(kmp_user_lock_p lck,
8210b57cec5SDimitry Andric                                                           kmp_int32 gtid) {
8220b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_test_nested_user_lock_with_checks_ != NULL);
8230b57cec5SDimitry Andric   return (*__kmp_test_nested_user_lock_with_checks_)(lck, gtid);
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric #endif
8260b57cec5SDimitry Andric 
8270b57cec5SDimitry Andric extern int (*__kmp_release_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
8280b57cec5SDimitry Andric                                                           kmp_int32 gtid);
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric static inline int
8310b57cec5SDimitry Andric __kmp_release_nested_user_lock_with_checks(kmp_user_lock_p lck,
8320b57cec5SDimitry Andric                                            kmp_int32 gtid) {
8330b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_release_nested_user_lock_with_checks_ != NULL);
8340b57cec5SDimitry Andric   return (*__kmp_release_nested_user_lock_with_checks_)(lck, gtid);
8350b57cec5SDimitry Andric }
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric extern void (*__kmp_init_nested_user_lock_with_checks_)(kmp_user_lock_p lck);
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric static inline void
8400b57cec5SDimitry Andric __kmp_init_nested_user_lock_with_checks(kmp_user_lock_p lck) {
8410b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_nested_user_lock_with_checks_ != NULL);
8420b57cec5SDimitry Andric   (*__kmp_init_nested_user_lock_with_checks_)(lck);
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric 
8450b57cec5SDimitry Andric extern void (*__kmp_destroy_nested_user_lock_with_checks_)(kmp_user_lock_p lck);
8460b57cec5SDimitry Andric 
8470b57cec5SDimitry Andric static inline void
8480b57cec5SDimitry Andric __kmp_destroy_nested_user_lock_with_checks(kmp_user_lock_p lck) {
8490b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_destroy_nested_user_lock_with_checks_ != NULL);
8500b57cec5SDimitry Andric   (*__kmp_destroy_nested_user_lock_with_checks_)(lck);
8510b57cec5SDimitry Andric }
8520b57cec5SDimitry Andric 
8530b57cec5SDimitry Andric // user lock functions which do not necessarily exist for all lock kinds.
8540b57cec5SDimitry Andric //
8550b57cec5SDimitry Andric // The "set" functions usually have wrapper routines that check for a NULL set
8560b57cec5SDimitry Andric // function pointer and call it if non-NULL.
8570b57cec5SDimitry Andric //
8580b57cec5SDimitry Andric // In some cases, it makes sense to have a "get" wrapper function check for a
8590b57cec5SDimitry Andric // NULL get function pointer and return NULL / invalid value / error code if
8600b57cec5SDimitry Andric // the function pointer is NULL.
8610b57cec5SDimitry Andric //
8620b57cec5SDimitry Andric // In other cases, the calling code really should differentiate between an
8630b57cec5SDimitry Andric // unimplemented function and one that is implemented but returning NULL /
8640b57cec5SDimitry Andric // invalied value.  If this is the case, no get function wrapper exists.
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric extern int (*__kmp_is_user_lock_initialized_)(kmp_user_lock_p lck);
8670b57cec5SDimitry Andric 
8680b57cec5SDimitry Andric // no set function; fields set durining local allocation
8690b57cec5SDimitry Andric 
8700b57cec5SDimitry Andric extern const ident_t *(*__kmp_get_user_lock_location_)(kmp_user_lock_p lck);
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric static inline const ident_t *__kmp_get_user_lock_location(kmp_user_lock_p lck) {
8730b57cec5SDimitry Andric   if (__kmp_get_user_lock_location_ != NULL) {
8740b57cec5SDimitry Andric     return (*__kmp_get_user_lock_location_)(lck);
8750b57cec5SDimitry Andric   } else {
8760b57cec5SDimitry Andric     return NULL;
8770b57cec5SDimitry Andric   }
8780b57cec5SDimitry Andric }
8790b57cec5SDimitry Andric 
8800b57cec5SDimitry Andric extern void (*__kmp_set_user_lock_location_)(kmp_user_lock_p lck,
8810b57cec5SDimitry Andric                                              const ident_t *loc);
8820b57cec5SDimitry Andric 
8830b57cec5SDimitry Andric static inline void __kmp_set_user_lock_location(kmp_user_lock_p lck,
8840b57cec5SDimitry Andric                                                 const ident_t *loc) {
8850b57cec5SDimitry Andric   if (__kmp_set_user_lock_location_ != NULL) {
8860b57cec5SDimitry Andric     (*__kmp_set_user_lock_location_)(lck, loc);
8870b57cec5SDimitry Andric   }
8880b57cec5SDimitry Andric }
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric extern kmp_lock_flags_t (*__kmp_get_user_lock_flags_)(kmp_user_lock_p lck);
8910b57cec5SDimitry Andric 
8920b57cec5SDimitry Andric extern void (*__kmp_set_user_lock_flags_)(kmp_user_lock_p lck,
8930b57cec5SDimitry Andric                                           kmp_lock_flags_t flags);
8940b57cec5SDimitry Andric 
8950b57cec5SDimitry Andric static inline void __kmp_set_user_lock_flags(kmp_user_lock_p lck,
8960b57cec5SDimitry Andric                                              kmp_lock_flags_t flags) {
8970b57cec5SDimitry Andric   if (__kmp_set_user_lock_flags_ != NULL) {
8980b57cec5SDimitry Andric     (*__kmp_set_user_lock_flags_)(lck, flags);
8990b57cec5SDimitry Andric   }
9000b57cec5SDimitry Andric }
9010b57cec5SDimitry Andric 
9020b57cec5SDimitry Andric // The fuction which sets up all of the vtbl pointers for kmp_user_lock_t.
9030b57cec5SDimitry Andric extern void __kmp_set_user_lock_vptrs(kmp_lock_kind_t user_lock_kind);
9040b57cec5SDimitry Andric 
9050b57cec5SDimitry Andric // Macros for binding user lock functions.
9060b57cec5SDimitry Andric #define KMP_BIND_USER_LOCK_TEMPLATE(nest, kind, suffix)                        \
9070b57cec5SDimitry Andric   {                                                                            \
9080b57cec5SDimitry Andric     __kmp_acquire##nest##user_lock_with_checks_ = (int (*)(                    \
9090b57cec5SDimitry Andric         kmp_user_lock_p, kmp_int32))__kmp_acquire##nest##kind##_##suffix;      \
9100b57cec5SDimitry Andric     __kmp_release##nest##user_lock_with_checks_ = (int (*)(                    \
9110b57cec5SDimitry Andric         kmp_user_lock_p, kmp_int32))__kmp_release##nest##kind##_##suffix;      \
9120b57cec5SDimitry Andric     __kmp_test##nest##user_lock_with_checks_ = (int (*)(                       \
9130b57cec5SDimitry Andric         kmp_user_lock_p, kmp_int32))__kmp_test##nest##kind##_##suffix;         \
9140b57cec5SDimitry Andric     __kmp_init##nest##user_lock_with_checks_ =                                 \
9150b57cec5SDimitry Andric         (void (*)(kmp_user_lock_p))__kmp_init##nest##kind##_##suffix;          \
9160b57cec5SDimitry Andric     __kmp_destroy##nest##user_lock_with_checks_ =                              \
9170b57cec5SDimitry Andric         (void (*)(kmp_user_lock_p))__kmp_destroy##nest##kind##_##suffix;       \
9180b57cec5SDimitry Andric   }
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric #define KMP_BIND_USER_LOCK(kind) KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock)
9210b57cec5SDimitry Andric #define KMP_BIND_USER_LOCK_WITH_CHECKS(kind)                                   \
9220b57cec5SDimitry Andric   KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock_with_checks)
9230b57cec5SDimitry Andric #define KMP_BIND_NESTED_USER_LOCK(kind)                                        \
9240b57cec5SDimitry Andric   KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock)
9250b57cec5SDimitry Andric #define KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(kind)                            \
9260b57cec5SDimitry Andric   KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock_with_checks)
9270b57cec5SDimitry Andric 
9280b57cec5SDimitry Andric // User lock table & lock allocation
9290b57cec5SDimitry Andric /* On 64-bit Linux* OS (and OS X*) GNU compiler allocates only 4 bytems memory
9300b57cec5SDimitry Andric    for lock variable, which is not enough to store a pointer, so we have to use
9310b57cec5SDimitry Andric    lock indexes instead of pointers and maintain lock table to map indexes to
9320b57cec5SDimitry Andric    pointers.
9330b57cec5SDimitry Andric 
9340b57cec5SDimitry Andric 
9350b57cec5SDimitry Andric    Note: The first element of the table is not a pointer to lock! It is a
9360b57cec5SDimitry Andric    pointer to previously allocated table (or NULL if it is the first table).
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric    Usage:
9390b57cec5SDimitry Andric 
9400b57cec5SDimitry Andric    if ( OMP_LOCK_T_SIZE < sizeof( <lock> ) ) { // or OMP_NEST_LOCK_T_SIZE
9410b57cec5SDimitry Andric      Lock table is fully utilized. User locks are indexes, so table is used on
9420b57cec5SDimitry Andric      user lock operation.
9430b57cec5SDimitry Andric      Note: it may be the case (lin_32) that we don't need to use a lock
9440b57cec5SDimitry Andric      table for regular locks, but do need the table for nested locks.
9450b57cec5SDimitry Andric    }
9460b57cec5SDimitry Andric    else {
9470b57cec5SDimitry Andric      Lock table initialized but not actually used.
9480b57cec5SDimitry Andric    }
9490b57cec5SDimitry Andric */
9500b57cec5SDimitry Andric 
9510b57cec5SDimitry Andric struct kmp_lock_table {
9520b57cec5SDimitry Andric   kmp_lock_index_t used; // Number of used elements
9530b57cec5SDimitry Andric   kmp_lock_index_t allocated; // Number of allocated elements
9540b57cec5SDimitry Andric   kmp_user_lock_p *table; // Lock table.
9550b57cec5SDimitry Andric };
9560b57cec5SDimitry Andric 
9570b57cec5SDimitry Andric typedef struct kmp_lock_table kmp_lock_table_t;
9580b57cec5SDimitry Andric 
9590b57cec5SDimitry Andric extern kmp_lock_table_t __kmp_user_lock_table;
9600b57cec5SDimitry Andric extern kmp_user_lock_p __kmp_lock_pool;
9610b57cec5SDimitry Andric 
9620b57cec5SDimitry Andric struct kmp_block_of_locks {
9630b57cec5SDimitry Andric   struct kmp_block_of_locks *next_block;
9640b57cec5SDimitry Andric   void *locks;
9650b57cec5SDimitry Andric };
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric typedef struct kmp_block_of_locks kmp_block_of_locks_t;
9680b57cec5SDimitry Andric 
9690b57cec5SDimitry Andric extern kmp_block_of_locks_t *__kmp_lock_blocks;
9700b57cec5SDimitry Andric extern int __kmp_num_locks_in_block;
9710b57cec5SDimitry Andric 
9720b57cec5SDimitry Andric extern kmp_user_lock_p __kmp_user_lock_allocate(void **user_lock,
9730b57cec5SDimitry Andric                                                 kmp_int32 gtid,
9740b57cec5SDimitry Andric                                                 kmp_lock_flags_t flags);
9750b57cec5SDimitry Andric extern void __kmp_user_lock_free(void **user_lock, kmp_int32 gtid,
9760b57cec5SDimitry Andric                                  kmp_user_lock_p lck);
9770b57cec5SDimitry Andric extern kmp_user_lock_p __kmp_lookup_user_lock(void **user_lock,
9780b57cec5SDimitry Andric                                               char const *func);
9790b57cec5SDimitry Andric extern void __kmp_cleanup_user_locks();
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric #define KMP_CHECK_USER_LOCK_INIT()                                             \
9820b57cec5SDimitry Andric   {                                                                            \
9830b57cec5SDimitry Andric     if (!TCR_4(__kmp_init_user_locks)) {                                       \
9840b57cec5SDimitry Andric       __kmp_acquire_bootstrap_lock(&__kmp_initz_lock);                         \
9850b57cec5SDimitry Andric       if (!TCR_4(__kmp_init_user_locks)) {                                     \
9860b57cec5SDimitry Andric         TCW_4(__kmp_init_user_locks, TRUE);                                    \
9870b57cec5SDimitry Andric       }                                                                        \
9880b57cec5SDimitry Andric       __kmp_release_bootstrap_lock(&__kmp_initz_lock);                         \
9890b57cec5SDimitry Andric     }                                                                          \
9900b57cec5SDimitry Andric   }
9910b57cec5SDimitry Andric 
9920b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
9930b57cec5SDimitry Andric 
9940b57cec5SDimitry Andric #undef KMP_PAD
9950b57cec5SDimitry Andric #undef KMP_GTID_DNE
9960b57cec5SDimitry Andric 
9970b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
9980b57cec5SDimitry Andric // KMP_USE_DYNAMIC_LOCK enables dynamic dispatch of lock functions without
9990b57cec5SDimitry Andric // breaking the current compatibility. Essential functionality of this new code
10000b57cec5SDimitry Andric // is dynamic dispatch, but it also implements (or enables implementation of)
10010b57cec5SDimitry Andric // hinted user lock and critical section which will be part of OMP 4.5 soon.
10020b57cec5SDimitry Andric //
10030b57cec5SDimitry Andric // Lock type can be decided at creation time (i.e., lock initialization), and
10040b57cec5SDimitry Andric // subsequent lock function call on the created lock object requires type
10050b57cec5SDimitry Andric // extraction and call through jump table using the extracted type. This type
10060b57cec5SDimitry Andric // information is stored in two different ways depending on the size of the lock
10070b57cec5SDimitry Andric // object, and we differentiate lock types by this size requirement - direct and
10080b57cec5SDimitry Andric // indirect locks.
10090b57cec5SDimitry Andric //
10100b57cec5SDimitry Andric // Direct locks:
10110b57cec5SDimitry Andric // A direct lock object fits into the space created by the compiler for an
10120b57cec5SDimitry Andric // omp_lock_t object, and TAS/Futex lock falls into this category. We use low
10130b57cec5SDimitry Andric // one byte of the lock object as the storage for the lock type, and appropriate
10140b57cec5SDimitry Andric // bit operation is required to access the data meaningful to the lock
10150b57cec5SDimitry Andric // algorithms. Also, to differentiate direct lock from indirect lock, 1 is
10160b57cec5SDimitry Andric // written to LSB of the lock object. The newly introduced "hle" lock is also a
10170b57cec5SDimitry Andric // direct lock.
10180b57cec5SDimitry Andric //
10190b57cec5SDimitry Andric // Indirect locks:
10200b57cec5SDimitry Andric // An indirect lock object requires more space than the compiler-generated
10210b57cec5SDimitry Andric // space, and it should be allocated from heap. Depending on the size of the
10220b57cec5SDimitry Andric // compiler-generated space for the lock (i.e., size of omp_lock_t), this
10230b57cec5SDimitry Andric // omp_lock_t object stores either the address of the heap-allocated indirect
10240b57cec5SDimitry Andric // lock (void * fits in the object) or an index to the indirect lock table entry
10250b57cec5SDimitry Andric // that holds the address. Ticket/Queuing/DRDPA/Adaptive lock falls into this
10260b57cec5SDimitry Andric // category, and the newly introduced "rtm" lock is also an indirect lock which
10270b57cec5SDimitry Andric // was implemented on top of the Queuing lock. When the omp_lock_t object holds
10280b57cec5SDimitry Andric // an index (not lock address), 0 is written to LSB to differentiate the lock
10290b57cec5SDimitry Andric // from a direct lock, and the remaining part is the actual index to the
10300b57cec5SDimitry Andric // indirect lock table.
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric #include <stdint.h> // for uintptr_t
10330b57cec5SDimitry Andric 
10340b57cec5SDimitry Andric // Shortcuts
10350b57cec5SDimitry Andric #define KMP_USE_INLINED_TAS                                                    \
10360b57cec5SDimitry Andric   (KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)) && 1
10370b57cec5SDimitry Andric #define KMP_USE_INLINED_FUTEX KMP_USE_FUTEX && 0
10380b57cec5SDimitry Andric 
10390b57cec5SDimitry Andric // List of lock definitions; all nested locks are indirect locks.
10400b57cec5SDimitry Andric // hle lock is xchg lock prefixed with XACQUIRE/XRELEASE.
10410b57cec5SDimitry Andric // All nested locks are indirect lock types.
10420b57cec5SDimitry Andric #if KMP_USE_TSX
10430b57cec5SDimitry Andric #if KMP_USE_FUTEX
10440b57cec5SDimitry Andric #define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a) m(hle, a)
10450b57cec5SDimitry Andric #define KMP_FOREACH_I_LOCK(m, a)                                               \
10460b57cec5SDimitry Andric   m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) m(rtm, a)              \
10470b57cec5SDimitry Andric       m(nested_tas, a) m(nested_futex, a) m(nested_ticket, a)                  \
10480b57cec5SDimitry Andric           m(nested_queuing, a) m(nested_drdpa, a)
10490b57cec5SDimitry Andric #else
10500b57cec5SDimitry Andric #define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(hle, a)
10510b57cec5SDimitry Andric #define KMP_FOREACH_I_LOCK(m, a)                                               \
10520b57cec5SDimitry Andric   m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) m(rtm, a)              \
10530b57cec5SDimitry Andric       m(nested_tas, a) m(nested_ticket, a) m(nested_queuing, a)                \
10540b57cec5SDimitry Andric           m(nested_drdpa, a)
10550b57cec5SDimitry Andric #endif // KMP_USE_FUTEX
10560b57cec5SDimitry Andric #define KMP_LAST_D_LOCK lockseq_hle
10570b57cec5SDimitry Andric #else
10580b57cec5SDimitry Andric #if KMP_USE_FUTEX
10590b57cec5SDimitry Andric #define KMP_FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a)
10600b57cec5SDimitry Andric #define KMP_FOREACH_I_LOCK(m, a)                                               \
10610b57cec5SDimitry Andric   m(ticket, a) m(queuing, a) m(drdpa, a) m(nested_tas, a) m(nested_futex, a)   \
10620b57cec5SDimitry Andric       m(nested_ticket, a) m(nested_queuing, a) m(nested_drdpa, a)
10630b57cec5SDimitry Andric #define KMP_LAST_D_LOCK lockseq_futex
10640b57cec5SDimitry Andric #else
10650b57cec5SDimitry Andric #define KMP_FOREACH_D_LOCK(m, a) m(tas, a)
10660b57cec5SDimitry Andric #define KMP_FOREACH_I_LOCK(m, a)                                               \
10670b57cec5SDimitry Andric   m(ticket, a) m(queuing, a) m(drdpa, a) m(nested_tas, a) m(nested_ticket, a)  \
10680b57cec5SDimitry Andric       m(nested_queuing, a) m(nested_drdpa, a)
10690b57cec5SDimitry Andric #define KMP_LAST_D_LOCK lockseq_tas
10700b57cec5SDimitry Andric #endif // KMP_USE_FUTEX
10710b57cec5SDimitry Andric #endif // KMP_USE_TSX
10720b57cec5SDimitry Andric 
10730b57cec5SDimitry Andric // Information used in dynamic dispatch
10740b57cec5SDimitry Andric #define KMP_LOCK_SHIFT                                                         \
10750b57cec5SDimitry Andric   8 // number of low bits to be used as tag for direct locks
10760b57cec5SDimitry Andric #define KMP_FIRST_D_LOCK lockseq_tas
10770b57cec5SDimitry Andric #define KMP_FIRST_I_LOCK lockseq_ticket
10780b57cec5SDimitry Andric #define KMP_LAST_I_LOCK lockseq_nested_drdpa
10790b57cec5SDimitry Andric #define KMP_NUM_I_LOCKS                                                        \
10800b57cec5SDimitry Andric   (locktag_nested_drdpa + 1) // number of indirect lock types
10810b57cec5SDimitry Andric 
10820b57cec5SDimitry Andric // Base type for dynamic locks.
10830b57cec5SDimitry Andric typedef kmp_uint32 kmp_dyna_lock_t;
10840b57cec5SDimitry Andric 
10850b57cec5SDimitry Andric // Lock sequence that enumerates all lock kinds. Always make this enumeration
10860b57cec5SDimitry Andric // consistent with kmp_lockseq_t in the include directory.
10870b57cec5SDimitry Andric typedef enum {
10880b57cec5SDimitry Andric   lockseq_indirect = 0,
10890b57cec5SDimitry Andric #define expand_seq(l, a) lockseq_##l,
10900b57cec5SDimitry Andric   KMP_FOREACH_D_LOCK(expand_seq, 0) KMP_FOREACH_I_LOCK(expand_seq, 0)
10910b57cec5SDimitry Andric #undef expand_seq
10920b57cec5SDimitry Andric } kmp_dyna_lockseq_t;
10930b57cec5SDimitry Andric 
10940b57cec5SDimitry Andric // Enumerates indirect lock tags.
10950b57cec5SDimitry Andric typedef enum {
10960b57cec5SDimitry Andric #define expand_tag(l, a) locktag_##l,
10970b57cec5SDimitry Andric   KMP_FOREACH_I_LOCK(expand_tag, 0)
10980b57cec5SDimitry Andric #undef expand_tag
10990b57cec5SDimitry Andric } kmp_indirect_locktag_t;
11000b57cec5SDimitry Andric 
11010b57cec5SDimitry Andric // Utility macros that extract information from lock sequences.
11020b57cec5SDimitry Andric #define KMP_IS_D_LOCK(seq)                                                     \
11030b57cec5SDimitry Andric   ((seq) >= KMP_FIRST_D_LOCK && (seq) <= KMP_LAST_D_LOCK)
11040b57cec5SDimitry Andric #define KMP_IS_I_LOCK(seq)                                                     \
11050b57cec5SDimitry Andric   ((seq) >= KMP_FIRST_I_LOCK && (seq) <= KMP_LAST_I_LOCK)
11060b57cec5SDimitry Andric #define KMP_GET_I_TAG(seq) (kmp_indirect_locktag_t)((seq)-KMP_FIRST_I_LOCK)
11070b57cec5SDimitry Andric #define KMP_GET_D_TAG(seq) ((seq) << 1 | 1)
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric // Enumerates direct lock tags starting from indirect tag.
11100b57cec5SDimitry Andric typedef enum {
11110b57cec5SDimitry Andric #define expand_tag(l, a) locktag_##l = KMP_GET_D_TAG(lockseq_##l),
11120b57cec5SDimitry Andric   KMP_FOREACH_D_LOCK(expand_tag, 0)
11130b57cec5SDimitry Andric #undef expand_tag
11140b57cec5SDimitry Andric } kmp_direct_locktag_t;
11150b57cec5SDimitry Andric 
11160b57cec5SDimitry Andric // Indirect lock type
11170b57cec5SDimitry Andric typedef struct {
11180b57cec5SDimitry Andric   kmp_user_lock_p lock;
11190b57cec5SDimitry Andric   kmp_indirect_locktag_t type;
11200b57cec5SDimitry Andric } kmp_indirect_lock_t;
11210b57cec5SDimitry Andric 
11220b57cec5SDimitry Andric // Function tables for direct locks. Set/unset/test differentiate functions
11230b57cec5SDimitry Andric // with/without consistency checking.
11240b57cec5SDimitry Andric extern void (*__kmp_direct_init[])(kmp_dyna_lock_t *, kmp_dyna_lockseq_t);
1125*489b1cf2SDimitry Andric extern void (**__kmp_direct_destroy)(kmp_dyna_lock_t *);
1126*489b1cf2SDimitry Andric extern int (**__kmp_direct_set)(kmp_dyna_lock_t *, kmp_int32);
1127*489b1cf2SDimitry Andric extern int (**__kmp_direct_unset)(kmp_dyna_lock_t *, kmp_int32);
1128*489b1cf2SDimitry Andric extern int (**__kmp_direct_test)(kmp_dyna_lock_t *, kmp_int32);
11290b57cec5SDimitry Andric 
11300b57cec5SDimitry Andric // Function tables for indirect locks. Set/unset/test differentiate functions
11310b57cec5SDimitry Andric // with/withuot consistency checking.
11320b57cec5SDimitry Andric extern void (*__kmp_indirect_init[])(kmp_user_lock_p);
1133*489b1cf2SDimitry Andric extern void (**__kmp_indirect_destroy)(kmp_user_lock_p);
1134*489b1cf2SDimitry Andric extern int (**__kmp_indirect_set)(kmp_user_lock_p, kmp_int32);
1135*489b1cf2SDimitry Andric extern int (**__kmp_indirect_unset)(kmp_user_lock_p, kmp_int32);
1136*489b1cf2SDimitry Andric extern int (**__kmp_indirect_test)(kmp_user_lock_p, kmp_int32);
11370b57cec5SDimitry Andric 
11380b57cec5SDimitry Andric // Extracts direct lock tag from a user lock pointer
11390b57cec5SDimitry Andric #define KMP_EXTRACT_D_TAG(l)                                                   \
11400b57cec5SDimitry Andric   (*((kmp_dyna_lock_t *)(l)) & ((1 << KMP_LOCK_SHIFT) - 1) &                   \
11410b57cec5SDimitry Andric    -(*((kmp_dyna_lock_t *)(l)) & 1))
11420b57cec5SDimitry Andric 
11430b57cec5SDimitry Andric // Extracts indirect lock index from a user lock pointer
11440b57cec5SDimitry Andric #define KMP_EXTRACT_I_INDEX(l) (*(kmp_lock_index_t *)(l) >> 1)
11450b57cec5SDimitry Andric 
11460b57cec5SDimitry Andric // Returns function pointer to the direct lock function with l (kmp_dyna_lock_t
11470b57cec5SDimitry Andric // *) and op (operation type).
11480b57cec5SDimitry Andric #define KMP_D_LOCK_FUNC(l, op) __kmp_direct_##op[KMP_EXTRACT_D_TAG(l)]
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric // Returns function pointer to the indirect lock function with l
11510b57cec5SDimitry Andric // (kmp_indirect_lock_t *) and op (operation type).
11520b57cec5SDimitry Andric #define KMP_I_LOCK_FUNC(l, op)                                                 \
11530b57cec5SDimitry Andric   __kmp_indirect_##op[((kmp_indirect_lock_t *)(l))->type]
11540b57cec5SDimitry Andric 
11550b57cec5SDimitry Andric // Initializes a direct lock with the given lock pointer and lock sequence.
11560b57cec5SDimitry Andric #define KMP_INIT_D_LOCK(l, seq)                                                \
11570b57cec5SDimitry Andric   __kmp_direct_init[KMP_GET_D_TAG(seq)]((kmp_dyna_lock_t *)l, seq)
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric // Initializes an indirect lock with the given lock pointer and lock sequence.
11600b57cec5SDimitry Andric #define KMP_INIT_I_LOCK(l, seq)                                                \
11610b57cec5SDimitry Andric   __kmp_direct_init[0]((kmp_dyna_lock_t *)(l), seq)
11620b57cec5SDimitry Andric 
11630b57cec5SDimitry Andric // Returns "free" lock value for the given lock type.
11640b57cec5SDimitry Andric #define KMP_LOCK_FREE(type) (locktag_##type)
11650b57cec5SDimitry Andric 
11660b57cec5SDimitry Andric // Returns "busy" lock value for the given lock teyp.
11670b57cec5SDimitry Andric #define KMP_LOCK_BUSY(v, type) ((v) << KMP_LOCK_SHIFT | locktag_##type)
11680b57cec5SDimitry Andric 
11690b57cec5SDimitry Andric // Returns lock value after removing (shifting) lock tag.
11700b57cec5SDimitry Andric #define KMP_LOCK_STRIP(v) ((v) >> KMP_LOCK_SHIFT)
11710b57cec5SDimitry Andric 
11720b57cec5SDimitry Andric // Initializes global states and data structures for managing dynamic user
11730b57cec5SDimitry Andric // locks.
11740b57cec5SDimitry Andric extern void __kmp_init_dynamic_user_locks();
11750b57cec5SDimitry Andric 
11760b57cec5SDimitry Andric // Allocates and returns an indirect lock with the given indirect lock tag.
11770b57cec5SDimitry Andric extern kmp_indirect_lock_t *
11780b57cec5SDimitry Andric __kmp_allocate_indirect_lock(void **, kmp_int32, kmp_indirect_locktag_t);
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric // Cleans up global states and data structures for managing dynamic user locks.
11810b57cec5SDimitry Andric extern void __kmp_cleanup_indirect_user_locks();
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric // Default user lock sequence when not using hinted locks.
11840b57cec5SDimitry Andric extern kmp_dyna_lockseq_t __kmp_user_lock_seq;
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric // Jump table for "set lock location", available only for indirect locks.
11870b57cec5SDimitry Andric extern void (*__kmp_indirect_set_location[KMP_NUM_I_LOCKS])(kmp_user_lock_p,
11880b57cec5SDimitry Andric                                                             const ident_t *);
11890b57cec5SDimitry Andric #define KMP_SET_I_LOCK_LOCATION(lck, loc)                                      \
11900b57cec5SDimitry Andric   {                                                                            \
11910b57cec5SDimitry Andric     if (__kmp_indirect_set_location[(lck)->type] != NULL)                      \
11920b57cec5SDimitry Andric       __kmp_indirect_set_location[(lck)->type]((lck)->lock, loc);              \
11930b57cec5SDimitry Andric   }
11940b57cec5SDimitry Andric 
11950b57cec5SDimitry Andric // Jump table for "set lock flags", available only for indirect locks.
11960b57cec5SDimitry Andric extern void (*__kmp_indirect_set_flags[KMP_NUM_I_LOCKS])(kmp_user_lock_p,
11970b57cec5SDimitry Andric                                                          kmp_lock_flags_t);
11980b57cec5SDimitry Andric #define KMP_SET_I_LOCK_FLAGS(lck, flag)                                        \
11990b57cec5SDimitry Andric   {                                                                            \
12000b57cec5SDimitry Andric     if (__kmp_indirect_set_flags[(lck)->type] != NULL)                         \
12010b57cec5SDimitry Andric       __kmp_indirect_set_flags[(lck)->type]((lck)->lock, flag);                \
12020b57cec5SDimitry Andric   }
12030b57cec5SDimitry Andric 
12040b57cec5SDimitry Andric // Jump table for "get lock location", available only for indirect locks.
12050b57cec5SDimitry Andric extern const ident_t *(*__kmp_indirect_get_location[KMP_NUM_I_LOCKS])(
12060b57cec5SDimitry Andric     kmp_user_lock_p);
12070b57cec5SDimitry Andric #define KMP_GET_I_LOCK_LOCATION(lck)                                           \
12080b57cec5SDimitry Andric   (__kmp_indirect_get_location[(lck)->type] != NULL                            \
12090b57cec5SDimitry Andric        ? __kmp_indirect_get_location[(lck)->type]((lck)->lock)                 \
12100b57cec5SDimitry Andric        : NULL)
12110b57cec5SDimitry Andric 
12120b57cec5SDimitry Andric // Jump table for "get lock flags", available only for indirect locks.
12130b57cec5SDimitry Andric extern kmp_lock_flags_t (*__kmp_indirect_get_flags[KMP_NUM_I_LOCKS])(
12140b57cec5SDimitry Andric     kmp_user_lock_p);
12150b57cec5SDimitry Andric #define KMP_GET_I_LOCK_FLAGS(lck)                                              \
12160b57cec5SDimitry Andric   (__kmp_indirect_get_flags[(lck)->type] != NULL                               \
12170b57cec5SDimitry Andric        ? __kmp_indirect_get_flags[(lck)->type]((lck)->lock)                    \
12180b57cec5SDimitry Andric        : NULL)
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric #define KMP_I_LOCK_CHUNK                                                       \
12210b57cec5SDimitry Andric   1024 // number of kmp_indirect_lock_t objects to be allocated together
12220b57cec5SDimitry Andric 
12230b57cec5SDimitry Andric // Lock table for indirect locks.
12240b57cec5SDimitry Andric typedef struct kmp_indirect_lock_table {
12250b57cec5SDimitry Andric   kmp_indirect_lock_t **table; // blocks of indirect locks allocated
12260b57cec5SDimitry Andric   kmp_lock_index_t size; // size of the indirect lock table
12270b57cec5SDimitry Andric   kmp_lock_index_t next; // index to the next lock to be allocated
12280b57cec5SDimitry Andric } kmp_indirect_lock_table_t;
12290b57cec5SDimitry Andric 
12300b57cec5SDimitry Andric extern kmp_indirect_lock_table_t __kmp_i_lock_table;
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric // Returns the indirect lock associated with the given index.
12330b57cec5SDimitry Andric #define KMP_GET_I_LOCK(index)                                                  \
12340b57cec5SDimitry Andric   (*(__kmp_i_lock_table.table + (index) / KMP_I_LOCK_CHUNK) +                  \
12350b57cec5SDimitry Andric    (index) % KMP_I_LOCK_CHUNK)
12360b57cec5SDimitry Andric 
12370b57cec5SDimitry Andric // Number of locks in a lock block, which is fixed to "1" now.
12380b57cec5SDimitry Andric // TODO: No lock block implementation now. If we do support, we need to manage
12390b57cec5SDimitry Andric // lock block data structure for each indirect lock type.
12400b57cec5SDimitry Andric extern int __kmp_num_locks_in_block;
12410b57cec5SDimitry Andric 
12420b57cec5SDimitry Andric // Fast lock table lookup without consistency checking
12430b57cec5SDimitry Andric #define KMP_LOOKUP_I_LOCK(l)                                                   \
12440b57cec5SDimitry Andric   ((OMP_LOCK_T_SIZE < sizeof(void *)) ? KMP_GET_I_LOCK(KMP_EXTRACT_I_INDEX(l)) \
12450b57cec5SDimitry Andric                                       : *((kmp_indirect_lock_t **)(l)))
12460b57cec5SDimitry Andric 
12470b57cec5SDimitry Andric // Used once in kmp_error.cpp
12480b57cec5SDimitry Andric extern kmp_int32 __kmp_get_user_lock_owner(kmp_user_lock_p, kmp_uint32);
12490b57cec5SDimitry Andric 
12500b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric #define KMP_LOCK_BUSY(v, type) (v)
12530b57cec5SDimitry Andric #define KMP_LOCK_FREE(type) 0
12540b57cec5SDimitry Andric #define KMP_LOCK_STRIP(v) (v)
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
12570b57cec5SDimitry Andric 
12580b57cec5SDimitry Andric // data structure for using backoff within spin locks.
12590b57cec5SDimitry Andric typedef struct {
12600b57cec5SDimitry Andric   kmp_uint32 step; // current step
12610b57cec5SDimitry Andric   kmp_uint32 max_backoff; // upper bound of outer delay loop
12620b57cec5SDimitry Andric   kmp_uint32 min_tick; // size of inner delay loop in ticks (machine-dependent)
12630b57cec5SDimitry Andric } kmp_backoff_t;
12640b57cec5SDimitry Andric 
12650b57cec5SDimitry Andric // Runtime's default backoff parameters
12660b57cec5SDimitry Andric extern kmp_backoff_t __kmp_spin_backoff_params;
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric // Backoff function
12690b57cec5SDimitry Andric extern void __kmp_spin_backoff(kmp_backoff_t *);
12700b57cec5SDimitry Andric 
12710b57cec5SDimitry Andric #ifdef __cplusplus
12720b57cec5SDimitry Andric } // extern "C"
12730b57cec5SDimitry Andric #endif // __cplusplus
12740b57cec5SDimitry Andric 
12750b57cec5SDimitry Andric #endif /* KMP_LOCK_H */
1276