10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric * kmp_lock.cpp -- lock-related functions
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 #include <stddef.h>
140b57cec5SDimitry Andric #include <atomic>
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric #include "kmp.h"
170b57cec5SDimitry Andric #include "kmp_i18n.h"
180b57cec5SDimitry Andric #include "kmp_io.h"
190b57cec5SDimitry Andric #include "kmp_itt.h"
200b57cec5SDimitry Andric #include "kmp_lock.h"
210b57cec5SDimitry Andric #include "kmp_wait_release.h"
220b57cec5SDimitry Andric #include "kmp_wrapper_getpid.h"
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric #if KMP_USE_FUTEX
250b57cec5SDimitry Andric #include <sys/syscall.h>
260b57cec5SDimitry Andric #include <unistd.h>
270b57cec5SDimitry Andric // We should really include <futex.h>, but that causes compatibility problems on
280b57cec5SDimitry Andric // different Linux* OS distributions that either require that you include (or
290b57cec5SDimitry Andric // break when you try to include) <pci/types.h>. Since all we need is the two
300b57cec5SDimitry Andric // macros below (which are part of the kernel ABI, so can't change) we just
310b57cec5SDimitry Andric // define the constants here and don't include <futex.h>
320b57cec5SDimitry Andric #ifndef FUTEX_WAIT
330b57cec5SDimitry Andric #define FUTEX_WAIT 0
340b57cec5SDimitry Andric #endif
350b57cec5SDimitry Andric #ifndef FUTEX_WAKE
360b57cec5SDimitry Andric #define FUTEX_WAKE 1
370b57cec5SDimitry Andric #endif
380b57cec5SDimitry Andric #endif
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric /* Implement spin locks for internal library use. */
410b57cec5SDimitry Andric /* The algorithm implemented is Lamport's bakery lock [1974]. */
420b57cec5SDimitry Andric
__kmp_validate_locks(void)430b57cec5SDimitry Andric void __kmp_validate_locks(void) {
440b57cec5SDimitry Andric int i;
450b57cec5SDimitry Andric kmp_uint32 x, y;
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric /* Check to make sure unsigned arithmetic does wraps properly */
480b57cec5SDimitry Andric x = ~((kmp_uint32)0) - 2;
490b57cec5SDimitry Andric y = x - 2;
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric for (i = 0; i < 8; ++i, ++x, ++y) {
520b57cec5SDimitry Andric kmp_uint32 z = (x - y);
530b57cec5SDimitry Andric KMP_ASSERT(z == 2);
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric KMP_ASSERT(offsetof(kmp_base_queuing_lock, tail_id) % 8 == 0);
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric /* ------------------------------------------------------------------------ */
600b57cec5SDimitry Andric /* test and set locks */
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric // For the non-nested locks, we can only assume that the first 4 bytes were
630b57cec5SDimitry Andric // allocated, since gcc only allocates 4 bytes for omp_lock_t, and the Intel
640b57cec5SDimitry Andric // compiler only allocates a 4 byte pointer on IA-32 architecture. On
650b57cec5SDimitry Andric // Windows* OS on Intel(R) 64, we can assume that all 8 bytes were allocated.
660b57cec5SDimitry Andric //
670b57cec5SDimitry Andric // gcc reserves >= 8 bytes for nested locks, so we can assume that the
680b57cec5SDimitry Andric // entire 8 bytes were allocated for nested locks on all 64-bit platforms.
690b57cec5SDimitry Andric
__kmp_get_tas_lock_owner(kmp_tas_lock_t * lck)700b57cec5SDimitry Andric static kmp_int32 __kmp_get_tas_lock_owner(kmp_tas_lock_t *lck) {
710b57cec5SDimitry Andric return KMP_LOCK_STRIP(KMP_ATOMIC_LD_RLX(&lck->lk.poll)) - 1;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric
__kmp_is_tas_lock_nestable(kmp_tas_lock_t * lck)740b57cec5SDimitry Andric static inline bool __kmp_is_tas_lock_nestable(kmp_tas_lock_t *lck) {
750b57cec5SDimitry Andric return lck->lk.depth_locked != -1;
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric __forceinline static int
__kmp_acquire_tas_lock_timed_template(kmp_tas_lock_t * lck,kmp_int32 gtid)790b57cec5SDimitry Andric __kmp_acquire_tas_lock_timed_template(kmp_tas_lock_t *lck, kmp_int32 gtid) {
800b57cec5SDimitry Andric KMP_MB();
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric #ifdef USE_LOCK_PROFILE
830b57cec5SDimitry Andric kmp_uint32 curr = KMP_LOCK_STRIP(lck->lk.poll);
840b57cec5SDimitry Andric if ((curr != 0) && (curr != gtid + 1))
850b57cec5SDimitry Andric __kmp_printf("LOCK CONTENTION: %p\n", lck);
860b57cec5SDimitry Andric /* else __kmp_printf( "." );*/
870b57cec5SDimitry Andric #endif /* USE_LOCK_PROFILE */
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric kmp_int32 tas_free = KMP_LOCK_FREE(tas);
900b57cec5SDimitry Andric kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas);
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric if (KMP_ATOMIC_LD_RLX(&lck->lk.poll) == tas_free &&
930b57cec5SDimitry Andric __kmp_atomic_compare_store_acq(&lck->lk.poll, tas_free, tas_busy)) {
940b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
950b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric kmp_uint32 spins;
9904eeddc0SDimitry Andric kmp_uint64 time;
1000b57cec5SDimitry Andric KMP_FSYNC_PREPARE(lck);
1010b57cec5SDimitry Andric KMP_INIT_YIELD(spins);
10204eeddc0SDimitry Andric KMP_INIT_BACKOFF(time);
1030b57cec5SDimitry Andric kmp_backoff_t backoff = __kmp_spin_backoff_params;
1040b57cec5SDimitry Andric do {
10504eeddc0SDimitry Andric #if !KMP_HAVE_UMWAIT
1060b57cec5SDimitry Andric __kmp_spin_backoff(&backoff);
10704eeddc0SDimitry Andric #else
10804eeddc0SDimitry Andric if (!__kmp_tpause_enabled)
10904eeddc0SDimitry Andric __kmp_spin_backoff(&backoff);
11004eeddc0SDimitry Andric #endif
11104eeddc0SDimitry Andric KMP_YIELD_OVERSUB_ELSE_SPIN(spins, time);
1120b57cec5SDimitry Andric } while (KMP_ATOMIC_LD_RLX(&lck->lk.poll) != tas_free ||
1130b57cec5SDimitry Andric !__kmp_atomic_compare_store_acq(&lck->lk.poll, tas_free, tas_busy));
1140b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
1150b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
__kmp_acquire_tas_lock(kmp_tas_lock_t * lck,kmp_int32 gtid)1180b57cec5SDimitry Andric int __kmp_acquire_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid) {
1190b57cec5SDimitry Andric int retval = __kmp_acquire_tas_lock_timed_template(lck, gtid);
1200b57cec5SDimitry Andric return retval;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric
__kmp_acquire_tas_lock_with_checks(kmp_tas_lock_t * lck,kmp_int32 gtid)1230b57cec5SDimitry Andric static int __kmp_acquire_tas_lock_with_checks(kmp_tas_lock_t *lck,
1240b57cec5SDimitry Andric kmp_int32 gtid) {
1250b57cec5SDimitry Andric char const *const func = "omp_set_lock";
1260b57cec5SDimitry Andric if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) &&
1270b57cec5SDimitry Andric __kmp_is_tas_lock_nestable(lck)) {
1280b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_tas_lock_owner(lck) == gtid)) {
1310b57cec5SDimitry Andric KMP_FATAL(LockIsAlreadyOwned, func);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric return __kmp_acquire_tas_lock(lck, gtid);
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
__kmp_test_tas_lock(kmp_tas_lock_t * lck,kmp_int32 gtid)1360b57cec5SDimitry Andric int __kmp_test_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid) {
1370b57cec5SDimitry Andric kmp_int32 tas_free = KMP_LOCK_FREE(tas);
1380b57cec5SDimitry Andric kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas);
1390b57cec5SDimitry Andric if (KMP_ATOMIC_LD_RLX(&lck->lk.poll) == tas_free &&
1400b57cec5SDimitry Andric __kmp_atomic_compare_store_acq(&lck->lk.poll, tas_free, tas_busy)) {
1410b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
1420b57cec5SDimitry Andric return TRUE;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric return FALSE;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric
__kmp_test_tas_lock_with_checks(kmp_tas_lock_t * lck,kmp_int32 gtid)1470b57cec5SDimitry Andric static int __kmp_test_tas_lock_with_checks(kmp_tas_lock_t *lck,
1480b57cec5SDimitry Andric kmp_int32 gtid) {
1490b57cec5SDimitry Andric char const *const func = "omp_test_lock";
1500b57cec5SDimitry Andric if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) &&
1510b57cec5SDimitry Andric __kmp_is_tas_lock_nestable(lck)) {
1520b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric return __kmp_test_tas_lock(lck, gtid);
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric
__kmp_release_tas_lock(kmp_tas_lock_t * lck,kmp_int32 gtid)1570b57cec5SDimitry Andric int __kmp_release_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid) {
1580b57cec5SDimitry Andric KMP_MB(); /* Flush all pending memory write invalidates. */
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric KMP_FSYNC_RELEASING(lck);
1610b57cec5SDimitry Andric KMP_ATOMIC_ST_REL(&lck->lk.poll, KMP_LOCK_FREE(tas));
1620b57cec5SDimitry Andric KMP_MB(); /* Flush all pending memory write invalidates. */
1630b57cec5SDimitry Andric
1640b57cec5SDimitry Andric KMP_YIELD_OVERSUB();
1650b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
__kmp_release_tas_lock_with_checks(kmp_tas_lock_t * lck,kmp_int32 gtid)1680b57cec5SDimitry Andric static int __kmp_release_tas_lock_with_checks(kmp_tas_lock_t *lck,
1690b57cec5SDimitry Andric kmp_int32 gtid) {
1700b57cec5SDimitry Andric char const *const func = "omp_unset_lock";
1710b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
1720b57cec5SDimitry Andric if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) &&
1730b57cec5SDimitry Andric __kmp_is_tas_lock_nestable(lck)) {
1740b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric if (__kmp_get_tas_lock_owner(lck) == -1) {
1770b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_tas_lock_owner(lck) >= 0) &&
1800b57cec5SDimitry Andric (__kmp_get_tas_lock_owner(lck) != gtid)) {
1810b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric return __kmp_release_tas_lock(lck, gtid);
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric
__kmp_init_tas_lock(kmp_tas_lock_t * lck)1860b57cec5SDimitry Andric void __kmp_init_tas_lock(kmp_tas_lock_t *lck) {
1870b57cec5SDimitry Andric lck->lk.poll = KMP_LOCK_FREE(tas);
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric
__kmp_destroy_tas_lock(kmp_tas_lock_t * lck)1900b57cec5SDimitry Andric void __kmp_destroy_tas_lock(kmp_tas_lock_t *lck) { lck->lk.poll = 0; }
1910b57cec5SDimitry Andric
__kmp_destroy_tas_lock_with_checks(kmp_tas_lock_t * lck)1920b57cec5SDimitry Andric static void __kmp_destroy_tas_lock_with_checks(kmp_tas_lock_t *lck) {
1930b57cec5SDimitry Andric char const *const func = "omp_destroy_lock";
1940b57cec5SDimitry Andric if ((sizeof(kmp_tas_lock_t) <= OMP_LOCK_T_SIZE) &&
1950b57cec5SDimitry Andric __kmp_is_tas_lock_nestable(lck)) {
1960b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric if (__kmp_get_tas_lock_owner(lck) != -1) {
1990b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric __kmp_destroy_tas_lock(lck);
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric // nested test and set locks
2050b57cec5SDimitry Andric
__kmp_acquire_nested_tas_lock(kmp_tas_lock_t * lck,kmp_int32 gtid)2060b57cec5SDimitry Andric int __kmp_acquire_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid) {
2070b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric if (__kmp_get_tas_lock_owner(lck) == gtid) {
2100b57cec5SDimitry Andric lck->lk.depth_locked += 1;
2110b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_NEXT;
2120b57cec5SDimitry Andric } else {
2130b57cec5SDimitry Andric __kmp_acquire_tas_lock_timed_template(lck, gtid);
2140b57cec5SDimitry Andric lck->lk.depth_locked = 1;
2150b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
__kmp_acquire_nested_tas_lock_with_checks(kmp_tas_lock_t * lck,kmp_int32 gtid)2190b57cec5SDimitry Andric static int __kmp_acquire_nested_tas_lock_with_checks(kmp_tas_lock_t *lck,
2200b57cec5SDimitry Andric kmp_int32 gtid) {
2210b57cec5SDimitry Andric char const *const func = "omp_set_nest_lock";
2220b57cec5SDimitry Andric if (!__kmp_is_tas_lock_nestable(lck)) {
2230b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric return __kmp_acquire_nested_tas_lock(lck, gtid);
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric
__kmp_test_nested_tas_lock(kmp_tas_lock_t * lck,kmp_int32 gtid)2280b57cec5SDimitry Andric int __kmp_test_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid) {
2290b57cec5SDimitry Andric int retval;
2300b57cec5SDimitry Andric
2310b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric if (__kmp_get_tas_lock_owner(lck) == gtid) {
2340b57cec5SDimitry Andric retval = ++lck->lk.depth_locked;
2350b57cec5SDimitry Andric } else if (!__kmp_test_tas_lock(lck, gtid)) {
2360b57cec5SDimitry Andric retval = 0;
2370b57cec5SDimitry Andric } else {
2380b57cec5SDimitry Andric KMP_MB();
2390b57cec5SDimitry Andric retval = lck->lk.depth_locked = 1;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric return retval;
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric
__kmp_test_nested_tas_lock_with_checks(kmp_tas_lock_t * lck,kmp_int32 gtid)2440b57cec5SDimitry Andric static int __kmp_test_nested_tas_lock_with_checks(kmp_tas_lock_t *lck,
2450b57cec5SDimitry Andric kmp_int32 gtid) {
2460b57cec5SDimitry Andric char const *const func = "omp_test_nest_lock";
2470b57cec5SDimitry Andric if (!__kmp_is_tas_lock_nestable(lck)) {
2480b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric return __kmp_test_nested_tas_lock(lck, gtid);
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric
__kmp_release_nested_tas_lock(kmp_tas_lock_t * lck,kmp_int32 gtid)2530b57cec5SDimitry Andric int __kmp_release_nested_tas_lock(kmp_tas_lock_t *lck, kmp_int32 gtid) {
2540b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
2550b57cec5SDimitry Andric
2560b57cec5SDimitry Andric KMP_MB();
2570b57cec5SDimitry Andric if (--(lck->lk.depth_locked) == 0) {
2580b57cec5SDimitry Andric __kmp_release_tas_lock(lck, gtid);
2590b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric return KMP_LOCK_STILL_HELD;
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric
__kmp_release_nested_tas_lock_with_checks(kmp_tas_lock_t * lck,kmp_int32 gtid)2640b57cec5SDimitry Andric static int __kmp_release_nested_tas_lock_with_checks(kmp_tas_lock_t *lck,
2650b57cec5SDimitry Andric kmp_int32 gtid) {
2660b57cec5SDimitry Andric char const *const func = "omp_unset_nest_lock";
2670b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
2680b57cec5SDimitry Andric if (!__kmp_is_tas_lock_nestable(lck)) {
2690b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric if (__kmp_get_tas_lock_owner(lck) == -1) {
2720b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric if (__kmp_get_tas_lock_owner(lck) != gtid) {
2750b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric return __kmp_release_nested_tas_lock(lck, gtid);
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric
__kmp_init_nested_tas_lock(kmp_tas_lock_t * lck)2800b57cec5SDimitry Andric void __kmp_init_nested_tas_lock(kmp_tas_lock_t *lck) {
2810b57cec5SDimitry Andric __kmp_init_tas_lock(lck);
2820b57cec5SDimitry Andric lck->lk.depth_locked = 0; // >= 0 for nestable locks, -1 for simple locks
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric
__kmp_destroy_nested_tas_lock(kmp_tas_lock_t * lck)2850b57cec5SDimitry Andric void __kmp_destroy_nested_tas_lock(kmp_tas_lock_t *lck) {
2860b57cec5SDimitry Andric __kmp_destroy_tas_lock(lck);
2870b57cec5SDimitry Andric lck->lk.depth_locked = 0;
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric
__kmp_destroy_nested_tas_lock_with_checks(kmp_tas_lock_t * lck)2900b57cec5SDimitry Andric static void __kmp_destroy_nested_tas_lock_with_checks(kmp_tas_lock_t *lck) {
2910b57cec5SDimitry Andric char const *const func = "omp_destroy_nest_lock";
2920b57cec5SDimitry Andric if (!__kmp_is_tas_lock_nestable(lck)) {
2930b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric if (__kmp_get_tas_lock_owner(lck) != -1) {
2960b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
2970b57cec5SDimitry Andric }
2980b57cec5SDimitry Andric __kmp_destroy_nested_tas_lock(lck);
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric #if KMP_USE_FUTEX
3020b57cec5SDimitry Andric
3030b57cec5SDimitry Andric /* ------------------------------------------------------------------------ */
3040b57cec5SDimitry Andric /* futex locks */
3050b57cec5SDimitry Andric
3060b57cec5SDimitry Andric // futex locks are really just test and set locks, with a different method
3070b57cec5SDimitry Andric // of handling contention. They take the same amount of space as test and
3080b57cec5SDimitry Andric // set locks, and are allocated the same way (i.e. use the area allocated by
3090b57cec5SDimitry Andric // the compiler for non-nested locks / allocate nested locks on the heap).
3100b57cec5SDimitry Andric
__kmp_get_futex_lock_owner(kmp_futex_lock_t * lck)3110b57cec5SDimitry Andric static kmp_int32 __kmp_get_futex_lock_owner(kmp_futex_lock_t *lck) {
3120b57cec5SDimitry Andric return KMP_LOCK_STRIP((TCR_4(lck->lk.poll) >> 1)) - 1;
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric
__kmp_is_futex_lock_nestable(kmp_futex_lock_t * lck)3150b57cec5SDimitry Andric static inline bool __kmp_is_futex_lock_nestable(kmp_futex_lock_t *lck) {
3160b57cec5SDimitry Andric return lck->lk.depth_locked != -1;
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric
3190b57cec5SDimitry Andric __forceinline static int
__kmp_acquire_futex_lock_timed_template(kmp_futex_lock_t * lck,kmp_int32 gtid)3200b57cec5SDimitry Andric __kmp_acquire_futex_lock_timed_template(kmp_futex_lock_t *lck, kmp_int32 gtid) {
3210b57cec5SDimitry Andric kmp_int32 gtid_code = (gtid + 1) << 1;
3220b57cec5SDimitry Andric
3230b57cec5SDimitry Andric KMP_MB();
3240b57cec5SDimitry Andric
3250b57cec5SDimitry Andric #ifdef USE_LOCK_PROFILE
3260b57cec5SDimitry Andric kmp_uint32 curr = KMP_LOCK_STRIP(TCR_4(lck->lk.poll));
3270b57cec5SDimitry Andric if ((curr != 0) && (curr != gtid_code))
3280b57cec5SDimitry Andric __kmp_printf("LOCK CONTENTION: %p\n", lck);
3290b57cec5SDimitry Andric /* else __kmp_printf( "." );*/
3300b57cec5SDimitry Andric #endif /* USE_LOCK_PROFILE */
3310b57cec5SDimitry Andric
3320b57cec5SDimitry Andric KMP_FSYNC_PREPARE(lck);
3330b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_acquire_futex_lock: lck:%p(0x%x), T#%d entering\n",
3340b57cec5SDimitry Andric lck, lck->lk.poll, gtid));
3350b57cec5SDimitry Andric
3360b57cec5SDimitry Andric kmp_int32 poll_val;
3370b57cec5SDimitry Andric
3380b57cec5SDimitry Andric while ((poll_val = KMP_COMPARE_AND_STORE_RET32(
3390b57cec5SDimitry Andric &(lck->lk.poll), KMP_LOCK_FREE(futex),
3400b57cec5SDimitry Andric KMP_LOCK_BUSY(gtid_code, futex))) != KMP_LOCK_FREE(futex)) {
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric kmp_int32 cond = KMP_LOCK_STRIP(poll_val) & 1;
3430b57cec5SDimitry Andric KA_TRACE(
3440b57cec5SDimitry Andric 1000,
3450b57cec5SDimitry Andric ("__kmp_acquire_futex_lock: lck:%p, T#%d poll_val = 0x%x cond = 0x%x\n",
3460b57cec5SDimitry Andric lck, gtid, poll_val, cond));
3470b57cec5SDimitry Andric
3480b57cec5SDimitry Andric // NOTE: if you try to use the following condition for this branch
3490b57cec5SDimitry Andric //
3500b57cec5SDimitry Andric // if ( poll_val & 1 == 0 )
3510b57cec5SDimitry Andric //
3520b57cec5SDimitry Andric // Then the 12.0 compiler has a bug where the following block will
3530b57cec5SDimitry Andric // always be skipped, regardless of the value of the LSB of poll_val.
3540b57cec5SDimitry Andric if (!cond) {
3550b57cec5SDimitry Andric // Try to set the lsb in the poll to indicate to the owner
3560b57cec5SDimitry Andric // thread that they need to wake this thread up.
3570b57cec5SDimitry Andric if (!KMP_COMPARE_AND_STORE_REL32(&(lck->lk.poll), poll_val,
3580b57cec5SDimitry Andric poll_val | KMP_LOCK_BUSY(1, futex))) {
3590b57cec5SDimitry Andric KA_TRACE(
3600b57cec5SDimitry Andric 1000,
3610b57cec5SDimitry Andric ("__kmp_acquire_futex_lock: lck:%p(0x%x), T#%d can't set bit 0\n",
3620b57cec5SDimitry Andric lck, lck->lk.poll, gtid));
3630b57cec5SDimitry Andric continue;
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric poll_val |= KMP_LOCK_BUSY(1, futex);
3660b57cec5SDimitry Andric
3670b57cec5SDimitry Andric KA_TRACE(1000,
3680b57cec5SDimitry Andric ("__kmp_acquire_futex_lock: lck:%p(0x%x), T#%d bit 0 set\n", lck,
3690b57cec5SDimitry Andric lck->lk.poll, gtid));
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric
3720b57cec5SDimitry Andric KA_TRACE(
3730b57cec5SDimitry Andric 1000,
3740b57cec5SDimitry Andric ("__kmp_acquire_futex_lock: lck:%p, T#%d before futex_wait(0x%x)\n",
3750b57cec5SDimitry Andric lck, gtid, poll_val));
3760b57cec5SDimitry Andric
377e8d8bef9SDimitry Andric long rc;
3780b57cec5SDimitry Andric if ((rc = syscall(__NR_futex, &(lck->lk.poll), FUTEX_WAIT, poll_val, NULL,
3790b57cec5SDimitry Andric NULL, 0)) != 0) {
3800b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_acquire_futex_lock: lck:%p, T#%d futex_wait(0x%x) "
381e8d8bef9SDimitry Andric "failed (rc=%ld errno=%d)\n",
3820b57cec5SDimitry Andric lck, gtid, poll_val, rc, errno));
3830b57cec5SDimitry Andric continue;
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric
3860b57cec5SDimitry Andric KA_TRACE(1000,
3870b57cec5SDimitry Andric ("__kmp_acquire_futex_lock: lck:%p, T#%d after futex_wait(0x%x)\n",
3880b57cec5SDimitry Andric lck, gtid, poll_val));
3890b57cec5SDimitry Andric // This thread has now done a successful futex wait call and was entered on
3900b57cec5SDimitry Andric // the OS futex queue. We must now perform a futex wake call when releasing
3910b57cec5SDimitry Andric // the lock, as we have no idea how many other threads are in the queue.
3920b57cec5SDimitry Andric gtid_code |= 1;
3930b57cec5SDimitry Andric }
3940b57cec5SDimitry Andric
3950b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
3960b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_acquire_futex_lock: lck:%p(0x%x), T#%d exiting\n", lck,
3970b57cec5SDimitry Andric lck->lk.poll, gtid));
3980b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric
__kmp_acquire_futex_lock(kmp_futex_lock_t * lck,kmp_int32 gtid)4010b57cec5SDimitry Andric int __kmp_acquire_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid) {
4020b57cec5SDimitry Andric int retval = __kmp_acquire_futex_lock_timed_template(lck, gtid);
4030b57cec5SDimitry Andric return retval;
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric
__kmp_acquire_futex_lock_with_checks(kmp_futex_lock_t * lck,kmp_int32 gtid)4060b57cec5SDimitry Andric static int __kmp_acquire_futex_lock_with_checks(kmp_futex_lock_t *lck,
4070b57cec5SDimitry Andric kmp_int32 gtid) {
4080b57cec5SDimitry Andric char const *const func = "omp_set_lock";
4090b57cec5SDimitry Andric if ((sizeof(kmp_futex_lock_t) <= OMP_LOCK_T_SIZE) &&
4100b57cec5SDimitry Andric __kmp_is_futex_lock_nestable(lck)) {
4110b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_futex_lock_owner(lck) == gtid)) {
4140b57cec5SDimitry Andric KMP_FATAL(LockIsAlreadyOwned, func);
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric return __kmp_acquire_futex_lock(lck, gtid);
4170b57cec5SDimitry Andric }
4180b57cec5SDimitry Andric
__kmp_test_futex_lock(kmp_futex_lock_t * lck,kmp_int32 gtid)4190b57cec5SDimitry Andric int __kmp_test_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid) {
4200b57cec5SDimitry Andric if (KMP_COMPARE_AND_STORE_ACQ32(&(lck->lk.poll), KMP_LOCK_FREE(futex),
4210b57cec5SDimitry Andric KMP_LOCK_BUSY((gtid + 1) << 1, futex))) {
4220b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
4230b57cec5SDimitry Andric return TRUE;
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric return FALSE;
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric
__kmp_test_futex_lock_with_checks(kmp_futex_lock_t * lck,kmp_int32 gtid)4280b57cec5SDimitry Andric static int __kmp_test_futex_lock_with_checks(kmp_futex_lock_t *lck,
4290b57cec5SDimitry Andric kmp_int32 gtid) {
4300b57cec5SDimitry Andric char const *const func = "omp_test_lock";
4310b57cec5SDimitry Andric if ((sizeof(kmp_futex_lock_t) <= OMP_LOCK_T_SIZE) &&
4320b57cec5SDimitry Andric __kmp_is_futex_lock_nestable(lck)) {
4330b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric return __kmp_test_futex_lock(lck, gtid);
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric
__kmp_release_futex_lock(kmp_futex_lock_t * lck,kmp_int32 gtid)4380b57cec5SDimitry Andric int __kmp_release_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid) {
4390b57cec5SDimitry Andric KMP_MB(); /* Flush all pending memory write invalidates. */
4400b57cec5SDimitry Andric
4410b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_release_futex_lock: lck:%p(0x%x), T#%d entering\n",
4420b57cec5SDimitry Andric lck, lck->lk.poll, gtid));
4430b57cec5SDimitry Andric
4440b57cec5SDimitry Andric KMP_FSYNC_RELEASING(lck);
4450b57cec5SDimitry Andric
4460b57cec5SDimitry Andric kmp_int32 poll_val = KMP_XCHG_FIXED32(&(lck->lk.poll), KMP_LOCK_FREE(futex));
4470b57cec5SDimitry Andric
4480b57cec5SDimitry Andric KA_TRACE(1000,
4490b57cec5SDimitry Andric ("__kmp_release_futex_lock: lck:%p, T#%d released poll_val = 0x%x\n",
4500b57cec5SDimitry Andric lck, gtid, poll_val));
4510b57cec5SDimitry Andric
4520b57cec5SDimitry Andric if (KMP_LOCK_STRIP(poll_val) & 1) {
4530b57cec5SDimitry Andric KA_TRACE(1000,
4540b57cec5SDimitry Andric ("__kmp_release_futex_lock: lck:%p, T#%d futex_wake 1 thread\n",
4550b57cec5SDimitry Andric lck, gtid));
4560b57cec5SDimitry Andric syscall(__NR_futex, &(lck->lk.poll), FUTEX_WAKE, KMP_LOCK_BUSY(1, futex),
4570b57cec5SDimitry Andric NULL, NULL, 0);
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric KMP_MB(); /* Flush all pending memory write invalidates. */
4610b57cec5SDimitry Andric
4620b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_release_futex_lock: lck:%p(0x%x), T#%d exiting\n", lck,
4630b57cec5SDimitry Andric lck->lk.poll, gtid));
4640b57cec5SDimitry Andric
4650b57cec5SDimitry Andric KMP_YIELD_OVERSUB();
4660b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
4670b57cec5SDimitry Andric }
4680b57cec5SDimitry Andric
__kmp_release_futex_lock_with_checks(kmp_futex_lock_t * lck,kmp_int32 gtid)4690b57cec5SDimitry Andric static int __kmp_release_futex_lock_with_checks(kmp_futex_lock_t *lck,
4700b57cec5SDimitry Andric kmp_int32 gtid) {
4710b57cec5SDimitry Andric char const *const func = "omp_unset_lock";
4720b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
4730b57cec5SDimitry Andric if ((sizeof(kmp_futex_lock_t) <= OMP_LOCK_T_SIZE) &&
4740b57cec5SDimitry Andric __kmp_is_futex_lock_nestable(lck)) {
4750b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
4760b57cec5SDimitry Andric }
4770b57cec5SDimitry Andric if (__kmp_get_futex_lock_owner(lck) == -1) {
4780b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
4790b57cec5SDimitry Andric }
4800b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_futex_lock_owner(lck) >= 0) &&
4810b57cec5SDimitry Andric (__kmp_get_futex_lock_owner(lck) != gtid)) {
4820b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric return __kmp_release_futex_lock(lck, gtid);
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric
__kmp_init_futex_lock(kmp_futex_lock_t * lck)4870b57cec5SDimitry Andric void __kmp_init_futex_lock(kmp_futex_lock_t *lck) {
4880b57cec5SDimitry Andric TCW_4(lck->lk.poll, KMP_LOCK_FREE(futex));
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric
__kmp_destroy_futex_lock(kmp_futex_lock_t * lck)4910b57cec5SDimitry Andric void __kmp_destroy_futex_lock(kmp_futex_lock_t *lck) { lck->lk.poll = 0; }
4920b57cec5SDimitry Andric
__kmp_destroy_futex_lock_with_checks(kmp_futex_lock_t * lck)4930b57cec5SDimitry Andric static void __kmp_destroy_futex_lock_with_checks(kmp_futex_lock_t *lck) {
4940b57cec5SDimitry Andric char const *const func = "omp_destroy_lock";
4950b57cec5SDimitry Andric if ((sizeof(kmp_futex_lock_t) <= OMP_LOCK_T_SIZE) &&
4960b57cec5SDimitry Andric __kmp_is_futex_lock_nestable(lck)) {
4970b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
4980b57cec5SDimitry Andric }
4990b57cec5SDimitry Andric if (__kmp_get_futex_lock_owner(lck) != -1) {
5000b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
5010b57cec5SDimitry Andric }
5020b57cec5SDimitry Andric __kmp_destroy_futex_lock(lck);
5030b57cec5SDimitry Andric }
5040b57cec5SDimitry Andric
5050b57cec5SDimitry Andric // nested futex locks
5060b57cec5SDimitry Andric
__kmp_acquire_nested_futex_lock(kmp_futex_lock_t * lck,kmp_int32 gtid)5070b57cec5SDimitry Andric int __kmp_acquire_nested_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid) {
5080b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
5090b57cec5SDimitry Andric
5100b57cec5SDimitry Andric if (__kmp_get_futex_lock_owner(lck) == gtid) {
5110b57cec5SDimitry Andric lck->lk.depth_locked += 1;
5120b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_NEXT;
5130b57cec5SDimitry Andric } else {
5140b57cec5SDimitry Andric __kmp_acquire_futex_lock_timed_template(lck, gtid);
5150b57cec5SDimitry Andric lck->lk.depth_locked = 1;
5160b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
5170b57cec5SDimitry Andric }
5180b57cec5SDimitry Andric }
5190b57cec5SDimitry Andric
__kmp_acquire_nested_futex_lock_with_checks(kmp_futex_lock_t * lck,kmp_int32 gtid)5200b57cec5SDimitry Andric static int __kmp_acquire_nested_futex_lock_with_checks(kmp_futex_lock_t *lck,
5210b57cec5SDimitry Andric kmp_int32 gtid) {
5220b57cec5SDimitry Andric char const *const func = "omp_set_nest_lock";
5230b57cec5SDimitry Andric if (!__kmp_is_futex_lock_nestable(lck)) {
5240b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
5250b57cec5SDimitry Andric }
5260b57cec5SDimitry Andric return __kmp_acquire_nested_futex_lock(lck, gtid);
5270b57cec5SDimitry Andric }
5280b57cec5SDimitry Andric
__kmp_test_nested_futex_lock(kmp_futex_lock_t * lck,kmp_int32 gtid)5290b57cec5SDimitry Andric int __kmp_test_nested_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid) {
5300b57cec5SDimitry Andric int retval;
5310b57cec5SDimitry Andric
5320b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
5330b57cec5SDimitry Andric
5340b57cec5SDimitry Andric if (__kmp_get_futex_lock_owner(lck) == gtid) {
5350b57cec5SDimitry Andric retval = ++lck->lk.depth_locked;
5360b57cec5SDimitry Andric } else if (!__kmp_test_futex_lock(lck, gtid)) {
5370b57cec5SDimitry Andric retval = 0;
5380b57cec5SDimitry Andric } else {
5390b57cec5SDimitry Andric KMP_MB();
5400b57cec5SDimitry Andric retval = lck->lk.depth_locked = 1;
5410b57cec5SDimitry Andric }
5420b57cec5SDimitry Andric return retval;
5430b57cec5SDimitry Andric }
5440b57cec5SDimitry Andric
__kmp_test_nested_futex_lock_with_checks(kmp_futex_lock_t * lck,kmp_int32 gtid)5450b57cec5SDimitry Andric static int __kmp_test_nested_futex_lock_with_checks(kmp_futex_lock_t *lck,
5460b57cec5SDimitry Andric kmp_int32 gtid) {
5470b57cec5SDimitry Andric char const *const func = "omp_test_nest_lock";
5480b57cec5SDimitry Andric if (!__kmp_is_futex_lock_nestable(lck)) {
5490b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
5500b57cec5SDimitry Andric }
5510b57cec5SDimitry Andric return __kmp_test_nested_futex_lock(lck, gtid);
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric
__kmp_release_nested_futex_lock(kmp_futex_lock_t * lck,kmp_int32 gtid)5540b57cec5SDimitry Andric int __kmp_release_nested_futex_lock(kmp_futex_lock_t *lck, kmp_int32 gtid) {
5550b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
5560b57cec5SDimitry Andric
5570b57cec5SDimitry Andric KMP_MB();
5580b57cec5SDimitry Andric if (--(lck->lk.depth_locked) == 0) {
5590b57cec5SDimitry Andric __kmp_release_futex_lock(lck, gtid);
5600b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
5610b57cec5SDimitry Andric }
5620b57cec5SDimitry Andric return KMP_LOCK_STILL_HELD;
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric
__kmp_release_nested_futex_lock_with_checks(kmp_futex_lock_t * lck,kmp_int32 gtid)5650b57cec5SDimitry Andric static int __kmp_release_nested_futex_lock_with_checks(kmp_futex_lock_t *lck,
5660b57cec5SDimitry Andric kmp_int32 gtid) {
5670b57cec5SDimitry Andric char const *const func = "omp_unset_nest_lock";
5680b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
5690b57cec5SDimitry Andric if (!__kmp_is_futex_lock_nestable(lck)) {
5700b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
5710b57cec5SDimitry Andric }
5720b57cec5SDimitry Andric if (__kmp_get_futex_lock_owner(lck) == -1) {
5730b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
5740b57cec5SDimitry Andric }
5750b57cec5SDimitry Andric if (__kmp_get_futex_lock_owner(lck) != gtid) {
5760b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric return __kmp_release_nested_futex_lock(lck, gtid);
5790b57cec5SDimitry Andric }
5800b57cec5SDimitry Andric
__kmp_init_nested_futex_lock(kmp_futex_lock_t * lck)5810b57cec5SDimitry Andric void __kmp_init_nested_futex_lock(kmp_futex_lock_t *lck) {
5820b57cec5SDimitry Andric __kmp_init_futex_lock(lck);
5830b57cec5SDimitry Andric lck->lk.depth_locked = 0; // >= 0 for nestable locks, -1 for simple locks
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric
__kmp_destroy_nested_futex_lock(kmp_futex_lock_t * lck)5860b57cec5SDimitry Andric void __kmp_destroy_nested_futex_lock(kmp_futex_lock_t *lck) {
5870b57cec5SDimitry Andric __kmp_destroy_futex_lock(lck);
5880b57cec5SDimitry Andric lck->lk.depth_locked = 0;
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric
__kmp_destroy_nested_futex_lock_with_checks(kmp_futex_lock_t * lck)5910b57cec5SDimitry Andric static void __kmp_destroy_nested_futex_lock_with_checks(kmp_futex_lock_t *lck) {
5920b57cec5SDimitry Andric char const *const func = "omp_destroy_nest_lock";
5930b57cec5SDimitry Andric if (!__kmp_is_futex_lock_nestable(lck)) {
5940b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
5950b57cec5SDimitry Andric }
5960b57cec5SDimitry Andric if (__kmp_get_futex_lock_owner(lck) != -1) {
5970b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
5980b57cec5SDimitry Andric }
5990b57cec5SDimitry Andric __kmp_destroy_nested_futex_lock(lck);
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric #endif // KMP_USE_FUTEX
6030b57cec5SDimitry Andric
6040b57cec5SDimitry Andric /* ------------------------------------------------------------------------ */
6050b57cec5SDimitry Andric /* ticket (bakery) locks */
6060b57cec5SDimitry Andric
__kmp_get_ticket_lock_owner(kmp_ticket_lock_t * lck)6070b57cec5SDimitry Andric static kmp_int32 __kmp_get_ticket_lock_owner(kmp_ticket_lock_t *lck) {
6080b57cec5SDimitry Andric return std::atomic_load_explicit(&lck->lk.owner_id,
6090b57cec5SDimitry Andric std::memory_order_relaxed) -
6100b57cec5SDimitry Andric 1;
6110b57cec5SDimitry Andric }
6120b57cec5SDimitry Andric
__kmp_is_ticket_lock_nestable(kmp_ticket_lock_t * lck)6130b57cec5SDimitry Andric static inline bool __kmp_is_ticket_lock_nestable(kmp_ticket_lock_t *lck) {
6140b57cec5SDimitry Andric return std::atomic_load_explicit(&lck->lk.depth_locked,
6150b57cec5SDimitry Andric std::memory_order_relaxed) != -1;
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric
__kmp_bakery_check(void * now_serving,kmp_uint32 my_ticket)6180b57cec5SDimitry Andric static kmp_uint32 __kmp_bakery_check(void *now_serving, kmp_uint32 my_ticket) {
6190b57cec5SDimitry Andric return std::atomic_load_explicit((std::atomic<unsigned> *)now_serving,
6200b57cec5SDimitry Andric std::memory_order_acquire) == my_ticket;
6210b57cec5SDimitry Andric }
6220b57cec5SDimitry Andric
6230b57cec5SDimitry Andric __forceinline static int
__kmp_acquire_ticket_lock_timed_template(kmp_ticket_lock_t * lck,kmp_int32 gtid)6240b57cec5SDimitry Andric __kmp_acquire_ticket_lock_timed_template(kmp_ticket_lock_t *lck,
6250b57cec5SDimitry Andric kmp_int32 gtid) {
6260b57cec5SDimitry Andric kmp_uint32 my_ticket = std::atomic_fetch_add_explicit(
6270b57cec5SDimitry Andric &lck->lk.next_ticket, 1U, std::memory_order_relaxed);
6280b57cec5SDimitry Andric
6290b57cec5SDimitry Andric #ifdef USE_LOCK_PROFILE
6300b57cec5SDimitry Andric if (std::atomic_load_explicit(&lck->lk.now_serving,
6310b57cec5SDimitry Andric std::memory_order_relaxed) != my_ticket)
6320b57cec5SDimitry Andric __kmp_printf("LOCK CONTENTION: %p\n", lck);
6330b57cec5SDimitry Andric /* else __kmp_printf( "." );*/
6340b57cec5SDimitry Andric #endif /* USE_LOCK_PROFILE */
6350b57cec5SDimitry Andric
6360b57cec5SDimitry Andric if (std::atomic_load_explicit(&lck->lk.now_serving,
6370b57cec5SDimitry Andric std::memory_order_acquire) == my_ticket) {
6380b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
6390b57cec5SDimitry Andric }
6400b57cec5SDimitry Andric KMP_WAIT_PTR(&lck->lk.now_serving, my_ticket, __kmp_bakery_check, lck);
6410b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
6420b57cec5SDimitry Andric }
6430b57cec5SDimitry Andric
__kmp_acquire_ticket_lock(kmp_ticket_lock_t * lck,kmp_int32 gtid)6440b57cec5SDimitry Andric int __kmp_acquire_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid) {
6450b57cec5SDimitry Andric int retval = __kmp_acquire_ticket_lock_timed_template(lck, gtid);
6460b57cec5SDimitry Andric return retval;
6470b57cec5SDimitry Andric }
6480b57cec5SDimitry Andric
__kmp_acquire_ticket_lock_with_checks(kmp_ticket_lock_t * lck,kmp_int32 gtid)6490b57cec5SDimitry Andric static int __kmp_acquire_ticket_lock_with_checks(kmp_ticket_lock_t *lck,
6500b57cec5SDimitry Andric kmp_int32 gtid) {
6510b57cec5SDimitry Andric char const *const func = "omp_set_lock";
6520b57cec5SDimitry Andric
6530b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
6540b57cec5SDimitry Andric std::memory_order_relaxed)) {
6550b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
6560b57cec5SDimitry Andric }
6570b57cec5SDimitry Andric if (lck->lk.self != lck) {
6580b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
6590b57cec5SDimitry Andric }
6600b57cec5SDimitry Andric if (__kmp_is_ticket_lock_nestable(lck)) {
6610b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_ticket_lock_owner(lck) == gtid)) {
6640b57cec5SDimitry Andric KMP_FATAL(LockIsAlreadyOwned, func);
6650b57cec5SDimitry Andric }
6660b57cec5SDimitry Andric
6670b57cec5SDimitry Andric __kmp_acquire_ticket_lock(lck, gtid);
6680b57cec5SDimitry Andric
6690b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.owner_id, gtid + 1,
6700b57cec5SDimitry Andric std::memory_order_relaxed);
6710b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric
__kmp_test_ticket_lock(kmp_ticket_lock_t * lck,kmp_int32 gtid)6740b57cec5SDimitry Andric int __kmp_test_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid) {
6750b57cec5SDimitry Andric kmp_uint32 my_ticket = std::atomic_load_explicit(&lck->lk.next_ticket,
6760b57cec5SDimitry Andric std::memory_order_relaxed);
6770b57cec5SDimitry Andric
6780b57cec5SDimitry Andric if (std::atomic_load_explicit(&lck->lk.now_serving,
6790b57cec5SDimitry Andric std::memory_order_relaxed) == my_ticket) {
6800b57cec5SDimitry Andric kmp_uint32 next_ticket = my_ticket + 1;
6810b57cec5SDimitry Andric if (std::atomic_compare_exchange_strong_explicit(
6820b57cec5SDimitry Andric &lck->lk.next_ticket, &my_ticket, next_ticket,
6830b57cec5SDimitry Andric std::memory_order_acquire, std::memory_order_acquire)) {
6840b57cec5SDimitry Andric return TRUE;
6850b57cec5SDimitry Andric }
6860b57cec5SDimitry Andric }
6870b57cec5SDimitry Andric return FALSE;
6880b57cec5SDimitry Andric }
6890b57cec5SDimitry Andric
__kmp_test_ticket_lock_with_checks(kmp_ticket_lock_t * lck,kmp_int32 gtid)6900b57cec5SDimitry Andric static int __kmp_test_ticket_lock_with_checks(kmp_ticket_lock_t *lck,
6910b57cec5SDimitry Andric kmp_int32 gtid) {
6920b57cec5SDimitry Andric char const *const func = "omp_test_lock";
6930b57cec5SDimitry Andric
6940b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
6950b57cec5SDimitry Andric std::memory_order_relaxed)) {
6960b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
6970b57cec5SDimitry Andric }
6980b57cec5SDimitry Andric if (lck->lk.self != lck) {
6990b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
7000b57cec5SDimitry Andric }
7010b57cec5SDimitry Andric if (__kmp_is_ticket_lock_nestable(lck)) {
7020b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
7030b57cec5SDimitry Andric }
7040b57cec5SDimitry Andric
7050b57cec5SDimitry Andric int retval = __kmp_test_ticket_lock(lck, gtid);
7060b57cec5SDimitry Andric
7070b57cec5SDimitry Andric if (retval) {
7080b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.owner_id, gtid + 1,
7090b57cec5SDimitry Andric std::memory_order_relaxed);
7100b57cec5SDimitry Andric }
7110b57cec5SDimitry Andric return retval;
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric
__kmp_release_ticket_lock(kmp_ticket_lock_t * lck,kmp_int32 gtid)7140b57cec5SDimitry Andric int __kmp_release_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid) {
7150b57cec5SDimitry Andric kmp_uint32 distance = std::atomic_load_explicit(&lck->lk.next_ticket,
7160b57cec5SDimitry Andric std::memory_order_relaxed) -
7170b57cec5SDimitry Andric std::atomic_load_explicit(&lck->lk.now_serving,
7180b57cec5SDimitry Andric std::memory_order_relaxed);
7190b57cec5SDimitry Andric
7200b57cec5SDimitry Andric std::atomic_fetch_add_explicit(&lck->lk.now_serving, 1U,
7210b57cec5SDimitry Andric std::memory_order_release);
7220b57cec5SDimitry Andric
7230b57cec5SDimitry Andric KMP_YIELD(distance >
7240b57cec5SDimitry Andric (kmp_uint32)(__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc));
7250b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
7260b57cec5SDimitry Andric }
7270b57cec5SDimitry Andric
__kmp_release_ticket_lock_with_checks(kmp_ticket_lock_t * lck,kmp_int32 gtid)7280b57cec5SDimitry Andric static int __kmp_release_ticket_lock_with_checks(kmp_ticket_lock_t *lck,
7290b57cec5SDimitry Andric kmp_int32 gtid) {
7300b57cec5SDimitry Andric char const *const func = "omp_unset_lock";
7310b57cec5SDimitry Andric
7320b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
7330b57cec5SDimitry Andric std::memory_order_relaxed)) {
7340b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
7350b57cec5SDimitry Andric }
7360b57cec5SDimitry Andric if (lck->lk.self != lck) {
7370b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
7380b57cec5SDimitry Andric }
7390b57cec5SDimitry Andric if (__kmp_is_ticket_lock_nestable(lck)) {
7400b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric if (__kmp_get_ticket_lock_owner(lck) == -1) {
7430b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_ticket_lock_owner(lck) >= 0) &&
7460b57cec5SDimitry Andric (__kmp_get_ticket_lock_owner(lck) != gtid)) {
7470b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
7480b57cec5SDimitry Andric }
7490b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.owner_id, 0, std::memory_order_relaxed);
7500b57cec5SDimitry Andric return __kmp_release_ticket_lock(lck, gtid);
7510b57cec5SDimitry Andric }
7520b57cec5SDimitry Andric
__kmp_init_ticket_lock(kmp_ticket_lock_t * lck)7530b57cec5SDimitry Andric void __kmp_init_ticket_lock(kmp_ticket_lock_t *lck) {
7540b57cec5SDimitry Andric lck->lk.location = NULL;
7550b57cec5SDimitry Andric lck->lk.self = lck;
7560b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.next_ticket, 0U,
7570b57cec5SDimitry Andric std::memory_order_relaxed);
7580b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.now_serving, 0U,
7590b57cec5SDimitry Andric std::memory_order_relaxed);
7600b57cec5SDimitry Andric std::atomic_store_explicit(
7610b57cec5SDimitry Andric &lck->lk.owner_id, 0,
7620b57cec5SDimitry Andric std::memory_order_relaxed); // no thread owns the lock.
7630b57cec5SDimitry Andric std::atomic_store_explicit(
7640b57cec5SDimitry Andric &lck->lk.depth_locked, -1,
7650b57cec5SDimitry Andric std::memory_order_relaxed); // -1 => not a nested lock.
7660b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.initialized, true,
7670b57cec5SDimitry Andric std::memory_order_release);
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric
__kmp_destroy_ticket_lock(kmp_ticket_lock_t * lck)7700b57cec5SDimitry Andric void __kmp_destroy_ticket_lock(kmp_ticket_lock_t *lck) {
7710b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.initialized, false,
7720b57cec5SDimitry Andric std::memory_order_release);
7730b57cec5SDimitry Andric lck->lk.self = NULL;
7740b57cec5SDimitry Andric lck->lk.location = NULL;
7750b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.next_ticket, 0U,
7760b57cec5SDimitry Andric std::memory_order_relaxed);
7770b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.now_serving, 0U,
7780b57cec5SDimitry Andric std::memory_order_relaxed);
7790b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.owner_id, 0, std::memory_order_relaxed);
7800b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.depth_locked, -1,
7810b57cec5SDimitry Andric std::memory_order_relaxed);
7820b57cec5SDimitry Andric }
7830b57cec5SDimitry Andric
__kmp_destroy_ticket_lock_with_checks(kmp_ticket_lock_t * lck)7840b57cec5SDimitry Andric static void __kmp_destroy_ticket_lock_with_checks(kmp_ticket_lock_t *lck) {
7850b57cec5SDimitry Andric char const *const func = "omp_destroy_lock";
7860b57cec5SDimitry Andric
7870b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
7880b57cec5SDimitry Andric std::memory_order_relaxed)) {
7890b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
7900b57cec5SDimitry Andric }
7910b57cec5SDimitry Andric if (lck->lk.self != lck) {
7920b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
7930b57cec5SDimitry Andric }
7940b57cec5SDimitry Andric if (__kmp_is_ticket_lock_nestable(lck)) {
7950b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
7960b57cec5SDimitry Andric }
7970b57cec5SDimitry Andric if (__kmp_get_ticket_lock_owner(lck) != -1) {
7980b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
7990b57cec5SDimitry Andric }
8000b57cec5SDimitry Andric __kmp_destroy_ticket_lock(lck);
8010b57cec5SDimitry Andric }
8020b57cec5SDimitry Andric
8030b57cec5SDimitry Andric // nested ticket locks
8040b57cec5SDimitry Andric
__kmp_acquire_nested_ticket_lock(kmp_ticket_lock_t * lck,kmp_int32 gtid)8050b57cec5SDimitry Andric int __kmp_acquire_nested_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid) {
8060b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
8070b57cec5SDimitry Andric
8080b57cec5SDimitry Andric if (__kmp_get_ticket_lock_owner(lck) == gtid) {
8090b57cec5SDimitry Andric std::atomic_fetch_add_explicit(&lck->lk.depth_locked, 1,
8100b57cec5SDimitry Andric std::memory_order_relaxed);
8110b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_NEXT;
8120b57cec5SDimitry Andric } else {
8130b57cec5SDimitry Andric __kmp_acquire_ticket_lock_timed_template(lck, gtid);
8140b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.depth_locked, 1,
8150b57cec5SDimitry Andric std::memory_order_relaxed);
8160b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.owner_id, gtid + 1,
8170b57cec5SDimitry Andric std::memory_order_relaxed);
8180b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric }
8210b57cec5SDimitry Andric
__kmp_acquire_nested_ticket_lock_with_checks(kmp_ticket_lock_t * lck,kmp_int32 gtid)8220b57cec5SDimitry Andric static int __kmp_acquire_nested_ticket_lock_with_checks(kmp_ticket_lock_t *lck,
8230b57cec5SDimitry Andric kmp_int32 gtid) {
8240b57cec5SDimitry Andric char const *const func = "omp_set_nest_lock";
8250b57cec5SDimitry Andric
8260b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
8270b57cec5SDimitry Andric std::memory_order_relaxed)) {
8280b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric if (lck->lk.self != lck) {
8310b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
8320b57cec5SDimitry Andric }
8330b57cec5SDimitry Andric if (!__kmp_is_ticket_lock_nestable(lck)) {
8340b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
8350b57cec5SDimitry Andric }
8360b57cec5SDimitry Andric return __kmp_acquire_nested_ticket_lock(lck, gtid);
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric
__kmp_test_nested_ticket_lock(kmp_ticket_lock_t * lck,kmp_int32 gtid)8390b57cec5SDimitry Andric int __kmp_test_nested_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid) {
8400b57cec5SDimitry Andric int retval;
8410b57cec5SDimitry Andric
8420b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
8430b57cec5SDimitry Andric
8440b57cec5SDimitry Andric if (__kmp_get_ticket_lock_owner(lck) == gtid) {
8450b57cec5SDimitry Andric retval = std::atomic_fetch_add_explicit(&lck->lk.depth_locked, 1,
8460b57cec5SDimitry Andric std::memory_order_relaxed) +
8470b57cec5SDimitry Andric 1;
8480b57cec5SDimitry Andric } else if (!__kmp_test_ticket_lock(lck, gtid)) {
8490b57cec5SDimitry Andric retval = 0;
8500b57cec5SDimitry Andric } else {
8510b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.depth_locked, 1,
8520b57cec5SDimitry Andric std::memory_order_relaxed);
8530b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.owner_id, gtid + 1,
8540b57cec5SDimitry Andric std::memory_order_relaxed);
8550b57cec5SDimitry Andric retval = 1;
8560b57cec5SDimitry Andric }
8570b57cec5SDimitry Andric return retval;
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric
__kmp_test_nested_ticket_lock_with_checks(kmp_ticket_lock_t * lck,kmp_int32 gtid)8600b57cec5SDimitry Andric static int __kmp_test_nested_ticket_lock_with_checks(kmp_ticket_lock_t *lck,
8610b57cec5SDimitry Andric kmp_int32 gtid) {
8620b57cec5SDimitry Andric char const *const func = "omp_test_nest_lock";
8630b57cec5SDimitry Andric
8640b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
8650b57cec5SDimitry Andric std::memory_order_relaxed)) {
8660b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
8670b57cec5SDimitry Andric }
8680b57cec5SDimitry Andric if (lck->lk.self != lck) {
8690b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
8700b57cec5SDimitry Andric }
8710b57cec5SDimitry Andric if (!__kmp_is_ticket_lock_nestable(lck)) {
8720b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
8730b57cec5SDimitry Andric }
8740b57cec5SDimitry Andric return __kmp_test_nested_ticket_lock(lck, gtid);
8750b57cec5SDimitry Andric }
8760b57cec5SDimitry Andric
__kmp_release_nested_ticket_lock(kmp_ticket_lock_t * lck,kmp_int32 gtid)8770b57cec5SDimitry Andric int __kmp_release_nested_ticket_lock(kmp_ticket_lock_t *lck, kmp_int32 gtid) {
8780b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
8790b57cec5SDimitry Andric
8800b57cec5SDimitry Andric if ((std::atomic_fetch_add_explicit(&lck->lk.depth_locked, -1,
8810b57cec5SDimitry Andric std::memory_order_relaxed) -
8820b57cec5SDimitry Andric 1) == 0) {
8830b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.owner_id, 0, std::memory_order_relaxed);
8840b57cec5SDimitry Andric __kmp_release_ticket_lock(lck, gtid);
8850b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
8860b57cec5SDimitry Andric }
8870b57cec5SDimitry Andric return KMP_LOCK_STILL_HELD;
8880b57cec5SDimitry Andric }
8890b57cec5SDimitry Andric
__kmp_release_nested_ticket_lock_with_checks(kmp_ticket_lock_t * lck,kmp_int32 gtid)8900b57cec5SDimitry Andric static int __kmp_release_nested_ticket_lock_with_checks(kmp_ticket_lock_t *lck,
8910b57cec5SDimitry Andric kmp_int32 gtid) {
8920b57cec5SDimitry Andric char const *const func = "omp_unset_nest_lock";
8930b57cec5SDimitry Andric
8940b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
8950b57cec5SDimitry Andric std::memory_order_relaxed)) {
8960b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
8970b57cec5SDimitry Andric }
8980b57cec5SDimitry Andric if (lck->lk.self != lck) {
8990b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
9000b57cec5SDimitry Andric }
9010b57cec5SDimitry Andric if (!__kmp_is_ticket_lock_nestable(lck)) {
9020b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
9030b57cec5SDimitry Andric }
9040b57cec5SDimitry Andric if (__kmp_get_ticket_lock_owner(lck) == -1) {
9050b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
9060b57cec5SDimitry Andric }
9070b57cec5SDimitry Andric if (__kmp_get_ticket_lock_owner(lck) != gtid) {
9080b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
9090b57cec5SDimitry Andric }
9100b57cec5SDimitry Andric return __kmp_release_nested_ticket_lock(lck, gtid);
9110b57cec5SDimitry Andric }
9120b57cec5SDimitry Andric
__kmp_init_nested_ticket_lock(kmp_ticket_lock_t * lck)9130b57cec5SDimitry Andric void __kmp_init_nested_ticket_lock(kmp_ticket_lock_t *lck) {
9140b57cec5SDimitry Andric __kmp_init_ticket_lock(lck);
9150b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.depth_locked, 0,
9160b57cec5SDimitry Andric std::memory_order_relaxed);
9170b57cec5SDimitry Andric // >= 0 for nestable locks, -1 for simple locks
9180b57cec5SDimitry Andric }
9190b57cec5SDimitry Andric
__kmp_destroy_nested_ticket_lock(kmp_ticket_lock_t * lck)9200b57cec5SDimitry Andric void __kmp_destroy_nested_ticket_lock(kmp_ticket_lock_t *lck) {
9210b57cec5SDimitry Andric __kmp_destroy_ticket_lock(lck);
9220b57cec5SDimitry Andric std::atomic_store_explicit(&lck->lk.depth_locked, 0,
9230b57cec5SDimitry Andric std::memory_order_relaxed);
9240b57cec5SDimitry Andric }
9250b57cec5SDimitry Andric
9260b57cec5SDimitry Andric static void
__kmp_destroy_nested_ticket_lock_with_checks(kmp_ticket_lock_t * lck)9270b57cec5SDimitry Andric __kmp_destroy_nested_ticket_lock_with_checks(kmp_ticket_lock_t *lck) {
9280b57cec5SDimitry Andric char const *const func = "omp_destroy_nest_lock";
9290b57cec5SDimitry Andric
9300b57cec5SDimitry Andric if (!std::atomic_load_explicit(&lck->lk.initialized,
9310b57cec5SDimitry Andric std::memory_order_relaxed)) {
9320b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
9330b57cec5SDimitry Andric }
9340b57cec5SDimitry Andric if (lck->lk.self != lck) {
9350b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
9360b57cec5SDimitry Andric }
9370b57cec5SDimitry Andric if (!__kmp_is_ticket_lock_nestable(lck)) {
9380b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric if (__kmp_get_ticket_lock_owner(lck) != -1) {
9410b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
9420b57cec5SDimitry Andric }
9430b57cec5SDimitry Andric __kmp_destroy_nested_ticket_lock(lck);
9440b57cec5SDimitry Andric }
9450b57cec5SDimitry Andric
9460b57cec5SDimitry Andric // access functions to fields which don't exist for all lock kinds.
9470b57cec5SDimitry Andric
__kmp_get_ticket_lock_location(kmp_ticket_lock_t * lck)9480b57cec5SDimitry Andric static const ident_t *__kmp_get_ticket_lock_location(kmp_ticket_lock_t *lck) {
9490b57cec5SDimitry Andric return lck->lk.location;
9500b57cec5SDimitry Andric }
9510b57cec5SDimitry Andric
__kmp_set_ticket_lock_location(kmp_ticket_lock_t * lck,const ident_t * loc)9520b57cec5SDimitry Andric static void __kmp_set_ticket_lock_location(kmp_ticket_lock_t *lck,
9530b57cec5SDimitry Andric const ident_t *loc) {
9540b57cec5SDimitry Andric lck->lk.location = loc;
9550b57cec5SDimitry Andric }
9560b57cec5SDimitry Andric
__kmp_get_ticket_lock_flags(kmp_ticket_lock_t * lck)9570b57cec5SDimitry Andric static kmp_lock_flags_t __kmp_get_ticket_lock_flags(kmp_ticket_lock_t *lck) {
9580b57cec5SDimitry Andric return lck->lk.flags;
9590b57cec5SDimitry Andric }
9600b57cec5SDimitry Andric
__kmp_set_ticket_lock_flags(kmp_ticket_lock_t * lck,kmp_lock_flags_t flags)9610b57cec5SDimitry Andric static void __kmp_set_ticket_lock_flags(kmp_ticket_lock_t *lck,
9620b57cec5SDimitry Andric kmp_lock_flags_t flags) {
9630b57cec5SDimitry Andric lck->lk.flags = flags;
9640b57cec5SDimitry Andric }
9650b57cec5SDimitry Andric
9660b57cec5SDimitry Andric /* ------------------------------------------------------------------------ */
9670b57cec5SDimitry Andric /* queuing locks */
9680b57cec5SDimitry Andric
9690b57cec5SDimitry Andric /* First the states
9700b57cec5SDimitry Andric (head,tail) = 0, 0 means lock is unheld, nobody on queue
9710b57cec5SDimitry Andric UINT_MAX or -1, 0 means lock is held, nobody on queue
9720b57cec5SDimitry Andric h, h means lock held or about to transition,
9730b57cec5SDimitry Andric 1 element on queue
9740b57cec5SDimitry Andric h, t h <> t, means lock is held or about to
9750b57cec5SDimitry Andric transition, >1 elements on queue
9760b57cec5SDimitry Andric
9770b57cec5SDimitry Andric Now the transitions
9780b57cec5SDimitry Andric Acquire(0,0) = -1 ,0
9790b57cec5SDimitry Andric Release(0,0) = Error
9800b57cec5SDimitry Andric Acquire(-1,0) = h ,h h > 0
9810b57cec5SDimitry Andric Release(-1,0) = 0 ,0
9820b57cec5SDimitry Andric Acquire(h,h) = h ,t h > 0, t > 0, h <> t
9830b57cec5SDimitry Andric Release(h,h) = -1 ,0 h > 0
9840b57cec5SDimitry Andric Acquire(h,t) = h ,t' h > 0, t > 0, t' > 0, h <> t, h <> t', t <> t'
9850b57cec5SDimitry Andric Release(h,t) = h',t h > 0, t > 0, h <> t, h <> h', h' maybe = t
9860b57cec5SDimitry Andric
9870b57cec5SDimitry Andric And pictorially
9880b57cec5SDimitry Andric
9890b57cec5SDimitry Andric +-----+
9900b57cec5SDimitry Andric | 0, 0|------- release -------> Error
9910b57cec5SDimitry Andric +-----+
9920b57cec5SDimitry Andric | ^
9930b57cec5SDimitry Andric acquire| |release
9940b57cec5SDimitry Andric | |
9950b57cec5SDimitry Andric | |
9960b57cec5SDimitry Andric v |
9970b57cec5SDimitry Andric +-----+
9980b57cec5SDimitry Andric |-1, 0|
9990b57cec5SDimitry Andric +-----+
10000b57cec5SDimitry Andric | ^
10010b57cec5SDimitry Andric acquire| |release
10020b57cec5SDimitry Andric | |
10030b57cec5SDimitry Andric | |
10040b57cec5SDimitry Andric v |
10050b57cec5SDimitry Andric +-----+
10060b57cec5SDimitry Andric | h, h|
10070b57cec5SDimitry Andric +-----+
10080b57cec5SDimitry Andric | ^
10090b57cec5SDimitry Andric acquire| |release
10100b57cec5SDimitry Andric | |
10110b57cec5SDimitry Andric | |
10120b57cec5SDimitry Andric v |
10130b57cec5SDimitry Andric +-----+
10140b57cec5SDimitry Andric | h, t|----- acquire, release loopback ---+
10150b57cec5SDimitry Andric +-----+ |
10160b57cec5SDimitry Andric ^ |
10170b57cec5SDimitry Andric | |
10180b57cec5SDimitry Andric +------------------------------------+
10190b57cec5SDimitry Andric */
10200b57cec5SDimitry Andric
10210b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
10220b57cec5SDimitry Andric
10230b57cec5SDimitry Andric /* Stuff for circular trace buffer */
10240b57cec5SDimitry Andric #define TRACE_BUF_ELE 1024
10250b57cec5SDimitry Andric static char traces[TRACE_BUF_ELE][128] = {0};
10260b57cec5SDimitry Andric static int tc = 0;
10270b57cec5SDimitry Andric #define TRACE_LOCK(X, Y) \
10280b57cec5SDimitry Andric KMP_SNPRINTF(traces[tc++ % TRACE_BUF_ELE], 128, "t%d at %s\n", X, Y);
10290b57cec5SDimitry Andric #define TRACE_LOCK_T(X, Y, Z) \
10300b57cec5SDimitry Andric KMP_SNPRINTF(traces[tc++ % TRACE_BUF_ELE], 128, "t%d at %s%d\n", X, Y, Z);
10310b57cec5SDimitry Andric #define TRACE_LOCK_HT(X, Y, Z, Q) \
10320b57cec5SDimitry Andric KMP_SNPRINTF(traces[tc++ % TRACE_BUF_ELE], 128, "t%d at %s %d,%d\n", X, Y, \
10330b57cec5SDimitry Andric Z, Q);
10340b57cec5SDimitry Andric
__kmp_dump_queuing_lock(kmp_info_t * this_thr,kmp_int32 gtid,kmp_queuing_lock_t * lck,kmp_int32 head_id,kmp_int32 tail_id)10350b57cec5SDimitry Andric static void __kmp_dump_queuing_lock(kmp_info_t *this_thr, kmp_int32 gtid,
10360b57cec5SDimitry Andric kmp_queuing_lock_t *lck, kmp_int32 head_id,
10370b57cec5SDimitry Andric kmp_int32 tail_id) {
10380b57cec5SDimitry Andric kmp_int32 t, i;
10390b57cec5SDimitry Andric
10400b57cec5SDimitry Andric __kmp_printf_no_lock("\n__kmp_dump_queuing_lock: TRACE BEGINS HERE! \n");
10410b57cec5SDimitry Andric
10420b57cec5SDimitry Andric i = tc % TRACE_BUF_ELE;
10430b57cec5SDimitry Andric __kmp_printf_no_lock("%s\n", traces[i]);
10440b57cec5SDimitry Andric i = (i + 1) % TRACE_BUF_ELE;
10450b57cec5SDimitry Andric while (i != (tc % TRACE_BUF_ELE)) {
10460b57cec5SDimitry Andric __kmp_printf_no_lock("%s", traces[i]);
10470b57cec5SDimitry Andric i = (i + 1) % TRACE_BUF_ELE;
10480b57cec5SDimitry Andric }
10490b57cec5SDimitry Andric __kmp_printf_no_lock("\n");
10500b57cec5SDimitry Andric
10510b57cec5SDimitry Andric __kmp_printf_no_lock("\n__kmp_dump_queuing_lock: gtid+1:%d, spin_here:%d, "
10520b57cec5SDimitry Andric "next_wait:%d, head_id:%d, tail_id:%d\n",
10530b57cec5SDimitry Andric gtid + 1, this_thr->th.th_spin_here,
10540b57cec5SDimitry Andric this_thr->th.th_next_waiting, head_id, tail_id);
10550b57cec5SDimitry Andric
10560b57cec5SDimitry Andric __kmp_printf_no_lock("\t\thead: %d ", lck->lk.head_id);
10570b57cec5SDimitry Andric
10580b57cec5SDimitry Andric if (lck->lk.head_id >= 1) {
10590b57cec5SDimitry Andric t = __kmp_threads[lck->lk.head_id - 1]->th.th_next_waiting;
10600b57cec5SDimitry Andric while (t > 0) {
10610b57cec5SDimitry Andric __kmp_printf_no_lock("-> %d ", t);
10620b57cec5SDimitry Andric t = __kmp_threads[t - 1]->th.th_next_waiting;
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric }
10650b57cec5SDimitry Andric __kmp_printf_no_lock("; tail: %d ", lck->lk.tail_id);
10660b57cec5SDimitry Andric __kmp_printf_no_lock("\n\n");
10670b57cec5SDimitry Andric }
10680b57cec5SDimitry Andric
10690b57cec5SDimitry Andric #endif /* DEBUG_QUEUING_LOCKS */
10700b57cec5SDimitry Andric
__kmp_get_queuing_lock_owner(kmp_queuing_lock_t * lck)10710b57cec5SDimitry Andric static kmp_int32 __kmp_get_queuing_lock_owner(kmp_queuing_lock_t *lck) {
10720b57cec5SDimitry Andric return TCR_4(lck->lk.owner_id) - 1;
10730b57cec5SDimitry Andric }
10740b57cec5SDimitry Andric
__kmp_is_queuing_lock_nestable(kmp_queuing_lock_t * lck)10750b57cec5SDimitry Andric static inline bool __kmp_is_queuing_lock_nestable(kmp_queuing_lock_t *lck) {
10760b57cec5SDimitry Andric return lck->lk.depth_locked != -1;
10770b57cec5SDimitry Andric }
10780b57cec5SDimitry Andric
10790b57cec5SDimitry Andric /* Acquire a lock using a the queuing lock implementation */
10800b57cec5SDimitry Andric template <bool takeTime>
10810b57cec5SDimitry Andric /* [TLW] The unused template above is left behind because of what BEB believes
10820b57cec5SDimitry Andric is a potential compiler problem with __forceinline. */
10830b57cec5SDimitry Andric __forceinline static int
__kmp_acquire_queuing_lock_timed_template(kmp_queuing_lock_t * lck,kmp_int32 gtid)10840b57cec5SDimitry Andric __kmp_acquire_queuing_lock_timed_template(kmp_queuing_lock_t *lck,
10850b57cec5SDimitry Andric kmp_int32 gtid) {
10860b57cec5SDimitry Andric kmp_info_t *this_thr = __kmp_thread_from_gtid(gtid);
10870b57cec5SDimitry Andric volatile kmp_int32 *head_id_p = &lck->lk.head_id;
10880b57cec5SDimitry Andric volatile kmp_int32 *tail_id_p = &lck->lk.tail_id;
10890b57cec5SDimitry Andric volatile kmp_uint32 *spin_here_p;
10900b57cec5SDimitry Andric
10910b57cec5SDimitry Andric #if OMPT_SUPPORT
10920b57cec5SDimitry Andric ompt_state_t prev_state = ompt_state_undefined;
10930b57cec5SDimitry Andric #endif
10940b57cec5SDimitry Andric
10950b57cec5SDimitry Andric KA_TRACE(1000,
10960b57cec5SDimitry Andric ("__kmp_acquire_queuing_lock: lck:%p, T#%d entering\n", lck, gtid));
10970b57cec5SDimitry Andric
10980b57cec5SDimitry Andric KMP_FSYNC_PREPARE(lck);
10990b57cec5SDimitry Andric KMP_DEBUG_ASSERT(this_thr != NULL);
11000b57cec5SDimitry Andric spin_here_p = &this_thr->th.th_spin_here;
11010b57cec5SDimitry Andric
11020b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
11030b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "acq ent");
11040b57cec5SDimitry Andric if (*spin_here_p)
11050b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, *head_id_p, *tail_id_p);
11060b57cec5SDimitry Andric if (this_thr->th.th_next_waiting != 0)
11070b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, *head_id_p, *tail_id_p);
11080b57cec5SDimitry Andric #endif
11090b57cec5SDimitry Andric KMP_DEBUG_ASSERT(!*spin_here_p);
11100b57cec5SDimitry Andric KMP_DEBUG_ASSERT(this_thr->th.th_next_waiting == 0);
11110b57cec5SDimitry Andric
11120b57cec5SDimitry Andric /* The following st.rel to spin_here_p needs to precede the cmpxchg.acq to
11130b57cec5SDimitry Andric head_id_p that may follow, not just in execution order, but also in
11140b57cec5SDimitry Andric visibility order. This way, when a releasing thread observes the changes to
11150b57cec5SDimitry Andric the queue by this thread, it can rightly assume that spin_here_p has
11160b57cec5SDimitry Andric already been set to TRUE, so that when it sets spin_here_p to FALSE, it is
11170b57cec5SDimitry Andric not premature. If the releasing thread sets spin_here_p to FALSE before
11180b57cec5SDimitry Andric this thread sets it to TRUE, this thread will hang. */
11190b57cec5SDimitry Andric *spin_here_p = TRUE; /* before enqueuing to prevent race */
11200b57cec5SDimitry Andric
11210b57cec5SDimitry Andric while (1) {
11220b57cec5SDimitry Andric kmp_int32 enqueued;
11230b57cec5SDimitry Andric kmp_int32 head;
11240b57cec5SDimitry Andric kmp_int32 tail;
11250b57cec5SDimitry Andric
11260b57cec5SDimitry Andric head = *head_id_p;
11270b57cec5SDimitry Andric
11280b57cec5SDimitry Andric switch (head) {
11290b57cec5SDimitry Andric
11300b57cec5SDimitry Andric case -1: {
11310b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
11320b57cec5SDimitry Andric tail = *tail_id_p;
11330b57cec5SDimitry Andric TRACE_LOCK_HT(gtid + 1, "acq read: ", head, tail);
11340b57cec5SDimitry Andric #endif
11350b57cec5SDimitry Andric tail = 0; /* to make sure next link asynchronously read is not set
11360b57cec5SDimitry Andric accidentally; this assignment prevents us from entering the
11370b57cec5SDimitry Andric if ( t > 0 ) condition in the enqueued case below, which is not
11380b57cec5SDimitry Andric necessary for this state transition */
11390b57cec5SDimitry Andric
11400b57cec5SDimitry Andric /* try (-1,0)->(tid,tid) */
11410b57cec5SDimitry Andric enqueued = KMP_COMPARE_AND_STORE_ACQ64((volatile kmp_int64 *)tail_id_p,
11420b57cec5SDimitry Andric KMP_PACK_64(-1, 0),
11430b57cec5SDimitry Andric KMP_PACK_64(gtid + 1, gtid + 1));
11440b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
11450b57cec5SDimitry Andric if (enqueued)
11460b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "acq enq: (-1,0)->(tid,tid)");
11470b57cec5SDimitry Andric #endif
11480b57cec5SDimitry Andric } break;
11490b57cec5SDimitry Andric
11500b57cec5SDimitry Andric default: {
11510b57cec5SDimitry Andric tail = *tail_id_p;
11520b57cec5SDimitry Andric KMP_DEBUG_ASSERT(tail != gtid + 1);
11530b57cec5SDimitry Andric
11540b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
11550b57cec5SDimitry Andric TRACE_LOCK_HT(gtid + 1, "acq read: ", head, tail);
11560b57cec5SDimitry Andric #endif
11570b57cec5SDimitry Andric
11580b57cec5SDimitry Andric if (tail == 0) {
11590b57cec5SDimitry Andric enqueued = FALSE;
11600b57cec5SDimitry Andric } else {
11610b57cec5SDimitry Andric /* try (h,t) or (h,h)->(h,tid) */
11620b57cec5SDimitry Andric enqueued = KMP_COMPARE_AND_STORE_ACQ32(tail_id_p, tail, gtid + 1);
11630b57cec5SDimitry Andric
11640b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
11650b57cec5SDimitry Andric if (enqueued)
11660b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "acq enq: (h,t)->(h,tid)");
11670b57cec5SDimitry Andric #endif
11680b57cec5SDimitry Andric }
11690b57cec5SDimitry Andric } break;
11700b57cec5SDimitry Andric
11710b57cec5SDimitry Andric case 0: /* empty queue */
11720b57cec5SDimitry Andric {
11730b57cec5SDimitry Andric kmp_int32 grabbed_lock;
11740b57cec5SDimitry Andric
11750b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
11760b57cec5SDimitry Andric tail = *tail_id_p;
11770b57cec5SDimitry Andric TRACE_LOCK_HT(gtid + 1, "acq read: ", head, tail);
11780b57cec5SDimitry Andric #endif
11790b57cec5SDimitry Andric /* try (0,0)->(-1,0) */
11800b57cec5SDimitry Andric
11810b57cec5SDimitry Andric /* only legal transition out of head = 0 is head = -1 with no change to
11820b57cec5SDimitry Andric * tail */
11830b57cec5SDimitry Andric grabbed_lock = KMP_COMPARE_AND_STORE_ACQ32(head_id_p, 0, -1);
11840b57cec5SDimitry Andric
11850b57cec5SDimitry Andric if (grabbed_lock) {
11860b57cec5SDimitry Andric
11870b57cec5SDimitry Andric *spin_here_p = FALSE;
11880b57cec5SDimitry Andric
11890b57cec5SDimitry Andric KA_TRACE(
11900b57cec5SDimitry Andric 1000,
11910b57cec5SDimitry Andric ("__kmp_acquire_queuing_lock: lck:%p, T#%d exiting: no queuing\n",
11920b57cec5SDimitry Andric lck, gtid));
11930b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
11940b57cec5SDimitry Andric TRACE_LOCK_HT(gtid + 1, "acq exit: ", head, 0);
11950b57cec5SDimitry Andric #endif
11960b57cec5SDimitry Andric
11970b57cec5SDimitry Andric #if OMPT_SUPPORT
11980b57cec5SDimitry Andric if (ompt_enabled.enabled && prev_state != ompt_state_undefined) {
11990b57cec5SDimitry Andric /* change the state before clearing wait_id */
12000b57cec5SDimitry Andric this_thr->th.ompt_thread_info.state = prev_state;
12010b57cec5SDimitry Andric this_thr->th.ompt_thread_info.wait_id = 0;
12020b57cec5SDimitry Andric }
12030b57cec5SDimitry Andric #endif
12040b57cec5SDimitry Andric
12050b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
12060b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST; /* lock holder cannot be on queue */
12070b57cec5SDimitry Andric }
12080b57cec5SDimitry Andric enqueued = FALSE;
12090b57cec5SDimitry Andric } break;
12100b57cec5SDimitry Andric }
12110b57cec5SDimitry Andric
12120b57cec5SDimitry Andric #if OMPT_SUPPORT
12130b57cec5SDimitry Andric if (ompt_enabled.enabled && prev_state == ompt_state_undefined) {
12140b57cec5SDimitry Andric /* this thread will spin; set wait_id before entering wait state */
12150b57cec5SDimitry Andric prev_state = this_thr->th.ompt_thread_info.state;
12160b57cec5SDimitry Andric this_thr->th.ompt_thread_info.wait_id = (uint64_t)lck;
12170b57cec5SDimitry Andric this_thr->th.ompt_thread_info.state = ompt_state_wait_lock;
12180b57cec5SDimitry Andric }
12190b57cec5SDimitry Andric #endif
12200b57cec5SDimitry Andric
12210b57cec5SDimitry Andric if (enqueued) {
12220b57cec5SDimitry Andric if (tail > 0) {
12230b57cec5SDimitry Andric kmp_info_t *tail_thr = __kmp_thread_from_gtid(tail - 1);
12240b57cec5SDimitry Andric KMP_ASSERT(tail_thr != NULL);
12250b57cec5SDimitry Andric tail_thr->th.th_next_waiting = gtid + 1;
12260b57cec5SDimitry Andric /* corresponding wait for this write in release code */
12270b57cec5SDimitry Andric }
12280b57cec5SDimitry Andric KA_TRACE(1000,
12290b57cec5SDimitry Andric ("__kmp_acquire_queuing_lock: lck:%p, T#%d waiting for lock\n",
12300b57cec5SDimitry Andric lck, gtid));
12310b57cec5SDimitry Andric
12320b57cec5SDimitry Andric KMP_MB();
12330b57cec5SDimitry Andric // ToDo: Use __kmp_wait_sleep or similar when blocktime != inf
12340b57cec5SDimitry Andric KMP_WAIT(spin_here_p, FALSE, KMP_EQ, lck);
12355ffd83dbSDimitry Andric // Synchronize writes to both runtime thread structures
12365ffd83dbSDimitry Andric // and writes in user code.
12375ffd83dbSDimitry Andric KMP_MB();
12380b57cec5SDimitry Andric
12390b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
12400b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "acq spin");
12410b57cec5SDimitry Andric
12420b57cec5SDimitry Andric if (this_thr->th.th_next_waiting != 0)
12430b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, *head_id_p, *tail_id_p);
12440b57cec5SDimitry Andric #endif
12450b57cec5SDimitry Andric KMP_DEBUG_ASSERT(this_thr->th.th_next_waiting == 0);
12460b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_acquire_queuing_lock: lck:%p, T#%d exiting: after "
12470b57cec5SDimitry Andric "waiting on queue\n",
12480b57cec5SDimitry Andric lck, gtid));
12490b57cec5SDimitry Andric
12500b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
12510b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "acq exit 2");
12520b57cec5SDimitry Andric #endif
12530b57cec5SDimitry Andric
12540b57cec5SDimitry Andric #if OMPT_SUPPORT
12550b57cec5SDimitry Andric /* change the state before clearing wait_id */
12560b57cec5SDimitry Andric this_thr->th.ompt_thread_info.state = prev_state;
12570b57cec5SDimitry Andric this_thr->th.ompt_thread_info.wait_id = 0;
12580b57cec5SDimitry Andric #endif
12590b57cec5SDimitry Andric
12600b57cec5SDimitry Andric /* got lock, we were dequeued by the thread that released lock */
12610b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
12620b57cec5SDimitry Andric }
12630b57cec5SDimitry Andric
12640b57cec5SDimitry Andric /* Yield if number of threads > number of logical processors */
12650b57cec5SDimitry Andric /* ToDo: Not sure why this should only be in oversubscription case,
12660b57cec5SDimitry Andric maybe should be traditional YIELD_INIT/YIELD_WHEN loop */
12670b57cec5SDimitry Andric KMP_YIELD_OVERSUB();
12680b57cec5SDimitry Andric
12690b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
12700b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "acq retry");
12710b57cec5SDimitry Andric #endif
12720b57cec5SDimitry Andric }
12730b57cec5SDimitry Andric KMP_ASSERT2(0, "should not get here");
12740b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
12750b57cec5SDimitry Andric }
12760b57cec5SDimitry Andric
__kmp_acquire_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)12770b57cec5SDimitry Andric int __kmp_acquire_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid) {
12780b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
12790b57cec5SDimitry Andric
12800b57cec5SDimitry Andric int retval = __kmp_acquire_queuing_lock_timed_template<false>(lck, gtid);
12810b57cec5SDimitry Andric return retval;
12820b57cec5SDimitry Andric }
12830b57cec5SDimitry Andric
__kmp_acquire_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)12840b57cec5SDimitry Andric static int __kmp_acquire_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
12850b57cec5SDimitry Andric kmp_int32 gtid) {
12860b57cec5SDimitry Andric char const *const func = "omp_set_lock";
12870b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
12880b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
12890b57cec5SDimitry Andric }
12900b57cec5SDimitry Andric if (__kmp_is_queuing_lock_nestable(lck)) {
12910b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
12920b57cec5SDimitry Andric }
12930b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) == gtid) {
12940b57cec5SDimitry Andric KMP_FATAL(LockIsAlreadyOwned, func);
12950b57cec5SDimitry Andric }
12960b57cec5SDimitry Andric
12970b57cec5SDimitry Andric __kmp_acquire_queuing_lock(lck, gtid);
12980b57cec5SDimitry Andric
12990b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
13000b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
13010b57cec5SDimitry Andric }
13020b57cec5SDimitry Andric
__kmp_test_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)13030b57cec5SDimitry Andric int __kmp_test_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid) {
13040b57cec5SDimitry Andric volatile kmp_int32 *head_id_p = &lck->lk.head_id;
13050b57cec5SDimitry Andric kmp_int32 head;
13060b57cec5SDimitry Andric #ifdef KMP_DEBUG
13070b57cec5SDimitry Andric kmp_info_t *this_thr;
13080b57cec5SDimitry Andric #endif
13090b57cec5SDimitry Andric
13100b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_test_queuing_lock: T#%d entering\n", gtid));
13110b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
13120b57cec5SDimitry Andric #ifdef KMP_DEBUG
13130b57cec5SDimitry Andric this_thr = __kmp_thread_from_gtid(gtid);
13140b57cec5SDimitry Andric KMP_DEBUG_ASSERT(this_thr != NULL);
13150b57cec5SDimitry Andric KMP_DEBUG_ASSERT(!this_thr->th.th_spin_here);
13160b57cec5SDimitry Andric #endif
13170b57cec5SDimitry Andric
13180b57cec5SDimitry Andric head = *head_id_p;
13190b57cec5SDimitry Andric
13200b57cec5SDimitry Andric if (head == 0) { /* nobody on queue, nobody holding */
13210b57cec5SDimitry Andric /* try (0,0)->(-1,0) */
13220b57cec5SDimitry Andric if (KMP_COMPARE_AND_STORE_ACQ32(head_id_p, 0, -1)) {
13230b57cec5SDimitry Andric KA_TRACE(1000,
13240b57cec5SDimitry Andric ("__kmp_test_queuing_lock: T#%d exiting: holding lock\n", gtid));
13250b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
13260b57cec5SDimitry Andric return TRUE;
13270b57cec5SDimitry Andric }
13280b57cec5SDimitry Andric }
13290b57cec5SDimitry Andric
13300b57cec5SDimitry Andric KA_TRACE(1000,
13310b57cec5SDimitry Andric ("__kmp_test_queuing_lock: T#%d exiting: without lock\n", gtid));
13320b57cec5SDimitry Andric return FALSE;
13330b57cec5SDimitry Andric }
13340b57cec5SDimitry Andric
__kmp_test_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)13350b57cec5SDimitry Andric static int __kmp_test_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
13360b57cec5SDimitry Andric kmp_int32 gtid) {
13370b57cec5SDimitry Andric char const *const func = "omp_test_lock";
13380b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
13390b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
13400b57cec5SDimitry Andric }
13410b57cec5SDimitry Andric if (__kmp_is_queuing_lock_nestable(lck)) {
13420b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
13430b57cec5SDimitry Andric }
13440b57cec5SDimitry Andric
13450b57cec5SDimitry Andric int retval = __kmp_test_queuing_lock(lck, gtid);
13460b57cec5SDimitry Andric
13470b57cec5SDimitry Andric if (retval) {
13480b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
13490b57cec5SDimitry Andric }
13500b57cec5SDimitry Andric return retval;
13510b57cec5SDimitry Andric }
13520b57cec5SDimitry Andric
__kmp_release_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)13530b57cec5SDimitry Andric int __kmp_release_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid) {
13540b57cec5SDimitry Andric volatile kmp_int32 *head_id_p = &lck->lk.head_id;
13550b57cec5SDimitry Andric volatile kmp_int32 *tail_id_p = &lck->lk.tail_id;
13560b57cec5SDimitry Andric
13570b57cec5SDimitry Andric KA_TRACE(1000,
13580b57cec5SDimitry Andric ("__kmp_release_queuing_lock: lck:%p, T#%d entering\n", lck, gtid));
13590b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
1360349cc55cSDimitry Andric #if KMP_DEBUG || DEBUG_QUEUING_LOCKS
1361349cc55cSDimitry Andric kmp_info_t *this_thr = __kmp_thread_from_gtid(gtid);
1362349cc55cSDimitry Andric #endif
13630b57cec5SDimitry Andric KMP_DEBUG_ASSERT(this_thr != NULL);
13640b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
13650b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "rel ent");
13660b57cec5SDimitry Andric
13670b57cec5SDimitry Andric if (this_thr->th.th_spin_here)
13680b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, *head_id_p, *tail_id_p);
13690b57cec5SDimitry Andric if (this_thr->th.th_next_waiting != 0)
13700b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, *head_id_p, *tail_id_p);
13710b57cec5SDimitry Andric #endif
13720b57cec5SDimitry Andric KMP_DEBUG_ASSERT(!this_thr->th.th_spin_here);
13730b57cec5SDimitry Andric KMP_DEBUG_ASSERT(this_thr->th.th_next_waiting == 0);
13740b57cec5SDimitry Andric
13750b57cec5SDimitry Andric KMP_FSYNC_RELEASING(lck);
13760b57cec5SDimitry Andric
13770b57cec5SDimitry Andric while (1) {
13780b57cec5SDimitry Andric kmp_int32 dequeued;
13790b57cec5SDimitry Andric kmp_int32 head;
13800b57cec5SDimitry Andric kmp_int32 tail;
13810b57cec5SDimitry Andric
13820b57cec5SDimitry Andric head = *head_id_p;
13830b57cec5SDimitry Andric
13840b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
13850b57cec5SDimitry Andric tail = *tail_id_p;
13860b57cec5SDimitry Andric TRACE_LOCK_HT(gtid + 1, "rel read: ", head, tail);
13870b57cec5SDimitry Andric if (head == 0)
13880b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, head, tail);
13890b57cec5SDimitry Andric #endif
13900b57cec5SDimitry Andric KMP_DEBUG_ASSERT(head !=
13910b57cec5SDimitry Andric 0); /* holding the lock, head must be -1 or queue head */
13920b57cec5SDimitry Andric
13930b57cec5SDimitry Andric if (head == -1) { /* nobody on queue */
13940b57cec5SDimitry Andric /* try (-1,0)->(0,0) */
13950b57cec5SDimitry Andric if (KMP_COMPARE_AND_STORE_REL32(head_id_p, -1, 0)) {
13960b57cec5SDimitry Andric KA_TRACE(
13970b57cec5SDimitry Andric 1000,
13980b57cec5SDimitry Andric ("__kmp_release_queuing_lock: lck:%p, T#%d exiting: queue empty\n",
13990b57cec5SDimitry Andric lck, gtid));
14000b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14010b57cec5SDimitry Andric TRACE_LOCK_HT(gtid + 1, "rel exit: ", 0, 0);
14020b57cec5SDimitry Andric #endif
14030b57cec5SDimitry Andric
14040b57cec5SDimitry Andric #if OMPT_SUPPORT
14050b57cec5SDimitry Andric /* nothing to do - no other thread is trying to shift blame */
14060b57cec5SDimitry Andric #endif
14070b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
14080b57cec5SDimitry Andric }
14090b57cec5SDimitry Andric dequeued = FALSE;
14100b57cec5SDimitry Andric } else {
14110b57cec5SDimitry Andric KMP_MB();
14120b57cec5SDimitry Andric tail = *tail_id_p;
14130b57cec5SDimitry Andric if (head == tail) { /* only one thread on the queue */
14140b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14150b57cec5SDimitry Andric if (head <= 0)
14160b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, head, tail);
14170b57cec5SDimitry Andric #endif
14180b57cec5SDimitry Andric KMP_DEBUG_ASSERT(head > 0);
14190b57cec5SDimitry Andric
14200b57cec5SDimitry Andric /* try (h,h)->(-1,0) */
14210b57cec5SDimitry Andric dequeued = KMP_COMPARE_AND_STORE_REL64(
14220b57cec5SDimitry Andric RCAST(volatile kmp_int64 *, tail_id_p), KMP_PACK_64(head, head),
14230b57cec5SDimitry Andric KMP_PACK_64(-1, 0));
14240b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14250b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "rel deq: (h,h)->(-1,0)");
14260b57cec5SDimitry Andric #endif
14270b57cec5SDimitry Andric
14280b57cec5SDimitry Andric } else {
14290b57cec5SDimitry Andric volatile kmp_int32 *waiting_id_p;
14300b57cec5SDimitry Andric kmp_info_t *head_thr = __kmp_thread_from_gtid(head - 1);
14310b57cec5SDimitry Andric KMP_DEBUG_ASSERT(head_thr != NULL);
14320b57cec5SDimitry Andric waiting_id_p = &head_thr->th.th_next_waiting;
14330b57cec5SDimitry Andric
14340b57cec5SDimitry Andric /* Does this require synchronous reads? */
14350b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14360b57cec5SDimitry Andric if (head <= 0 || tail <= 0)
14370b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, head, tail);
14380b57cec5SDimitry Andric #endif
14390b57cec5SDimitry Andric KMP_DEBUG_ASSERT(head > 0 && tail > 0);
14400b57cec5SDimitry Andric
14410b57cec5SDimitry Andric /* try (h,t)->(h',t) or (t,t) */
14420b57cec5SDimitry Andric KMP_MB();
14430b57cec5SDimitry Andric /* make sure enqueuing thread has time to update next waiting thread
14440b57cec5SDimitry Andric * field */
14450b57cec5SDimitry Andric *head_id_p =
14460b57cec5SDimitry Andric KMP_WAIT((volatile kmp_uint32 *)waiting_id_p, 0, KMP_NEQ, NULL);
14470b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14480b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "rel deq: (h,t)->(h',t)");
14490b57cec5SDimitry Andric #endif
14500b57cec5SDimitry Andric dequeued = TRUE;
14510b57cec5SDimitry Andric }
14520b57cec5SDimitry Andric }
14530b57cec5SDimitry Andric
14540b57cec5SDimitry Andric if (dequeued) {
14550b57cec5SDimitry Andric kmp_info_t *head_thr = __kmp_thread_from_gtid(head - 1);
14560b57cec5SDimitry Andric KMP_DEBUG_ASSERT(head_thr != NULL);
14570b57cec5SDimitry Andric
14580b57cec5SDimitry Andric /* Does this require synchronous reads? */
14590b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14600b57cec5SDimitry Andric if (head <= 0 || tail <= 0)
14610b57cec5SDimitry Andric __kmp_dump_queuing_lock(this_thr, gtid, lck, head, tail);
14620b57cec5SDimitry Andric #endif
14630b57cec5SDimitry Andric KMP_DEBUG_ASSERT(head > 0 && tail > 0);
14640b57cec5SDimitry Andric
14650b57cec5SDimitry Andric /* For clean code only. Thread not released until next statement prevents
14660b57cec5SDimitry Andric race with acquire code. */
14670b57cec5SDimitry Andric head_thr->th.th_next_waiting = 0;
14680b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14690b57cec5SDimitry Andric TRACE_LOCK_T(gtid + 1, "rel nw=0 for t=", head);
14700b57cec5SDimitry Andric #endif
14710b57cec5SDimitry Andric
14720b57cec5SDimitry Andric KMP_MB();
14730b57cec5SDimitry Andric /* reset spin value */
14740b57cec5SDimitry Andric head_thr->th.th_spin_here = FALSE;
14750b57cec5SDimitry Andric
14760b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_release_queuing_lock: lck:%p, T#%d exiting: after "
14770b57cec5SDimitry Andric "dequeuing\n",
14780b57cec5SDimitry Andric lck, gtid));
14790b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14800b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "rel exit 2");
14810b57cec5SDimitry Andric #endif
14820b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
14830b57cec5SDimitry Andric }
14840b57cec5SDimitry Andric /* KMP_CPU_PAUSE(); don't want to make releasing thread hold up acquiring
14850b57cec5SDimitry Andric threads */
14860b57cec5SDimitry Andric
14870b57cec5SDimitry Andric #ifdef DEBUG_QUEUING_LOCKS
14880b57cec5SDimitry Andric TRACE_LOCK(gtid + 1, "rel retry");
14890b57cec5SDimitry Andric #endif
14900b57cec5SDimitry Andric
14910b57cec5SDimitry Andric } /* while */
14920b57cec5SDimitry Andric KMP_ASSERT2(0, "should not get here");
14930b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
14940b57cec5SDimitry Andric }
14950b57cec5SDimitry Andric
__kmp_release_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)14960b57cec5SDimitry Andric static int __kmp_release_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
14970b57cec5SDimitry Andric kmp_int32 gtid) {
14980b57cec5SDimitry Andric char const *const func = "omp_unset_lock";
14990b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
15000b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
15010b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
15020b57cec5SDimitry Andric }
15030b57cec5SDimitry Andric if (__kmp_is_queuing_lock_nestable(lck)) {
15040b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
15050b57cec5SDimitry Andric }
15060b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) == -1) {
15070b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
15080b57cec5SDimitry Andric }
15090b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) != gtid) {
15100b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
15110b57cec5SDimitry Andric }
15120b57cec5SDimitry Andric lck->lk.owner_id = 0;
15130b57cec5SDimitry Andric return __kmp_release_queuing_lock(lck, gtid);
15140b57cec5SDimitry Andric }
15150b57cec5SDimitry Andric
__kmp_init_queuing_lock(kmp_queuing_lock_t * lck)15160b57cec5SDimitry Andric void __kmp_init_queuing_lock(kmp_queuing_lock_t *lck) {
15170b57cec5SDimitry Andric lck->lk.location = NULL;
15180b57cec5SDimitry Andric lck->lk.head_id = 0;
15190b57cec5SDimitry Andric lck->lk.tail_id = 0;
15200b57cec5SDimitry Andric lck->lk.next_ticket = 0;
15210b57cec5SDimitry Andric lck->lk.now_serving = 0;
15220b57cec5SDimitry Andric lck->lk.owner_id = 0; // no thread owns the lock.
15230b57cec5SDimitry Andric lck->lk.depth_locked = -1; // >= 0 for nestable locks, -1 for simple locks.
15240b57cec5SDimitry Andric lck->lk.initialized = lck;
15250b57cec5SDimitry Andric
15260b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_init_queuing_lock: lock %p initialized\n", lck));
15270b57cec5SDimitry Andric }
15280b57cec5SDimitry Andric
__kmp_destroy_queuing_lock(kmp_queuing_lock_t * lck)15290b57cec5SDimitry Andric void __kmp_destroy_queuing_lock(kmp_queuing_lock_t *lck) {
15300b57cec5SDimitry Andric lck->lk.initialized = NULL;
15310b57cec5SDimitry Andric lck->lk.location = NULL;
15320b57cec5SDimitry Andric lck->lk.head_id = 0;
15330b57cec5SDimitry Andric lck->lk.tail_id = 0;
15340b57cec5SDimitry Andric lck->lk.next_ticket = 0;
15350b57cec5SDimitry Andric lck->lk.now_serving = 0;
15360b57cec5SDimitry Andric lck->lk.owner_id = 0;
15370b57cec5SDimitry Andric lck->lk.depth_locked = -1;
15380b57cec5SDimitry Andric }
15390b57cec5SDimitry Andric
__kmp_destroy_queuing_lock_with_checks(kmp_queuing_lock_t * lck)15400b57cec5SDimitry Andric static void __kmp_destroy_queuing_lock_with_checks(kmp_queuing_lock_t *lck) {
15410b57cec5SDimitry Andric char const *const func = "omp_destroy_lock";
15420b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
15430b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
15440b57cec5SDimitry Andric }
15450b57cec5SDimitry Andric if (__kmp_is_queuing_lock_nestable(lck)) {
15460b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
15470b57cec5SDimitry Andric }
15480b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) != -1) {
15490b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
15500b57cec5SDimitry Andric }
15510b57cec5SDimitry Andric __kmp_destroy_queuing_lock(lck);
15520b57cec5SDimitry Andric }
15530b57cec5SDimitry Andric
15540b57cec5SDimitry Andric // nested queuing locks
15550b57cec5SDimitry Andric
__kmp_acquire_nested_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)15560b57cec5SDimitry Andric int __kmp_acquire_nested_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid) {
15570b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
15580b57cec5SDimitry Andric
15590b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) == gtid) {
15600b57cec5SDimitry Andric lck->lk.depth_locked += 1;
15610b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_NEXT;
15620b57cec5SDimitry Andric } else {
15630b57cec5SDimitry Andric __kmp_acquire_queuing_lock_timed_template<false>(lck, gtid);
15640b57cec5SDimitry Andric KMP_MB();
15650b57cec5SDimitry Andric lck->lk.depth_locked = 1;
15660b57cec5SDimitry Andric KMP_MB();
15670b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
15680b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
15690b57cec5SDimitry Andric }
15700b57cec5SDimitry Andric }
15710b57cec5SDimitry Andric
15720b57cec5SDimitry Andric static int
__kmp_acquire_nested_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)15730b57cec5SDimitry Andric __kmp_acquire_nested_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
15740b57cec5SDimitry Andric kmp_int32 gtid) {
15750b57cec5SDimitry Andric char const *const func = "omp_set_nest_lock";
15760b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
15770b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
15780b57cec5SDimitry Andric }
15790b57cec5SDimitry Andric if (!__kmp_is_queuing_lock_nestable(lck)) {
15800b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
15810b57cec5SDimitry Andric }
15820b57cec5SDimitry Andric return __kmp_acquire_nested_queuing_lock(lck, gtid);
15830b57cec5SDimitry Andric }
15840b57cec5SDimitry Andric
__kmp_test_nested_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)15850b57cec5SDimitry Andric int __kmp_test_nested_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid) {
15860b57cec5SDimitry Andric int retval;
15870b57cec5SDimitry Andric
15880b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
15890b57cec5SDimitry Andric
15900b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) == gtid) {
15910b57cec5SDimitry Andric retval = ++lck->lk.depth_locked;
15920b57cec5SDimitry Andric } else if (!__kmp_test_queuing_lock(lck, gtid)) {
15930b57cec5SDimitry Andric retval = 0;
15940b57cec5SDimitry Andric } else {
15950b57cec5SDimitry Andric KMP_MB();
15960b57cec5SDimitry Andric retval = lck->lk.depth_locked = 1;
15970b57cec5SDimitry Andric KMP_MB();
15980b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
15990b57cec5SDimitry Andric }
16000b57cec5SDimitry Andric return retval;
16010b57cec5SDimitry Andric }
16020b57cec5SDimitry Andric
__kmp_test_nested_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)16030b57cec5SDimitry Andric static int __kmp_test_nested_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
16040b57cec5SDimitry Andric kmp_int32 gtid) {
16050b57cec5SDimitry Andric char const *const func = "omp_test_nest_lock";
16060b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
16070b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
16080b57cec5SDimitry Andric }
16090b57cec5SDimitry Andric if (!__kmp_is_queuing_lock_nestable(lck)) {
16100b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
16110b57cec5SDimitry Andric }
16120b57cec5SDimitry Andric return __kmp_test_nested_queuing_lock(lck, gtid);
16130b57cec5SDimitry Andric }
16140b57cec5SDimitry Andric
__kmp_release_nested_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)16150b57cec5SDimitry Andric int __kmp_release_nested_queuing_lock(kmp_queuing_lock_t *lck, kmp_int32 gtid) {
16160b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
16170b57cec5SDimitry Andric
16180b57cec5SDimitry Andric KMP_MB();
16190b57cec5SDimitry Andric if (--(lck->lk.depth_locked) == 0) {
16200b57cec5SDimitry Andric KMP_MB();
16210b57cec5SDimitry Andric lck->lk.owner_id = 0;
16220b57cec5SDimitry Andric __kmp_release_queuing_lock(lck, gtid);
16230b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
16240b57cec5SDimitry Andric }
16250b57cec5SDimitry Andric return KMP_LOCK_STILL_HELD;
16260b57cec5SDimitry Andric }
16270b57cec5SDimitry Andric
16280b57cec5SDimitry Andric static int
__kmp_release_nested_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)16290b57cec5SDimitry Andric __kmp_release_nested_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
16300b57cec5SDimitry Andric kmp_int32 gtid) {
16310b57cec5SDimitry Andric char const *const func = "omp_unset_nest_lock";
16320b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
16330b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
16340b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
16350b57cec5SDimitry Andric }
16360b57cec5SDimitry Andric if (!__kmp_is_queuing_lock_nestable(lck)) {
16370b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
16380b57cec5SDimitry Andric }
16390b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) == -1) {
16400b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
16410b57cec5SDimitry Andric }
16420b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) != gtid) {
16430b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
16440b57cec5SDimitry Andric }
16450b57cec5SDimitry Andric return __kmp_release_nested_queuing_lock(lck, gtid);
16460b57cec5SDimitry Andric }
16470b57cec5SDimitry Andric
__kmp_init_nested_queuing_lock(kmp_queuing_lock_t * lck)16480b57cec5SDimitry Andric void __kmp_init_nested_queuing_lock(kmp_queuing_lock_t *lck) {
16490b57cec5SDimitry Andric __kmp_init_queuing_lock(lck);
16500b57cec5SDimitry Andric lck->lk.depth_locked = 0; // >= 0 for nestable locks, -1 for simple locks
16510b57cec5SDimitry Andric }
16520b57cec5SDimitry Andric
__kmp_destroy_nested_queuing_lock(kmp_queuing_lock_t * lck)16530b57cec5SDimitry Andric void __kmp_destroy_nested_queuing_lock(kmp_queuing_lock_t *lck) {
16540b57cec5SDimitry Andric __kmp_destroy_queuing_lock(lck);
16550b57cec5SDimitry Andric lck->lk.depth_locked = 0;
16560b57cec5SDimitry Andric }
16570b57cec5SDimitry Andric
16580b57cec5SDimitry Andric static void
__kmp_destroy_nested_queuing_lock_with_checks(kmp_queuing_lock_t * lck)16590b57cec5SDimitry Andric __kmp_destroy_nested_queuing_lock_with_checks(kmp_queuing_lock_t *lck) {
16600b57cec5SDimitry Andric char const *const func = "omp_destroy_nest_lock";
16610b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
16620b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
16630b57cec5SDimitry Andric }
16640b57cec5SDimitry Andric if (!__kmp_is_queuing_lock_nestable(lck)) {
16650b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
16660b57cec5SDimitry Andric }
16670b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(lck) != -1) {
16680b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
16690b57cec5SDimitry Andric }
16700b57cec5SDimitry Andric __kmp_destroy_nested_queuing_lock(lck);
16710b57cec5SDimitry Andric }
16720b57cec5SDimitry Andric
16730b57cec5SDimitry Andric // access functions to fields which don't exist for all lock kinds.
16740b57cec5SDimitry Andric
__kmp_get_queuing_lock_location(kmp_queuing_lock_t * lck)16750b57cec5SDimitry Andric static const ident_t *__kmp_get_queuing_lock_location(kmp_queuing_lock_t *lck) {
16760b57cec5SDimitry Andric return lck->lk.location;
16770b57cec5SDimitry Andric }
16780b57cec5SDimitry Andric
__kmp_set_queuing_lock_location(kmp_queuing_lock_t * lck,const ident_t * loc)16790b57cec5SDimitry Andric static void __kmp_set_queuing_lock_location(kmp_queuing_lock_t *lck,
16800b57cec5SDimitry Andric const ident_t *loc) {
16810b57cec5SDimitry Andric lck->lk.location = loc;
16820b57cec5SDimitry Andric }
16830b57cec5SDimitry Andric
__kmp_get_queuing_lock_flags(kmp_queuing_lock_t * lck)16840b57cec5SDimitry Andric static kmp_lock_flags_t __kmp_get_queuing_lock_flags(kmp_queuing_lock_t *lck) {
16850b57cec5SDimitry Andric return lck->lk.flags;
16860b57cec5SDimitry Andric }
16870b57cec5SDimitry Andric
__kmp_set_queuing_lock_flags(kmp_queuing_lock_t * lck,kmp_lock_flags_t flags)16880b57cec5SDimitry Andric static void __kmp_set_queuing_lock_flags(kmp_queuing_lock_t *lck,
16890b57cec5SDimitry Andric kmp_lock_flags_t flags) {
16900b57cec5SDimitry Andric lck->lk.flags = flags;
16910b57cec5SDimitry Andric }
16920b57cec5SDimitry Andric
16930b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
16940b57cec5SDimitry Andric
16950b57cec5SDimitry Andric /* RTM Adaptive locks */
16960b57cec5SDimitry Andric
1697e8d8bef9SDimitry Andric #if KMP_HAVE_RTM_INTRINSICS
16980b57cec5SDimitry Andric #include <immintrin.h>
16990b57cec5SDimitry Andric #define SOFT_ABORT_MASK (_XABORT_RETRY | _XABORT_CONFLICT | _XABORT_EXPLICIT)
17000b57cec5SDimitry Andric
17010b57cec5SDimitry Andric #else
17020b57cec5SDimitry Andric
17030b57cec5SDimitry Andric // Values from the status register after failed speculation.
17040b57cec5SDimitry Andric #define _XBEGIN_STARTED (~0u)
17050b57cec5SDimitry Andric #define _XABORT_EXPLICIT (1 << 0)
17060b57cec5SDimitry Andric #define _XABORT_RETRY (1 << 1)
17070b57cec5SDimitry Andric #define _XABORT_CONFLICT (1 << 2)
17080b57cec5SDimitry Andric #define _XABORT_CAPACITY (1 << 3)
17090b57cec5SDimitry Andric #define _XABORT_DEBUG (1 << 4)
17100b57cec5SDimitry Andric #define _XABORT_NESTED (1 << 5)
17110b57cec5SDimitry Andric #define _XABORT_CODE(x) ((unsigned char)(((x) >> 24) & 0xFF))
17120b57cec5SDimitry Andric
17130b57cec5SDimitry Andric // Aborts for which it's worth trying again immediately
17140b57cec5SDimitry Andric #define SOFT_ABORT_MASK (_XABORT_RETRY | _XABORT_CONFLICT | _XABORT_EXPLICIT)
17150b57cec5SDimitry Andric
17160b57cec5SDimitry Andric #define STRINGIZE_INTERNAL(arg) #arg
17170b57cec5SDimitry Andric #define STRINGIZE(arg) STRINGIZE_INTERNAL(arg)
17180b57cec5SDimitry Andric
17190b57cec5SDimitry Andric // Access to RTM instructions
17200b57cec5SDimitry Andric /*A version of XBegin which returns -1 on speculation, and the value of EAX on
17210b57cec5SDimitry Andric an abort. This is the same definition as the compiler intrinsic that will be
17220b57cec5SDimitry Andric supported at some point. */
_xbegin()17230b57cec5SDimitry Andric static __inline int _xbegin() {
17240b57cec5SDimitry Andric int res = -1;
17250b57cec5SDimitry Andric
17260b57cec5SDimitry Andric #if KMP_OS_WINDOWS
17270b57cec5SDimitry Andric #if KMP_ARCH_X86_64
17280b57cec5SDimitry Andric _asm {
17290b57cec5SDimitry Andric _emit 0xC7
17300b57cec5SDimitry Andric _emit 0xF8
17310b57cec5SDimitry Andric _emit 2
17320b57cec5SDimitry Andric _emit 0
17330b57cec5SDimitry Andric _emit 0
17340b57cec5SDimitry Andric _emit 0
17350b57cec5SDimitry Andric jmp L2
17360b57cec5SDimitry Andric mov res, eax
17370b57cec5SDimitry Andric L2:
17380b57cec5SDimitry Andric }
17390b57cec5SDimitry Andric #else /* IA32 */
17400b57cec5SDimitry Andric _asm {
17410b57cec5SDimitry Andric _emit 0xC7
17420b57cec5SDimitry Andric _emit 0xF8
17430b57cec5SDimitry Andric _emit 2
17440b57cec5SDimitry Andric _emit 0
17450b57cec5SDimitry Andric _emit 0
17460b57cec5SDimitry Andric _emit 0
17470b57cec5SDimitry Andric jmp L2
17480b57cec5SDimitry Andric mov res, eax
17490b57cec5SDimitry Andric L2:
17500b57cec5SDimitry Andric }
17510b57cec5SDimitry Andric #endif // KMP_ARCH_X86_64
17520b57cec5SDimitry Andric #else
17530b57cec5SDimitry Andric /* Note that %eax must be noted as killed (clobbered), because the XSR is
17540b57cec5SDimitry Andric returned in %eax(%rax) on abort. Other register values are restored, so
17550b57cec5SDimitry Andric don't need to be killed.
17560b57cec5SDimitry Andric
17570b57cec5SDimitry Andric We must also mark 'res' as an input and an output, since otherwise
17580b57cec5SDimitry Andric 'res=-1' may be dropped as being dead, whereas we do need the assignment on
17590b57cec5SDimitry Andric the successful (i.e., non-abort) path. */
17600b57cec5SDimitry Andric __asm__ volatile("1: .byte 0xC7; .byte 0xF8;\n"
17610b57cec5SDimitry Andric " .long 1f-1b-6\n"
17620b57cec5SDimitry Andric " jmp 2f\n"
17630b57cec5SDimitry Andric "1: movl %%eax,%0\n"
17640b57cec5SDimitry Andric "2:"
17650b57cec5SDimitry Andric : "+r"(res)::"memory", "%eax");
17660b57cec5SDimitry Andric #endif // KMP_OS_WINDOWS
17670b57cec5SDimitry Andric return res;
17680b57cec5SDimitry Andric }
17690b57cec5SDimitry Andric
17700b57cec5SDimitry Andric /* Transaction end */
_xend()17710b57cec5SDimitry Andric static __inline void _xend() {
17720b57cec5SDimitry Andric #if KMP_OS_WINDOWS
17730b57cec5SDimitry Andric __asm {
17740b57cec5SDimitry Andric _emit 0x0f
17750b57cec5SDimitry Andric _emit 0x01
17760b57cec5SDimitry Andric _emit 0xd5
17770b57cec5SDimitry Andric }
17780b57cec5SDimitry Andric #else
17790b57cec5SDimitry Andric __asm__ volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory");
17800b57cec5SDimitry Andric #endif
17810b57cec5SDimitry Andric }
17820b57cec5SDimitry Andric
17830b57cec5SDimitry Andric /* This is a macro, the argument must be a single byte constant which can be
17840b57cec5SDimitry Andric evaluated by the inline assembler, since it is emitted as a byte into the
17850b57cec5SDimitry Andric assembly code. */
17860b57cec5SDimitry Andric // clang-format off
17870b57cec5SDimitry Andric #if KMP_OS_WINDOWS
17880b57cec5SDimitry Andric #define _xabort(ARG) _asm _emit 0xc6 _asm _emit 0xf8 _asm _emit ARG
17890b57cec5SDimitry Andric #else
17900b57cec5SDimitry Andric #define _xabort(ARG) \
17910b57cec5SDimitry Andric __asm__ volatile(".byte 0xC6; .byte 0xF8; .byte " STRINGIZE(ARG):::"memory");
17920b57cec5SDimitry Andric #endif
17930b57cec5SDimitry Andric // clang-format on
17940b57cec5SDimitry Andric #endif // KMP_COMPILER_ICC && __INTEL_COMPILER >= 1300
17950b57cec5SDimitry Andric
17960b57cec5SDimitry Andric // Statistics is collected for testing purpose
17970b57cec5SDimitry Andric #if KMP_DEBUG_ADAPTIVE_LOCKS
17980b57cec5SDimitry Andric
17990b57cec5SDimitry Andric // We accumulate speculative lock statistics when the lock is destroyed. We
18000b57cec5SDimitry Andric // keep locks that haven't been destroyed in the liveLocks list so that we can
18010b57cec5SDimitry Andric // grab their statistics too.
18020b57cec5SDimitry Andric static kmp_adaptive_lock_statistics_t destroyedStats;
18030b57cec5SDimitry Andric
18040b57cec5SDimitry Andric // To hold the list of live locks.
18050b57cec5SDimitry Andric static kmp_adaptive_lock_info_t liveLocks;
18060b57cec5SDimitry Andric
18070b57cec5SDimitry Andric // A lock so we can safely update the list of locks.
18080b57cec5SDimitry Andric static kmp_bootstrap_lock_t chain_lock =
18090b57cec5SDimitry Andric KMP_BOOTSTRAP_LOCK_INITIALIZER(chain_lock);
18100b57cec5SDimitry Andric
18110b57cec5SDimitry Andric // Initialize the list of stats.
__kmp_init_speculative_stats()18120b57cec5SDimitry Andric void __kmp_init_speculative_stats() {
18130b57cec5SDimitry Andric kmp_adaptive_lock_info_t *lck = &liveLocks;
18140b57cec5SDimitry Andric
18150b57cec5SDimitry Andric memset(CCAST(kmp_adaptive_lock_statistics_t *, &(lck->stats)), 0,
18160b57cec5SDimitry Andric sizeof(lck->stats));
18170b57cec5SDimitry Andric lck->stats.next = lck;
18180b57cec5SDimitry Andric lck->stats.prev = lck;
18190b57cec5SDimitry Andric
18200b57cec5SDimitry Andric KMP_ASSERT(lck->stats.next->stats.prev == lck);
18210b57cec5SDimitry Andric KMP_ASSERT(lck->stats.prev->stats.next == lck);
18220b57cec5SDimitry Andric
18230b57cec5SDimitry Andric __kmp_init_bootstrap_lock(&chain_lock);
18240b57cec5SDimitry Andric }
18250b57cec5SDimitry Andric
18260b57cec5SDimitry Andric // Insert the lock into the circular list
__kmp_remember_lock(kmp_adaptive_lock_info_t * lck)18270b57cec5SDimitry Andric static void __kmp_remember_lock(kmp_adaptive_lock_info_t *lck) {
18280b57cec5SDimitry Andric __kmp_acquire_bootstrap_lock(&chain_lock);
18290b57cec5SDimitry Andric
18300b57cec5SDimitry Andric lck->stats.next = liveLocks.stats.next;
18310b57cec5SDimitry Andric lck->stats.prev = &liveLocks;
18320b57cec5SDimitry Andric
18330b57cec5SDimitry Andric liveLocks.stats.next = lck;
18340b57cec5SDimitry Andric lck->stats.next->stats.prev = lck;
18350b57cec5SDimitry Andric
18360b57cec5SDimitry Andric KMP_ASSERT(lck->stats.next->stats.prev == lck);
18370b57cec5SDimitry Andric KMP_ASSERT(lck->stats.prev->stats.next == lck);
18380b57cec5SDimitry Andric
18390b57cec5SDimitry Andric __kmp_release_bootstrap_lock(&chain_lock);
18400b57cec5SDimitry Andric }
18410b57cec5SDimitry Andric
__kmp_forget_lock(kmp_adaptive_lock_info_t * lck)18420b57cec5SDimitry Andric static void __kmp_forget_lock(kmp_adaptive_lock_info_t *lck) {
18430b57cec5SDimitry Andric KMP_ASSERT(lck->stats.next->stats.prev == lck);
18440b57cec5SDimitry Andric KMP_ASSERT(lck->stats.prev->stats.next == lck);
18450b57cec5SDimitry Andric
18460b57cec5SDimitry Andric kmp_adaptive_lock_info_t *n = lck->stats.next;
18470b57cec5SDimitry Andric kmp_adaptive_lock_info_t *p = lck->stats.prev;
18480b57cec5SDimitry Andric
18490b57cec5SDimitry Andric n->stats.prev = p;
18500b57cec5SDimitry Andric p->stats.next = n;
18510b57cec5SDimitry Andric }
18520b57cec5SDimitry Andric
__kmp_zero_speculative_stats(kmp_adaptive_lock_info_t * lck)18530b57cec5SDimitry Andric static void __kmp_zero_speculative_stats(kmp_adaptive_lock_info_t *lck) {
18540b57cec5SDimitry Andric memset(CCAST(kmp_adaptive_lock_statistics_t *, &lck->stats), 0,
18550b57cec5SDimitry Andric sizeof(lck->stats));
18560b57cec5SDimitry Andric __kmp_remember_lock(lck);
18570b57cec5SDimitry Andric }
18580b57cec5SDimitry Andric
__kmp_add_stats(kmp_adaptive_lock_statistics_t * t,kmp_adaptive_lock_info_t * lck)18590b57cec5SDimitry Andric static void __kmp_add_stats(kmp_adaptive_lock_statistics_t *t,
18600b57cec5SDimitry Andric kmp_adaptive_lock_info_t *lck) {
18610b57cec5SDimitry Andric kmp_adaptive_lock_statistics_t volatile *s = &lck->stats;
18620b57cec5SDimitry Andric
18630b57cec5SDimitry Andric t->nonSpeculativeAcquireAttempts += lck->acquire_attempts;
18640b57cec5SDimitry Andric t->successfulSpeculations += s->successfulSpeculations;
18650b57cec5SDimitry Andric t->hardFailedSpeculations += s->hardFailedSpeculations;
18660b57cec5SDimitry Andric t->softFailedSpeculations += s->softFailedSpeculations;
18670b57cec5SDimitry Andric t->nonSpeculativeAcquires += s->nonSpeculativeAcquires;
18680b57cec5SDimitry Andric t->lemmingYields += s->lemmingYields;
18690b57cec5SDimitry Andric }
18700b57cec5SDimitry Andric
__kmp_accumulate_speculative_stats(kmp_adaptive_lock_info_t * lck)18710b57cec5SDimitry Andric static void __kmp_accumulate_speculative_stats(kmp_adaptive_lock_info_t *lck) {
18720b57cec5SDimitry Andric __kmp_acquire_bootstrap_lock(&chain_lock);
18730b57cec5SDimitry Andric
18740b57cec5SDimitry Andric __kmp_add_stats(&destroyedStats, lck);
18750b57cec5SDimitry Andric __kmp_forget_lock(lck);
18760b57cec5SDimitry Andric
18770b57cec5SDimitry Andric __kmp_release_bootstrap_lock(&chain_lock);
18780b57cec5SDimitry Andric }
18790b57cec5SDimitry Andric
percent(kmp_uint32 count,kmp_uint32 total)18800b57cec5SDimitry Andric static float percent(kmp_uint32 count, kmp_uint32 total) {
18810b57cec5SDimitry Andric return (total == 0) ? 0.0 : (100.0 * count) / total;
18820b57cec5SDimitry Andric }
18830b57cec5SDimitry Andric
__kmp_print_speculative_stats()18840b57cec5SDimitry Andric void __kmp_print_speculative_stats() {
18850b57cec5SDimitry Andric kmp_adaptive_lock_statistics_t total = destroyedStats;
18860b57cec5SDimitry Andric kmp_adaptive_lock_info_t *lck;
18870b57cec5SDimitry Andric
18880b57cec5SDimitry Andric for (lck = liveLocks.stats.next; lck != &liveLocks; lck = lck->stats.next) {
18890b57cec5SDimitry Andric __kmp_add_stats(&total, lck);
18900b57cec5SDimitry Andric }
18910b57cec5SDimitry Andric kmp_adaptive_lock_statistics_t *t = &total;
18920b57cec5SDimitry Andric kmp_uint32 totalSections =
18930b57cec5SDimitry Andric t->nonSpeculativeAcquires + t->successfulSpeculations;
18940b57cec5SDimitry Andric kmp_uint32 totalSpeculations = t->successfulSpeculations +
18950b57cec5SDimitry Andric t->hardFailedSpeculations +
18960b57cec5SDimitry Andric t->softFailedSpeculations;
18970b57cec5SDimitry Andric if (totalSections <= 0)
18980b57cec5SDimitry Andric return;
18990b57cec5SDimitry Andric
1900e8d8bef9SDimitry Andric kmp_safe_raii_file_t statsFile;
1901e8d8bef9SDimitry Andric if (strcmp(__kmp_speculative_statsfile, "-") == 0) {
1902e8d8bef9SDimitry Andric statsFile.set_stdout();
1903e8d8bef9SDimitry Andric } else {
1904e8d8bef9SDimitry Andric size_t buffLen = KMP_STRLEN(__kmp_speculative_statsfile) + 20;
1905e8d8bef9SDimitry Andric char buffer[buffLen];
1906e8d8bef9SDimitry Andric KMP_SNPRINTF(&buffer[0], buffLen, __kmp_speculative_statsfile,
1907e8d8bef9SDimitry Andric (kmp_int32)getpid());
1908e8d8bef9SDimitry Andric statsFile.open(buffer, "w");
1909e8d8bef9SDimitry Andric }
19100b57cec5SDimitry Andric
19110b57cec5SDimitry Andric fprintf(statsFile, "Speculative lock statistics (all approximate!)\n");
1912fe6060f1SDimitry Andric fprintf(statsFile,
1913fe6060f1SDimitry Andric " Lock parameters: \n"
19140b57cec5SDimitry Andric " max_soft_retries : %10d\n"
19150b57cec5SDimitry Andric " max_badness : %10d\n",
19160b57cec5SDimitry Andric __kmp_adaptive_backoff_params.max_soft_retries,
19170b57cec5SDimitry Andric __kmp_adaptive_backoff_params.max_badness);
19180b57cec5SDimitry Andric fprintf(statsFile, " Non-speculative acquire attempts : %10d\n",
19190b57cec5SDimitry Andric t->nonSpeculativeAcquireAttempts);
19200b57cec5SDimitry Andric fprintf(statsFile, " Total critical sections : %10d\n",
19210b57cec5SDimitry Andric totalSections);
19220b57cec5SDimitry Andric fprintf(statsFile, " Successful speculations : %10d (%5.1f%%)\n",
19230b57cec5SDimitry Andric t->successfulSpeculations,
19240b57cec5SDimitry Andric percent(t->successfulSpeculations, totalSections));
19250b57cec5SDimitry Andric fprintf(statsFile, " Non-speculative acquires : %10d (%5.1f%%)\n",
19260b57cec5SDimitry Andric t->nonSpeculativeAcquires,
19270b57cec5SDimitry Andric percent(t->nonSpeculativeAcquires, totalSections));
19280b57cec5SDimitry Andric fprintf(statsFile, " Lemming yields : %10d\n\n",
19290b57cec5SDimitry Andric t->lemmingYields);
19300b57cec5SDimitry Andric
19310b57cec5SDimitry Andric fprintf(statsFile, " Speculative acquire attempts : %10d\n",
19320b57cec5SDimitry Andric totalSpeculations);
19330b57cec5SDimitry Andric fprintf(statsFile, " Successes : %10d (%5.1f%%)\n",
19340b57cec5SDimitry Andric t->successfulSpeculations,
19350b57cec5SDimitry Andric percent(t->successfulSpeculations, totalSpeculations));
19360b57cec5SDimitry Andric fprintf(statsFile, " Soft failures : %10d (%5.1f%%)\n",
19370b57cec5SDimitry Andric t->softFailedSpeculations,
19380b57cec5SDimitry Andric percent(t->softFailedSpeculations, totalSpeculations));
19390b57cec5SDimitry Andric fprintf(statsFile, " Hard failures : %10d (%5.1f%%)\n",
19400b57cec5SDimitry Andric t->hardFailedSpeculations,
19410b57cec5SDimitry Andric percent(t->hardFailedSpeculations, totalSpeculations));
19420b57cec5SDimitry Andric }
19430b57cec5SDimitry Andric
19440b57cec5SDimitry Andric #define KMP_INC_STAT(lck, stat) (lck->lk.adaptive.stats.stat++)
19450b57cec5SDimitry Andric #else
19460b57cec5SDimitry Andric #define KMP_INC_STAT(lck, stat)
19470b57cec5SDimitry Andric
19480b57cec5SDimitry Andric #endif // KMP_DEBUG_ADAPTIVE_LOCKS
19490b57cec5SDimitry Andric
__kmp_is_unlocked_queuing_lock(kmp_queuing_lock_t * lck)19500b57cec5SDimitry Andric static inline bool __kmp_is_unlocked_queuing_lock(kmp_queuing_lock_t *lck) {
19510b57cec5SDimitry Andric // It is enough to check that the head_id is zero.
19520b57cec5SDimitry Andric // We don't also need to check the tail.
19530b57cec5SDimitry Andric bool res = lck->lk.head_id == 0;
19540b57cec5SDimitry Andric
19550b57cec5SDimitry Andric // We need a fence here, since we must ensure that no memory operations
19560b57cec5SDimitry Andric // from later in this thread float above that read.
195781ad6265SDimitry Andric #if KMP_COMPILER_ICC || KMP_COMPILER_ICX
19580b57cec5SDimitry Andric _mm_mfence();
19590b57cec5SDimitry Andric #else
19600b57cec5SDimitry Andric __sync_synchronize();
19610b57cec5SDimitry Andric #endif
19620b57cec5SDimitry Andric
19630b57cec5SDimitry Andric return res;
19640b57cec5SDimitry Andric }
19650b57cec5SDimitry Andric
19660b57cec5SDimitry Andric // Functions for manipulating the badness
19670b57cec5SDimitry Andric static __inline void
__kmp_update_badness_after_success(kmp_adaptive_lock_t * lck)19680b57cec5SDimitry Andric __kmp_update_badness_after_success(kmp_adaptive_lock_t *lck) {
19690b57cec5SDimitry Andric // Reset the badness to zero so we eagerly try to speculate again
19700b57cec5SDimitry Andric lck->lk.adaptive.badness = 0;
19710b57cec5SDimitry Andric KMP_INC_STAT(lck, successfulSpeculations);
19720b57cec5SDimitry Andric }
19730b57cec5SDimitry Andric
19740b57cec5SDimitry Andric // Create a bit mask with one more set bit.
__kmp_step_badness(kmp_adaptive_lock_t * lck)19750b57cec5SDimitry Andric static __inline void __kmp_step_badness(kmp_adaptive_lock_t *lck) {
19760b57cec5SDimitry Andric kmp_uint32 newBadness = (lck->lk.adaptive.badness << 1) | 1;
19770b57cec5SDimitry Andric if (newBadness > lck->lk.adaptive.max_badness) {
19780b57cec5SDimitry Andric return;
19790b57cec5SDimitry Andric } else {
19800b57cec5SDimitry Andric lck->lk.adaptive.badness = newBadness;
19810b57cec5SDimitry Andric }
19820b57cec5SDimitry Andric }
19830b57cec5SDimitry Andric
19840b57cec5SDimitry Andric // Check whether speculation should be attempted.
1985e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_should_speculate(kmp_adaptive_lock_t * lck,kmp_int32 gtid)19860b57cec5SDimitry Andric static __inline int __kmp_should_speculate(kmp_adaptive_lock_t *lck,
19870b57cec5SDimitry Andric kmp_int32 gtid) {
19880b57cec5SDimitry Andric kmp_uint32 badness = lck->lk.adaptive.badness;
19890b57cec5SDimitry Andric kmp_uint32 attempts = lck->lk.adaptive.acquire_attempts;
19900b57cec5SDimitry Andric int res = (attempts & badness) == 0;
19910b57cec5SDimitry Andric return res;
19920b57cec5SDimitry Andric }
19930b57cec5SDimitry Andric
19940b57cec5SDimitry Andric // Attempt to acquire only the speculative lock.
19950b57cec5SDimitry Andric // Does not back off to the non-speculative lock.
1996e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_test_adaptive_lock_only(kmp_adaptive_lock_t * lck,kmp_int32 gtid)19970b57cec5SDimitry Andric static int __kmp_test_adaptive_lock_only(kmp_adaptive_lock_t *lck,
19980b57cec5SDimitry Andric kmp_int32 gtid) {
19990b57cec5SDimitry Andric int retries = lck->lk.adaptive.max_soft_retries;
20000b57cec5SDimitry Andric
20010b57cec5SDimitry Andric // We don't explicitly count the start of speculation, rather we record the
20020b57cec5SDimitry Andric // results (success, hard fail, soft fail). The sum of all of those is the
20030b57cec5SDimitry Andric // total number of times we started speculation since all speculations must
20040b57cec5SDimitry Andric // end one of those ways.
20050b57cec5SDimitry Andric do {
20060b57cec5SDimitry Andric kmp_uint32 status = _xbegin();
20070b57cec5SDimitry Andric // Switch this in to disable actual speculation but exercise at least some
20080b57cec5SDimitry Andric // of the rest of the code. Useful for debugging...
20090b57cec5SDimitry Andric // kmp_uint32 status = _XABORT_NESTED;
20100b57cec5SDimitry Andric
20110b57cec5SDimitry Andric if (status == _XBEGIN_STARTED) {
20120b57cec5SDimitry Andric /* We have successfully started speculation. Check that no-one acquired
20130b57cec5SDimitry Andric the lock for real between when we last looked and now. This also gets
20140b57cec5SDimitry Andric the lock cache line into our read-set, which we need so that we'll
20150b57cec5SDimitry Andric abort if anyone later claims it for real. */
20160b57cec5SDimitry Andric if (!__kmp_is_unlocked_queuing_lock(GET_QLK_PTR(lck))) {
20170b57cec5SDimitry Andric // Lock is now visibly acquired, so someone beat us to it. Abort the
20180b57cec5SDimitry Andric // transaction so we'll restart from _xbegin with the failure status.
20190b57cec5SDimitry Andric _xabort(0x01);
20200b57cec5SDimitry Andric KMP_ASSERT2(0, "should not get here");
20210b57cec5SDimitry Andric }
20220b57cec5SDimitry Andric return 1; // Lock has been acquired (speculatively)
20230b57cec5SDimitry Andric } else {
20240b57cec5SDimitry Andric // We have aborted, update the statistics
20250b57cec5SDimitry Andric if (status & SOFT_ABORT_MASK) {
20260b57cec5SDimitry Andric KMP_INC_STAT(lck, softFailedSpeculations);
20270b57cec5SDimitry Andric // and loop round to retry.
20280b57cec5SDimitry Andric } else {
20290b57cec5SDimitry Andric KMP_INC_STAT(lck, hardFailedSpeculations);
20300b57cec5SDimitry Andric // Give up if we had a hard failure.
20310b57cec5SDimitry Andric break;
20320b57cec5SDimitry Andric }
20330b57cec5SDimitry Andric }
20340b57cec5SDimitry Andric } while (retries--); // Loop while we have retries, and didn't fail hard.
20350b57cec5SDimitry Andric
20360b57cec5SDimitry Andric // Either we had a hard failure or we didn't succeed softly after
20370b57cec5SDimitry Andric // the full set of attempts, so back off the badness.
20380b57cec5SDimitry Andric __kmp_step_badness(lck);
20390b57cec5SDimitry Andric return 0;
20400b57cec5SDimitry Andric }
20410b57cec5SDimitry Andric
20420b57cec5SDimitry Andric // Attempt to acquire the speculative lock, or back off to the non-speculative
20430b57cec5SDimitry Andric // one if the speculative lock cannot be acquired.
20440b57cec5SDimitry Andric // We can succeed speculatively, non-speculatively, or fail.
__kmp_test_adaptive_lock(kmp_adaptive_lock_t * lck,kmp_int32 gtid)20450b57cec5SDimitry Andric static int __kmp_test_adaptive_lock(kmp_adaptive_lock_t *lck, kmp_int32 gtid) {
20460b57cec5SDimitry Andric // First try to acquire the lock speculatively
20470b57cec5SDimitry Andric if (__kmp_should_speculate(lck, gtid) &&
20480b57cec5SDimitry Andric __kmp_test_adaptive_lock_only(lck, gtid))
20490b57cec5SDimitry Andric return 1;
20500b57cec5SDimitry Andric
20510b57cec5SDimitry Andric // Speculative acquisition failed, so try to acquire it non-speculatively.
20520b57cec5SDimitry Andric // Count the non-speculative acquire attempt
20530b57cec5SDimitry Andric lck->lk.adaptive.acquire_attempts++;
20540b57cec5SDimitry Andric
20550b57cec5SDimitry Andric // Use base, non-speculative lock.
20560b57cec5SDimitry Andric if (__kmp_test_queuing_lock(GET_QLK_PTR(lck), gtid)) {
20570b57cec5SDimitry Andric KMP_INC_STAT(lck, nonSpeculativeAcquires);
20580b57cec5SDimitry Andric return 1; // Lock is acquired (non-speculatively)
20590b57cec5SDimitry Andric } else {
20600b57cec5SDimitry Andric return 0; // Failed to acquire the lock, it's already visibly locked.
20610b57cec5SDimitry Andric }
20620b57cec5SDimitry Andric }
20630b57cec5SDimitry Andric
__kmp_test_adaptive_lock_with_checks(kmp_adaptive_lock_t * lck,kmp_int32 gtid)20640b57cec5SDimitry Andric static int __kmp_test_adaptive_lock_with_checks(kmp_adaptive_lock_t *lck,
20650b57cec5SDimitry Andric kmp_int32 gtid) {
20660b57cec5SDimitry Andric char const *const func = "omp_test_lock";
20670b57cec5SDimitry Andric if (lck->lk.qlk.initialized != GET_QLK_PTR(lck)) {
20680b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
20690b57cec5SDimitry Andric }
20700b57cec5SDimitry Andric
20710b57cec5SDimitry Andric int retval = __kmp_test_adaptive_lock(lck, gtid);
20720b57cec5SDimitry Andric
20730b57cec5SDimitry Andric if (retval) {
20740b57cec5SDimitry Andric lck->lk.qlk.owner_id = gtid + 1;
20750b57cec5SDimitry Andric }
20760b57cec5SDimitry Andric return retval;
20770b57cec5SDimitry Andric }
20780b57cec5SDimitry Andric
20790b57cec5SDimitry Andric // Block until we can acquire a speculative, adaptive lock. We check whether we
20800b57cec5SDimitry Andric // should be trying to speculate. If we should be, we check the real lock to see
20810b57cec5SDimitry Andric // if it is free, and, if not, pause without attempting to acquire it until it
20820b57cec5SDimitry Andric // is. Then we try the speculative acquire. This means that although we suffer
20830b57cec5SDimitry Andric // from lemmings a little (because all we can't acquire the lock speculatively
20840b57cec5SDimitry Andric // until the queue of threads waiting has cleared), we don't get into a state
20850b57cec5SDimitry Andric // where we can never acquire the lock speculatively (because we force the queue
20860b57cec5SDimitry Andric // to clear by preventing new arrivals from entering the queue). This does mean
20870b57cec5SDimitry Andric // that when we're trying to break lemmings, the lock is no longer fair. However
20880b57cec5SDimitry Andric // OpenMP makes no guarantee that its locks are fair, so this isn't a real
20890b57cec5SDimitry Andric // problem.
__kmp_acquire_adaptive_lock(kmp_adaptive_lock_t * lck,kmp_int32 gtid)20900b57cec5SDimitry Andric static void __kmp_acquire_adaptive_lock(kmp_adaptive_lock_t *lck,
20910b57cec5SDimitry Andric kmp_int32 gtid) {
20920b57cec5SDimitry Andric if (__kmp_should_speculate(lck, gtid)) {
20930b57cec5SDimitry Andric if (__kmp_is_unlocked_queuing_lock(GET_QLK_PTR(lck))) {
20940b57cec5SDimitry Andric if (__kmp_test_adaptive_lock_only(lck, gtid))
20950b57cec5SDimitry Andric return;
20960b57cec5SDimitry Andric // We tried speculation and failed, so give up.
20970b57cec5SDimitry Andric } else {
20980b57cec5SDimitry Andric // We can't try speculation until the lock is free, so we pause here
20990b57cec5SDimitry Andric // (without suspending on the queueing lock, to allow it to drain, then
21000b57cec5SDimitry Andric // try again. All other threads will also see the same result for
21010b57cec5SDimitry Andric // shouldSpeculate, so will be doing the same if they try to claim the
21020b57cec5SDimitry Andric // lock from now on.
21030b57cec5SDimitry Andric while (!__kmp_is_unlocked_queuing_lock(GET_QLK_PTR(lck))) {
21040b57cec5SDimitry Andric KMP_INC_STAT(lck, lemmingYields);
21050b57cec5SDimitry Andric KMP_YIELD(TRUE);
21060b57cec5SDimitry Andric }
21070b57cec5SDimitry Andric
21080b57cec5SDimitry Andric if (__kmp_test_adaptive_lock_only(lck, gtid))
21090b57cec5SDimitry Andric return;
21100b57cec5SDimitry Andric }
21110b57cec5SDimitry Andric }
21120b57cec5SDimitry Andric
21130b57cec5SDimitry Andric // Speculative acquisition failed, so acquire it non-speculatively.
21140b57cec5SDimitry Andric // Count the non-speculative acquire attempt
21150b57cec5SDimitry Andric lck->lk.adaptive.acquire_attempts++;
21160b57cec5SDimitry Andric
21170b57cec5SDimitry Andric __kmp_acquire_queuing_lock_timed_template<FALSE>(GET_QLK_PTR(lck), gtid);
21180b57cec5SDimitry Andric // We have acquired the base lock, so count that.
21190b57cec5SDimitry Andric KMP_INC_STAT(lck, nonSpeculativeAcquires);
21200b57cec5SDimitry Andric }
21210b57cec5SDimitry Andric
__kmp_acquire_adaptive_lock_with_checks(kmp_adaptive_lock_t * lck,kmp_int32 gtid)21220b57cec5SDimitry Andric static void __kmp_acquire_adaptive_lock_with_checks(kmp_adaptive_lock_t *lck,
21230b57cec5SDimitry Andric kmp_int32 gtid) {
21240b57cec5SDimitry Andric char const *const func = "omp_set_lock";
21250b57cec5SDimitry Andric if (lck->lk.qlk.initialized != GET_QLK_PTR(lck)) {
21260b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
21270b57cec5SDimitry Andric }
21280b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(GET_QLK_PTR(lck)) == gtid) {
21290b57cec5SDimitry Andric KMP_FATAL(LockIsAlreadyOwned, func);
21300b57cec5SDimitry Andric }
21310b57cec5SDimitry Andric
21320b57cec5SDimitry Andric __kmp_acquire_adaptive_lock(lck, gtid);
21330b57cec5SDimitry Andric
21340b57cec5SDimitry Andric lck->lk.qlk.owner_id = gtid + 1;
21350b57cec5SDimitry Andric }
21360b57cec5SDimitry Andric
2137e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_release_adaptive_lock(kmp_adaptive_lock_t * lck,kmp_int32 gtid)21380b57cec5SDimitry Andric static int __kmp_release_adaptive_lock(kmp_adaptive_lock_t *lck,
21390b57cec5SDimitry Andric kmp_int32 gtid) {
21400b57cec5SDimitry Andric if (__kmp_is_unlocked_queuing_lock(GET_QLK_PTR(
21410b57cec5SDimitry Andric lck))) { // If the lock doesn't look claimed we must be speculating.
21420b57cec5SDimitry Andric // (Or the user's code is buggy and they're releasing without locking;
21430b57cec5SDimitry Andric // if we had XTEST we'd be able to check that case...)
21440b57cec5SDimitry Andric _xend(); // Exit speculation
21450b57cec5SDimitry Andric __kmp_update_badness_after_success(lck);
21460b57cec5SDimitry Andric } else { // Since the lock *is* visibly locked we're not speculating,
21470b57cec5SDimitry Andric // so should use the underlying lock's release scheme.
21480b57cec5SDimitry Andric __kmp_release_queuing_lock(GET_QLK_PTR(lck), gtid);
21490b57cec5SDimitry Andric }
21500b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
21510b57cec5SDimitry Andric }
21520b57cec5SDimitry Andric
__kmp_release_adaptive_lock_with_checks(kmp_adaptive_lock_t * lck,kmp_int32 gtid)21530b57cec5SDimitry Andric static int __kmp_release_adaptive_lock_with_checks(kmp_adaptive_lock_t *lck,
21540b57cec5SDimitry Andric kmp_int32 gtid) {
21550b57cec5SDimitry Andric char const *const func = "omp_unset_lock";
21560b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
21570b57cec5SDimitry Andric if (lck->lk.qlk.initialized != GET_QLK_PTR(lck)) {
21580b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
21590b57cec5SDimitry Andric }
21600b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(GET_QLK_PTR(lck)) == -1) {
21610b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
21620b57cec5SDimitry Andric }
21630b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(GET_QLK_PTR(lck)) != gtid) {
21640b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
21650b57cec5SDimitry Andric }
21660b57cec5SDimitry Andric lck->lk.qlk.owner_id = 0;
21670b57cec5SDimitry Andric __kmp_release_adaptive_lock(lck, gtid);
21680b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
21690b57cec5SDimitry Andric }
21700b57cec5SDimitry Andric
__kmp_init_adaptive_lock(kmp_adaptive_lock_t * lck)21710b57cec5SDimitry Andric static void __kmp_init_adaptive_lock(kmp_adaptive_lock_t *lck) {
21720b57cec5SDimitry Andric __kmp_init_queuing_lock(GET_QLK_PTR(lck));
21730b57cec5SDimitry Andric lck->lk.adaptive.badness = 0;
21740b57cec5SDimitry Andric lck->lk.adaptive.acquire_attempts = 0; // nonSpeculativeAcquireAttempts = 0;
21750b57cec5SDimitry Andric lck->lk.adaptive.max_soft_retries =
21760b57cec5SDimitry Andric __kmp_adaptive_backoff_params.max_soft_retries;
21770b57cec5SDimitry Andric lck->lk.adaptive.max_badness = __kmp_adaptive_backoff_params.max_badness;
21780b57cec5SDimitry Andric #if KMP_DEBUG_ADAPTIVE_LOCKS
21790b57cec5SDimitry Andric __kmp_zero_speculative_stats(&lck->lk.adaptive);
21800b57cec5SDimitry Andric #endif
21810b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_init_adaptive_lock: lock %p initialized\n", lck));
21820b57cec5SDimitry Andric }
21830b57cec5SDimitry Andric
__kmp_destroy_adaptive_lock(kmp_adaptive_lock_t * lck)21840b57cec5SDimitry Andric static void __kmp_destroy_adaptive_lock(kmp_adaptive_lock_t *lck) {
21850b57cec5SDimitry Andric #if KMP_DEBUG_ADAPTIVE_LOCKS
21860b57cec5SDimitry Andric __kmp_accumulate_speculative_stats(&lck->lk.adaptive);
21870b57cec5SDimitry Andric #endif
21880b57cec5SDimitry Andric __kmp_destroy_queuing_lock(GET_QLK_PTR(lck));
21890b57cec5SDimitry Andric // Nothing needed for the speculative part.
21900b57cec5SDimitry Andric }
21910b57cec5SDimitry Andric
__kmp_destroy_adaptive_lock_with_checks(kmp_adaptive_lock_t * lck)21920b57cec5SDimitry Andric static void __kmp_destroy_adaptive_lock_with_checks(kmp_adaptive_lock_t *lck) {
21930b57cec5SDimitry Andric char const *const func = "omp_destroy_lock";
21940b57cec5SDimitry Andric if (lck->lk.qlk.initialized != GET_QLK_PTR(lck)) {
21950b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
21960b57cec5SDimitry Andric }
21970b57cec5SDimitry Andric if (__kmp_get_queuing_lock_owner(GET_QLK_PTR(lck)) != -1) {
21980b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
21990b57cec5SDimitry Andric }
22000b57cec5SDimitry Andric __kmp_destroy_adaptive_lock(lck);
22010b57cec5SDimitry Andric }
22020b57cec5SDimitry Andric
22030b57cec5SDimitry Andric #endif // KMP_USE_ADAPTIVE_LOCKS
22040b57cec5SDimitry Andric
22050b57cec5SDimitry Andric /* ------------------------------------------------------------------------ */
22060b57cec5SDimitry Andric /* DRDPA ticket locks */
22070b57cec5SDimitry Andric /* "DRDPA" means Dynamically Reconfigurable Distributed Polling Area */
22080b57cec5SDimitry Andric
__kmp_get_drdpa_lock_owner(kmp_drdpa_lock_t * lck)22090b57cec5SDimitry Andric static kmp_int32 __kmp_get_drdpa_lock_owner(kmp_drdpa_lock_t *lck) {
22100b57cec5SDimitry Andric return lck->lk.owner_id - 1;
22110b57cec5SDimitry Andric }
22120b57cec5SDimitry Andric
__kmp_is_drdpa_lock_nestable(kmp_drdpa_lock_t * lck)22130b57cec5SDimitry Andric static inline bool __kmp_is_drdpa_lock_nestable(kmp_drdpa_lock_t *lck) {
22140b57cec5SDimitry Andric return lck->lk.depth_locked != -1;
22150b57cec5SDimitry Andric }
22160b57cec5SDimitry Andric
22170b57cec5SDimitry Andric __forceinline static int
__kmp_acquire_drdpa_lock_timed_template(kmp_drdpa_lock_t * lck,kmp_int32 gtid)22180b57cec5SDimitry Andric __kmp_acquire_drdpa_lock_timed_template(kmp_drdpa_lock_t *lck, kmp_int32 gtid) {
22190b57cec5SDimitry Andric kmp_uint64 ticket = KMP_ATOMIC_INC(&lck->lk.next_ticket);
22200b57cec5SDimitry Andric kmp_uint64 mask = lck->lk.mask; // atomic load
22210b57cec5SDimitry Andric std::atomic<kmp_uint64> *polls = lck->lk.polls;
22220b57cec5SDimitry Andric
22230b57cec5SDimitry Andric #ifdef USE_LOCK_PROFILE
22240b57cec5SDimitry Andric if (polls[ticket & mask] != ticket)
22250b57cec5SDimitry Andric __kmp_printf("LOCK CONTENTION: %p\n", lck);
22260b57cec5SDimitry Andric /* else __kmp_printf( "." );*/
22270b57cec5SDimitry Andric #endif /* USE_LOCK_PROFILE */
22280b57cec5SDimitry Andric
22290b57cec5SDimitry Andric // Now spin-wait, but reload the polls pointer and mask, in case the
22300b57cec5SDimitry Andric // polling area has been reconfigured. Unless it is reconfigured, the
22310b57cec5SDimitry Andric // reloads stay in L1 cache and are cheap.
22320b57cec5SDimitry Andric //
22330b57cec5SDimitry Andric // Keep this code in sync with KMP_WAIT, in kmp_dispatch.cpp !!!
22340b57cec5SDimitry Andric // The current implementation of KMP_WAIT doesn't allow for mask
22350b57cec5SDimitry Andric // and poll to be re-read every spin iteration.
22360b57cec5SDimitry Andric kmp_uint32 spins;
223704eeddc0SDimitry Andric kmp_uint64 time;
22380b57cec5SDimitry Andric KMP_FSYNC_PREPARE(lck);
22390b57cec5SDimitry Andric KMP_INIT_YIELD(spins);
224004eeddc0SDimitry Andric KMP_INIT_BACKOFF(time);
22410b57cec5SDimitry Andric while (polls[ticket & mask] < ticket) { // atomic load
224204eeddc0SDimitry Andric KMP_YIELD_OVERSUB_ELSE_SPIN(spins, time);
22430b57cec5SDimitry Andric // Re-read the mask and the poll pointer from the lock structure.
22440b57cec5SDimitry Andric //
22450b57cec5SDimitry Andric // Make certain that "mask" is read before "polls" !!!
22460b57cec5SDimitry Andric //
22470b57cec5SDimitry Andric // If another thread picks reconfigures the polling area and updates their
22480b57cec5SDimitry Andric // values, and we get the new value of mask and the old polls pointer, we
22490b57cec5SDimitry Andric // could access memory beyond the end of the old polling area.
22500b57cec5SDimitry Andric mask = lck->lk.mask; // atomic load
22510b57cec5SDimitry Andric polls = lck->lk.polls; // atomic load
22520b57cec5SDimitry Andric }
22530b57cec5SDimitry Andric
22540b57cec5SDimitry Andric // Critical section starts here
22550b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
22560b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_acquire_drdpa_lock: ticket #%lld acquired lock %p\n",
22570b57cec5SDimitry Andric ticket, lck));
22580b57cec5SDimitry Andric lck->lk.now_serving = ticket; // non-volatile store
22590b57cec5SDimitry Andric
22600b57cec5SDimitry Andric // Deallocate a garbage polling area if we know that we are the last
22610b57cec5SDimitry Andric // thread that could possibly access it.
22620b57cec5SDimitry Andric //
22630b57cec5SDimitry Andric // The >= check is in case __kmp_test_drdpa_lock() allocated the cleanup
22640b57cec5SDimitry Andric // ticket.
22650b57cec5SDimitry Andric if ((lck->lk.old_polls != NULL) && (ticket >= lck->lk.cleanup_ticket)) {
22660b57cec5SDimitry Andric __kmp_free(lck->lk.old_polls);
22670b57cec5SDimitry Andric lck->lk.old_polls = NULL;
22680b57cec5SDimitry Andric lck->lk.cleanup_ticket = 0;
22690b57cec5SDimitry Andric }
22700b57cec5SDimitry Andric
22710b57cec5SDimitry Andric // Check to see if we should reconfigure the polling area.
22720b57cec5SDimitry Andric // If there is still a garbage polling area to be deallocated from a
22730b57cec5SDimitry Andric // previous reconfiguration, let a later thread reconfigure it.
22740b57cec5SDimitry Andric if (lck->lk.old_polls == NULL) {
22750b57cec5SDimitry Andric bool reconfigure = false;
22760b57cec5SDimitry Andric std::atomic<kmp_uint64> *old_polls = polls;
22770b57cec5SDimitry Andric kmp_uint32 num_polls = TCR_4(lck->lk.num_polls);
22780b57cec5SDimitry Andric
22790b57cec5SDimitry Andric if (TCR_4(__kmp_nth) >
22800b57cec5SDimitry Andric (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) {
22810b57cec5SDimitry Andric // We are in oversubscription mode. Contract the polling area
22820b57cec5SDimitry Andric // down to a single location, if that hasn't been done already.
22830b57cec5SDimitry Andric if (num_polls > 1) {
22840b57cec5SDimitry Andric reconfigure = true;
22850b57cec5SDimitry Andric num_polls = TCR_4(lck->lk.num_polls);
22860b57cec5SDimitry Andric mask = 0;
22870b57cec5SDimitry Andric num_polls = 1;
22880b57cec5SDimitry Andric polls = (std::atomic<kmp_uint64> *)__kmp_allocate(num_polls *
22890b57cec5SDimitry Andric sizeof(*polls));
22900b57cec5SDimitry Andric polls[0] = ticket;
22910b57cec5SDimitry Andric }
22920b57cec5SDimitry Andric } else {
22930b57cec5SDimitry Andric // We are in under/fully subscribed mode. Check the number of
22940b57cec5SDimitry Andric // threads waiting on the lock. The size of the polling area
22950b57cec5SDimitry Andric // should be at least the number of threads waiting.
22960b57cec5SDimitry Andric kmp_uint64 num_waiting = TCR_8(lck->lk.next_ticket) - ticket - 1;
22970b57cec5SDimitry Andric if (num_waiting > num_polls) {
22980b57cec5SDimitry Andric kmp_uint32 old_num_polls = num_polls;
22990b57cec5SDimitry Andric reconfigure = true;
23000b57cec5SDimitry Andric do {
23010b57cec5SDimitry Andric mask = (mask << 1) | 1;
23020b57cec5SDimitry Andric num_polls *= 2;
23030b57cec5SDimitry Andric } while (num_polls <= num_waiting);
23040b57cec5SDimitry Andric
23050b57cec5SDimitry Andric // Allocate the new polling area, and copy the relevant portion
23060b57cec5SDimitry Andric // of the old polling area to the new area. __kmp_allocate()
23070b57cec5SDimitry Andric // zeroes the memory it allocates, and most of the old area is
23080b57cec5SDimitry Andric // just zero padding, so we only copy the release counters.
23090b57cec5SDimitry Andric polls = (std::atomic<kmp_uint64> *)__kmp_allocate(num_polls *
23100b57cec5SDimitry Andric sizeof(*polls));
23110b57cec5SDimitry Andric kmp_uint32 i;
23120b57cec5SDimitry Andric for (i = 0; i < old_num_polls; i++) {
23130b57cec5SDimitry Andric polls[i].store(old_polls[i]);
23140b57cec5SDimitry Andric }
23150b57cec5SDimitry Andric }
23160b57cec5SDimitry Andric }
23170b57cec5SDimitry Andric
23180b57cec5SDimitry Andric if (reconfigure) {
23190b57cec5SDimitry Andric // Now write the updated fields back to the lock structure.
23200b57cec5SDimitry Andric //
23210b57cec5SDimitry Andric // Make certain that "polls" is written before "mask" !!!
23220b57cec5SDimitry Andric //
23230b57cec5SDimitry Andric // If another thread picks up the new value of mask and the old polls
23240b57cec5SDimitry Andric // pointer , it could access memory beyond the end of the old polling
23250b57cec5SDimitry Andric // area.
23260b57cec5SDimitry Andric //
23270b57cec5SDimitry Andric // On x86, we need memory fences.
23280b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_acquire_drdpa_lock: ticket #%lld reconfiguring "
23290b57cec5SDimitry Andric "lock %p to %d polls\n",
23300b57cec5SDimitry Andric ticket, lck, num_polls));
23310b57cec5SDimitry Andric
23320b57cec5SDimitry Andric lck->lk.old_polls = old_polls;
23330b57cec5SDimitry Andric lck->lk.polls = polls; // atomic store
23340b57cec5SDimitry Andric
23350b57cec5SDimitry Andric KMP_MB();
23360b57cec5SDimitry Andric
23370b57cec5SDimitry Andric lck->lk.num_polls = num_polls;
23380b57cec5SDimitry Andric lck->lk.mask = mask; // atomic store
23390b57cec5SDimitry Andric
23400b57cec5SDimitry Andric KMP_MB();
23410b57cec5SDimitry Andric
23420b57cec5SDimitry Andric // Only after the new polling area and mask have been flushed
23430b57cec5SDimitry Andric // to main memory can we update the cleanup ticket field.
23440b57cec5SDimitry Andric //
23450b57cec5SDimitry Andric // volatile load / non-volatile store
23460b57cec5SDimitry Andric lck->lk.cleanup_ticket = lck->lk.next_ticket;
23470b57cec5SDimitry Andric }
23480b57cec5SDimitry Andric }
23490b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
23500b57cec5SDimitry Andric }
23510b57cec5SDimitry Andric
__kmp_acquire_drdpa_lock(kmp_drdpa_lock_t * lck,kmp_int32 gtid)23520b57cec5SDimitry Andric int __kmp_acquire_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid) {
23530b57cec5SDimitry Andric int retval = __kmp_acquire_drdpa_lock_timed_template(lck, gtid);
23540b57cec5SDimitry Andric return retval;
23550b57cec5SDimitry Andric }
23560b57cec5SDimitry Andric
__kmp_acquire_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck,kmp_int32 gtid)23570b57cec5SDimitry Andric static int __kmp_acquire_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck,
23580b57cec5SDimitry Andric kmp_int32 gtid) {
23590b57cec5SDimitry Andric char const *const func = "omp_set_lock";
23600b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
23610b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
23620b57cec5SDimitry Andric }
23630b57cec5SDimitry Andric if (__kmp_is_drdpa_lock_nestable(lck)) {
23640b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
23650b57cec5SDimitry Andric }
23660b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_drdpa_lock_owner(lck) == gtid)) {
23670b57cec5SDimitry Andric KMP_FATAL(LockIsAlreadyOwned, func);
23680b57cec5SDimitry Andric }
23690b57cec5SDimitry Andric
23700b57cec5SDimitry Andric __kmp_acquire_drdpa_lock(lck, gtid);
23710b57cec5SDimitry Andric
23720b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
23730b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
23740b57cec5SDimitry Andric }
23750b57cec5SDimitry Andric
__kmp_test_drdpa_lock(kmp_drdpa_lock_t * lck,kmp_int32 gtid)23760b57cec5SDimitry Andric int __kmp_test_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid) {
23770b57cec5SDimitry Andric // First get a ticket, then read the polls pointer and the mask.
23780b57cec5SDimitry Andric // The polls pointer must be read before the mask!!! (See above)
23790b57cec5SDimitry Andric kmp_uint64 ticket = lck->lk.next_ticket; // atomic load
23800b57cec5SDimitry Andric std::atomic<kmp_uint64> *polls = lck->lk.polls;
23810b57cec5SDimitry Andric kmp_uint64 mask = lck->lk.mask; // atomic load
23820b57cec5SDimitry Andric if (polls[ticket & mask] == ticket) {
23830b57cec5SDimitry Andric kmp_uint64 next_ticket = ticket + 1;
23840b57cec5SDimitry Andric if (__kmp_atomic_compare_store_acq(&lck->lk.next_ticket, ticket,
23850b57cec5SDimitry Andric next_ticket)) {
23860b57cec5SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
23870b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_test_drdpa_lock: ticket #%lld acquired lock %p\n",
23880b57cec5SDimitry Andric ticket, lck));
23890b57cec5SDimitry Andric lck->lk.now_serving = ticket; // non-volatile store
23900b57cec5SDimitry Andric
23910b57cec5SDimitry Andric // Since no threads are waiting, there is no possibility that we would
23920b57cec5SDimitry Andric // want to reconfigure the polling area. We might have the cleanup ticket
23930b57cec5SDimitry Andric // value (which says that it is now safe to deallocate old_polls), but
23940b57cec5SDimitry Andric // we'll let a later thread which calls __kmp_acquire_lock do that - this
23950b57cec5SDimitry Andric // routine isn't supposed to block, and we would risk blocks if we called
23960b57cec5SDimitry Andric // __kmp_free() to do the deallocation.
23970b57cec5SDimitry Andric return TRUE;
23980b57cec5SDimitry Andric }
23990b57cec5SDimitry Andric }
24000b57cec5SDimitry Andric return FALSE;
24010b57cec5SDimitry Andric }
24020b57cec5SDimitry Andric
__kmp_test_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck,kmp_int32 gtid)24030b57cec5SDimitry Andric static int __kmp_test_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck,
24040b57cec5SDimitry Andric kmp_int32 gtid) {
24050b57cec5SDimitry Andric char const *const func = "omp_test_lock";
24060b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
24070b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
24080b57cec5SDimitry Andric }
24090b57cec5SDimitry Andric if (__kmp_is_drdpa_lock_nestable(lck)) {
24100b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
24110b57cec5SDimitry Andric }
24120b57cec5SDimitry Andric
24130b57cec5SDimitry Andric int retval = __kmp_test_drdpa_lock(lck, gtid);
24140b57cec5SDimitry Andric
24150b57cec5SDimitry Andric if (retval) {
24160b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
24170b57cec5SDimitry Andric }
24180b57cec5SDimitry Andric return retval;
24190b57cec5SDimitry Andric }
24200b57cec5SDimitry Andric
__kmp_release_drdpa_lock(kmp_drdpa_lock_t * lck,kmp_int32 gtid)24210b57cec5SDimitry Andric int __kmp_release_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid) {
24220b57cec5SDimitry Andric // Read the ticket value from the lock data struct, then the polls pointer and
24230b57cec5SDimitry Andric // the mask. The polls pointer must be read before the mask!!! (See above)
24240b57cec5SDimitry Andric kmp_uint64 ticket = lck->lk.now_serving + 1; // non-atomic load
24250b57cec5SDimitry Andric std::atomic<kmp_uint64> *polls = lck->lk.polls; // atomic load
24260b57cec5SDimitry Andric kmp_uint64 mask = lck->lk.mask; // atomic load
24270b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_release_drdpa_lock: ticket #%lld released lock %p\n",
24280b57cec5SDimitry Andric ticket - 1, lck));
24290b57cec5SDimitry Andric KMP_FSYNC_RELEASING(lck);
24300b57cec5SDimitry Andric polls[ticket & mask] = ticket; // atomic store
24310b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
24320b57cec5SDimitry Andric }
24330b57cec5SDimitry Andric
__kmp_release_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck,kmp_int32 gtid)24340b57cec5SDimitry Andric static int __kmp_release_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck,
24350b57cec5SDimitry Andric kmp_int32 gtid) {
24360b57cec5SDimitry Andric char const *const func = "omp_unset_lock";
24370b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
24380b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
24390b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
24400b57cec5SDimitry Andric }
24410b57cec5SDimitry Andric if (__kmp_is_drdpa_lock_nestable(lck)) {
24420b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
24430b57cec5SDimitry Andric }
24440b57cec5SDimitry Andric if (__kmp_get_drdpa_lock_owner(lck) == -1) {
24450b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
24460b57cec5SDimitry Andric }
24470b57cec5SDimitry Andric if ((gtid >= 0) && (__kmp_get_drdpa_lock_owner(lck) >= 0) &&
24480b57cec5SDimitry Andric (__kmp_get_drdpa_lock_owner(lck) != gtid)) {
24490b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
24500b57cec5SDimitry Andric }
24510b57cec5SDimitry Andric lck->lk.owner_id = 0;
24520b57cec5SDimitry Andric return __kmp_release_drdpa_lock(lck, gtid);
24530b57cec5SDimitry Andric }
24540b57cec5SDimitry Andric
__kmp_init_drdpa_lock(kmp_drdpa_lock_t * lck)24550b57cec5SDimitry Andric void __kmp_init_drdpa_lock(kmp_drdpa_lock_t *lck) {
24560b57cec5SDimitry Andric lck->lk.location = NULL;
24570b57cec5SDimitry Andric lck->lk.mask = 0;
24580b57cec5SDimitry Andric lck->lk.num_polls = 1;
24590b57cec5SDimitry Andric lck->lk.polls = (std::atomic<kmp_uint64> *)__kmp_allocate(
24600b57cec5SDimitry Andric lck->lk.num_polls * sizeof(*(lck->lk.polls)));
24610b57cec5SDimitry Andric lck->lk.cleanup_ticket = 0;
24620b57cec5SDimitry Andric lck->lk.old_polls = NULL;
24630b57cec5SDimitry Andric lck->lk.next_ticket = 0;
24640b57cec5SDimitry Andric lck->lk.now_serving = 0;
24650b57cec5SDimitry Andric lck->lk.owner_id = 0; // no thread owns the lock.
24660b57cec5SDimitry Andric lck->lk.depth_locked = -1; // >= 0 for nestable locks, -1 for simple locks.
24670b57cec5SDimitry Andric lck->lk.initialized = lck;
24680b57cec5SDimitry Andric
24690b57cec5SDimitry Andric KA_TRACE(1000, ("__kmp_init_drdpa_lock: lock %p initialized\n", lck));
24700b57cec5SDimitry Andric }
24710b57cec5SDimitry Andric
__kmp_destroy_drdpa_lock(kmp_drdpa_lock_t * lck)24720b57cec5SDimitry Andric void __kmp_destroy_drdpa_lock(kmp_drdpa_lock_t *lck) {
24730b57cec5SDimitry Andric lck->lk.initialized = NULL;
24740b57cec5SDimitry Andric lck->lk.location = NULL;
24750b57cec5SDimitry Andric if (lck->lk.polls.load() != NULL) {
24760b57cec5SDimitry Andric __kmp_free(lck->lk.polls.load());
24770b57cec5SDimitry Andric lck->lk.polls = NULL;
24780b57cec5SDimitry Andric }
24790b57cec5SDimitry Andric if (lck->lk.old_polls != NULL) {
24800b57cec5SDimitry Andric __kmp_free(lck->lk.old_polls);
24810b57cec5SDimitry Andric lck->lk.old_polls = NULL;
24820b57cec5SDimitry Andric }
24830b57cec5SDimitry Andric lck->lk.mask = 0;
24840b57cec5SDimitry Andric lck->lk.num_polls = 0;
24850b57cec5SDimitry Andric lck->lk.cleanup_ticket = 0;
24860b57cec5SDimitry Andric lck->lk.next_ticket = 0;
24870b57cec5SDimitry Andric lck->lk.now_serving = 0;
24880b57cec5SDimitry Andric lck->lk.owner_id = 0;
24890b57cec5SDimitry Andric lck->lk.depth_locked = -1;
24900b57cec5SDimitry Andric }
24910b57cec5SDimitry Andric
__kmp_destroy_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck)24920b57cec5SDimitry Andric static void __kmp_destroy_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck) {
24930b57cec5SDimitry Andric char const *const func = "omp_destroy_lock";
24940b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
24950b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
24960b57cec5SDimitry Andric }
24970b57cec5SDimitry Andric if (__kmp_is_drdpa_lock_nestable(lck)) {
24980b57cec5SDimitry Andric KMP_FATAL(LockNestableUsedAsSimple, func);
24990b57cec5SDimitry Andric }
25000b57cec5SDimitry Andric if (__kmp_get_drdpa_lock_owner(lck) != -1) {
25010b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
25020b57cec5SDimitry Andric }
25030b57cec5SDimitry Andric __kmp_destroy_drdpa_lock(lck);
25040b57cec5SDimitry Andric }
25050b57cec5SDimitry Andric
25060b57cec5SDimitry Andric // nested drdpa ticket locks
25070b57cec5SDimitry Andric
__kmp_acquire_nested_drdpa_lock(kmp_drdpa_lock_t * lck,kmp_int32 gtid)25080b57cec5SDimitry Andric int __kmp_acquire_nested_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid) {
25090b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
25100b57cec5SDimitry Andric
25110b57cec5SDimitry Andric if (__kmp_get_drdpa_lock_owner(lck) == gtid) {
25120b57cec5SDimitry Andric lck->lk.depth_locked += 1;
25130b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_NEXT;
25140b57cec5SDimitry Andric } else {
25150b57cec5SDimitry Andric __kmp_acquire_drdpa_lock_timed_template(lck, gtid);
25160b57cec5SDimitry Andric KMP_MB();
25170b57cec5SDimitry Andric lck->lk.depth_locked = 1;
25180b57cec5SDimitry Andric KMP_MB();
25190b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
25200b57cec5SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
25210b57cec5SDimitry Andric }
25220b57cec5SDimitry Andric }
25230b57cec5SDimitry Andric
__kmp_acquire_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck,kmp_int32 gtid)25240b57cec5SDimitry Andric static void __kmp_acquire_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck,
25250b57cec5SDimitry Andric kmp_int32 gtid) {
25260b57cec5SDimitry Andric char const *const func = "omp_set_nest_lock";
25270b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
25280b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
25290b57cec5SDimitry Andric }
25300b57cec5SDimitry Andric if (!__kmp_is_drdpa_lock_nestable(lck)) {
25310b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
25320b57cec5SDimitry Andric }
25330b57cec5SDimitry Andric __kmp_acquire_nested_drdpa_lock(lck, gtid);
25340b57cec5SDimitry Andric }
25350b57cec5SDimitry Andric
__kmp_test_nested_drdpa_lock(kmp_drdpa_lock_t * lck,kmp_int32 gtid)25360b57cec5SDimitry Andric int __kmp_test_nested_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid) {
25370b57cec5SDimitry Andric int retval;
25380b57cec5SDimitry Andric
25390b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
25400b57cec5SDimitry Andric
25410b57cec5SDimitry Andric if (__kmp_get_drdpa_lock_owner(lck) == gtid) {
25420b57cec5SDimitry Andric retval = ++lck->lk.depth_locked;
25430b57cec5SDimitry Andric } else if (!__kmp_test_drdpa_lock(lck, gtid)) {
25440b57cec5SDimitry Andric retval = 0;
25450b57cec5SDimitry Andric } else {
25460b57cec5SDimitry Andric KMP_MB();
25470b57cec5SDimitry Andric retval = lck->lk.depth_locked = 1;
25480b57cec5SDimitry Andric KMP_MB();
25490b57cec5SDimitry Andric lck->lk.owner_id = gtid + 1;
25500b57cec5SDimitry Andric }
25510b57cec5SDimitry Andric return retval;
25520b57cec5SDimitry Andric }
25530b57cec5SDimitry Andric
__kmp_test_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck,kmp_int32 gtid)25540b57cec5SDimitry Andric static int __kmp_test_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck,
25550b57cec5SDimitry Andric kmp_int32 gtid) {
25560b57cec5SDimitry Andric char const *const func = "omp_test_nest_lock";
25570b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
25580b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
25590b57cec5SDimitry Andric }
25600b57cec5SDimitry Andric if (!__kmp_is_drdpa_lock_nestable(lck)) {
25610b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
25620b57cec5SDimitry Andric }
25630b57cec5SDimitry Andric return __kmp_test_nested_drdpa_lock(lck, gtid);
25640b57cec5SDimitry Andric }
25650b57cec5SDimitry Andric
__kmp_release_nested_drdpa_lock(kmp_drdpa_lock_t * lck,kmp_int32 gtid)25660b57cec5SDimitry Andric int __kmp_release_nested_drdpa_lock(kmp_drdpa_lock_t *lck, kmp_int32 gtid) {
25670b57cec5SDimitry Andric KMP_DEBUG_ASSERT(gtid >= 0);
25680b57cec5SDimitry Andric
25690b57cec5SDimitry Andric KMP_MB();
25700b57cec5SDimitry Andric if (--(lck->lk.depth_locked) == 0) {
25710b57cec5SDimitry Andric KMP_MB();
25720b57cec5SDimitry Andric lck->lk.owner_id = 0;
25730b57cec5SDimitry Andric __kmp_release_drdpa_lock(lck, gtid);
25740b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
25750b57cec5SDimitry Andric }
25760b57cec5SDimitry Andric return KMP_LOCK_STILL_HELD;
25770b57cec5SDimitry Andric }
25780b57cec5SDimitry Andric
__kmp_release_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck,kmp_int32 gtid)25790b57cec5SDimitry Andric static int __kmp_release_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck,
25800b57cec5SDimitry Andric kmp_int32 gtid) {
25810b57cec5SDimitry Andric char const *const func = "omp_unset_nest_lock";
25820b57cec5SDimitry Andric KMP_MB(); /* in case another processor initialized lock */
25830b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
25840b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
25850b57cec5SDimitry Andric }
25860b57cec5SDimitry Andric if (!__kmp_is_drdpa_lock_nestable(lck)) {
25870b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
25880b57cec5SDimitry Andric }
25890b57cec5SDimitry Andric if (__kmp_get_drdpa_lock_owner(lck) == -1) {
25900b57cec5SDimitry Andric KMP_FATAL(LockUnsettingFree, func);
25910b57cec5SDimitry Andric }
25920b57cec5SDimitry Andric if (__kmp_get_drdpa_lock_owner(lck) != gtid) {
25930b57cec5SDimitry Andric KMP_FATAL(LockUnsettingSetByAnother, func);
25940b57cec5SDimitry Andric }
25950b57cec5SDimitry Andric return __kmp_release_nested_drdpa_lock(lck, gtid);
25960b57cec5SDimitry Andric }
25970b57cec5SDimitry Andric
__kmp_init_nested_drdpa_lock(kmp_drdpa_lock_t * lck)25980b57cec5SDimitry Andric void __kmp_init_nested_drdpa_lock(kmp_drdpa_lock_t *lck) {
25990b57cec5SDimitry Andric __kmp_init_drdpa_lock(lck);
26000b57cec5SDimitry Andric lck->lk.depth_locked = 0; // >= 0 for nestable locks, -1 for simple locks
26010b57cec5SDimitry Andric }
26020b57cec5SDimitry Andric
__kmp_destroy_nested_drdpa_lock(kmp_drdpa_lock_t * lck)26030b57cec5SDimitry Andric void __kmp_destroy_nested_drdpa_lock(kmp_drdpa_lock_t *lck) {
26040b57cec5SDimitry Andric __kmp_destroy_drdpa_lock(lck);
26050b57cec5SDimitry Andric lck->lk.depth_locked = 0;
26060b57cec5SDimitry Andric }
26070b57cec5SDimitry Andric
__kmp_destroy_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck)26080b57cec5SDimitry Andric static void __kmp_destroy_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck) {
26090b57cec5SDimitry Andric char const *const func = "omp_destroy_nest_lock";
26100b57cec5SDimitry Andric if (lck->lk.initialized != lck) {
26110b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
26120b57cec5SDimitry Andric }
26130b57cec5SDimitry Andric if (!__kmp_is_drdpa_lock_nestable(lck)) {
26140b57cec5SDimitry Andric KMP_FATAL(LockSimpleUsedAsNestable, func);
26150b57cec5SDimitry Andric }
26160b57cec5SDimitry Andric if (__kmp_get_drdpa_lock_owner(lck) != -1) {
26170b57cec5SDimitry Andric KMP_FATAL(LockStillOwned, func);
26180b57cec5SDimitry Andric }
26190b57cec5SDimitry Andric __kmp_destroy_nested_drdpa_lock(lck);
26200b57cec5SDimitry Andric }
26210b57cec5SDimitry Andric
26220b57cec5SDimitry Andric // access functions to fields which don't exist for all lock kinds.
26230b57cec5SDimitry Andric
__kmp_get_drdpa_lock_location(kmp_drdpa_lock_t * lck)26240b57cec5SDimitry Andric static const ident_t *__kmp_get_drdpa_lock_location(kmp_drdpa_lock_t *lck) {
26250b57cec5SDimitry Andric return lck->lk.location;
26260b57cec5SDimitry Andric }
26270b57cec5SDimitry Andric
__kmp_set_drdpa_lock_location(kmp_drdpa_lock_t * lck,const ident_t * loc)26280b57cec5SDimitry Andric static void __kmp_set_drdpa_lock_location(kmp_drdpa_lock_t *lck,
26290b57cec5SDimitry Andric const ident_t *loc) {
26300b57cec5SDimitry Andric lck->lk.location = loc;
26310b57cec5SDimitry Andric }
26320b57cec5SDimitry Andric
__kmp_get_drdpa_lock_flags(kmp_drdpa_lock_t * lck)26330b57cec5SDimitry Andric static kmp_lock_flags_t __kmp_get_drdpa_lock_flags(kmp_drdpa_lock_t *lck) {
26340b57cec5SDimitry Andric return lck->lk.flags;
26350b57cec5SDimitry Andric }
26360b57cec5SDimitry Andric
__kmp_set_drdpa_lock_flags(kmp_drdpa_lock_t * lck,kmp_lock_flags_t flags)26370b57cec5SDimitry Andric static void __kmp_set_drdpa_lock_flags(kmp_drdpa_lock_t *lck,
26380b57cec5SDimitry Andric kmp_lock_flags_t flags) {
26390b57cec5SDimitry Andric lck->lk.flags = flags;
26400b57cec5SDimitry Andric }
26410b57cec5SDimitry Andric
26420b57cec5SDimitry Andric // Time stamp counter
26430b57cec5SDimitry Andric #if KMP_ARCH_X86 || KMP_ARCH_X86_64
26440b57cec5SDimitry Andric #define __kmp_tsc() __kmp_hardware_timestamp()
26450b57cec5SDimitry Andric // Runtime's default backoff parameters
26460b57cec5SDimitry Andric kmp_backoff_t __kmp_spin_backoff_params = {1, 4096, 100};
26470b57cec5SDimitry Andric #else
26480b57cec5SDimitry Andric // Use nanoseconds for other platforms
26490b57cec5SDimitry Andric extern kmp_uint64 __kmp_now_nsec();
26500b57cec5SDimitry Andric kmp_backoff_t __kmp_spin_backoff_params = {1, 256, 100};
26510b57cec5SDimitry Andric #define __kmp_tsc() __kmp_now_nsec()
26520b57cec5SDimitry Andric #endif
26530b57cec5SDimitry Andric
26540b57cec5SDimitry Andric // A useful predicate for dealing with timestamps that may wrap.
26550b57cec5SDimitry Andric // Is a before b? Since the timestamps may wrap, this is asking whether it's
26560b57cec5SDimitry Andric // shorter to go clockwise from a to b around the clock-face, or anti-clockwise.
26570b57cec5SDimitry Andric // Times where going clockwise is less distance than going anti-clockwise
26580b57cec5SDimitry Andric // are in the future, others are in the past. e.g. a = MAX-1, b = MAX+1 (=0),
26590b57cec5SDimitry Andric // then a > b (true) does not mean a reached b; whereas signed(a) = -2,
26600b57cec5SDimitry Andric // signed(b) = 0 captures the actual difference
before(kmp_uint64 a,kmp_uint64 b)26610b57cec5SDimitry Andric static inline bool before(kmp_uint64 a, kmp_uint64 b) {
26620b57cec5SDimitry Andric return ((kmp_int64)b - (kmp_int64)a) > 0;
26630b57cec5SDimitry Andric }
26640b57cec5SDimitry Andric
26650b57cec5SDimitry Andric // Truncated binary exponential backoff function
__kmp_spin_backoff(kmp_backoff_t * boff)26660b57cec5SDimitry Andric void __kmp_spin_backoff(kmp_backoff_t *boff) {
26670b57cec5SDimitry Andric // We could flatten this loop, but making it a nested loop gives better result
26680b57cec5SDimitry Andric kmp_uint32 i;
26690b57cec5SDimitry Andric for (i = boff->step; i > 0; i--) {
26700b57cec5SDimitry Andric kmp_uint64 goal = __kmp_tsc() + boff->min_tick;
267104eeddc0SDimitry Andric #if KMP_HAVE_UMWAIT
267204eeddc0SDimitry Andric if (__kmp_umwait_enabled) {
267304eeddc0SDimitry Andric __kmp_tpause(0, boff->min_tick);
267404eeddc0SDimitry Andric } else {
267504eeddc0SDimitry Andric #endif
26760b57cec5SDimitry Andric do {
26770b57cec5SDimitry Andric KMP_CPU_PAUSE();
26780b57cec5SDimitry Andric } while (before(__kmp_tsc(), goal));
267904eeddc0SDimitry Andric #if KMP_HAVE_UMWAIT
268004eeddc0SDimitry Andric }
268104eeddc0SDimitry Andric #endif
26820b57cec5SDimitry Andric }
26830b57cec5SDimitry Andric boff->step = (boff->step << 1 | 1) & (boff->max_backoff - 1);
26840b57cec5SDimitry Andric }
26850b57cec5SDimitry Andric
26860b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
26870b57cec5SDimitry Andric
26880b57cec5SDimitry Andric // Direct lock initializers. It simply writes a tag to the low 8 bits of the
26890b57cec5SDimitry Andric // lock word.
__kmp_init_direct_lock(kmp_dyna_lock_t * lck,kmp_dyna_lockseq_t seq)26900b57cec5SDimitry Andric static void __kmp_init_direct_lock(kmp_dyna_lock_t *lck,
26910b57cec5SDimitry Andric kmp_dyna_lockseq_t seq) {
2692*74626c16SDimitry Andric TCW_4(((kmp_base_tas_lock_t *)lck)->poll, KMP_GET_D_TAG(seq));
26930b57cec5SDimitry Andric KA_TRACE(
26940b57cec5SDimitry Andric 20,
26950b57cec5SDimitry Andric ("__kmp_init_direct_lock: initialized direct lock with type#%d\n", seq));
26960b57cec5SDimitry Andric }
26970b57cec5SDimitry Andric
26980b57cec5SDimitry Andric #if KMP_USE_TSX
26990b57cec5SDimitry Andric
27000b57cec5SDimitry Andric // HLE lock functions - imported from the testbed runtime.
27010b57cec5SDimitry Andric #define HLE_ACQUIRE ".byte 0xf2;"
27020b57cec5SDimitry Andric #define HLE_RELEASE ".byte 0xf3;"
27030b57cec5SDimitry Andric
swap4(kmp_uint32 volatile * p,kmp_uint32 v)27040b57cec5SDimitry Andric static inline kmp_uint32 swap4(kmp_uint32 volatile *p, kmp_uint32 v) {
27050b57cec5SDimitry Andric __asm__ volatile(HLE_ACQUIRE "xchg %1,%0" : "+r"(v), "+m"(*p) : : "memory");
27060b57cec5SDimitry Andric return v;
27070b57cec5SDimitry Andric }
27080b57cec5SDimitry Andric
__kmp_destroy_hle_lock(kmp_dyna_lock_t * lck)27090b57cec5SDimitry Andric static void __kmp_destroy_hle_lock(kmp_dyna_lock_t *lck) { TCW_4(*lck, 0); }
27100b57cec5SDimitry Andric
__kmp_destroy_hle_lock_with_checks(kmp_dyna_lock_t * lck)27110b57cec5SDimitry Andric static void __kmp_destroy_hle_lock_with_checks(kmp_dyna_lock_t *lck) {
27120b57cec5SDimitry Andric TCW_4(*lck, 0);
27130b57cec5SDimitry Andric }
27140b57cec5SDimitry Andric
__kmp_acquire_hle_lock(kmp_dyna_lock_t * lck,kmp_int32 gtid)27150b57cec5SDimitry Andric static void __kmp_acquire_hle_lock(kmp_dyna_lock_t *lck, kmp_int32 gtid) {
27160b57cec5SDimitry Andric // Use gtid for KMP_LOCK_BUSY if necessary
27170b57cec5SDimitry Andric if (swap4(lck, KMP_LOCK_BUSY(1, hle)) != KMP_LOCK_FREE(hle)) {
27180b57cec5SDimitry Andric int delay = 1;
27190b57cec5SDimitry Andric do {
27200b57cec5SDimitry Andric while (*(kmp_uint32 volatile *)lck != KMP_LOCK_FREE(hle)) {
27210b57cec5SDimitry Andric for (int i = delay; i != 0; --i)
27220b57cec5SDimitry Andric KMP_CPU_PAUSE();
27230b57cec5SDimitry Andric delay = ((delay << 1) | 1) & 7;
27240b57cec5SDimitry Andric }
27250b57cec5SDimitry Andric } while (swap4(lck, KMP_LOCK_BUSY(1, hle)) != KMP_LOCK_FREE(hle));
27260b57cec5SDimitry Andric }
27270b57cec5SDimitry Andric }
27280b57cec5SDimitry Andric
__kmp_acquire_hle_lock_with_checks(kmp_dyna_lock_t * lck,kmp_int32 gtid)27290b57cec5SDimitry Andric static void __kmp_acquire_hle_lock_with_checks(kmp_dyna_lock_t *lck,
27300b57cec5SDimitry Andric kmp_int32 gtid) {
27310b57cec5SDimitry Andric __kmp_acquire_hle_lock(lck, gtid); // TODO: add checks
27320b57cec5SDimitry Andric }
27330b57cec5SDimitry Andric
__kmp_release_hle_lock(kmp_dyna_lock_t * lck,kmp_int32 gtid)27340b57cec5SDimitry Andric static int __kmp_release_hle_lock(kmp_dyna_lock_t *lck, kmp_int32 gtid) {
27350b57cec5SDimitry Andric __asm__ volatile(HLE_RELEASE "movl %1,%0"
27360b57cec5SDimitry Andric : "=m"(*lck)
27370b57cec5SDimitry Andric : "r"(KMP_LOCK_FREE(hle))
27380b57cec5SDimitry Andric : "memory");
27390b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
27400b57cec5SDimitry Andric }
27410b57cec5SDimitry Andric
__kmp_release_hle_lock_with_checks(kmp_dyna_lock_t * lck,kmp_int32 gtid)27420b57cec5SDimitry Andric static int __kmp_release_hle_lock_with_checks(kmp_dyna_lock_t *lck,
27430b57cec5SDimitry Andric kmp_int32 gtid) {
27440b57cec5SDimitry Andric return __kmp_release_hle_lock(lck, gtid); // TODO: add checks
27450b57cec5SDimitry Andric }
27460b57cec5SDimitry Andric
__kmp_test_hle_lock(kmp_dyna_lock_t * lck,kmp_int32 gtid)27470b57cec5SDimitry Andric static int __kmp_test_hle_lock(kmp_dyna_lock_t *lck, kmp_int32 gtid) {
27480b57cec5SDimitry Andric return swap4(lck, KMP_LOCK_BUSY(1, hle)) == KMP_LOCK_FREE(hle);
27490b57cec5SDimitry Andric }
27500b57cec5SDimitry Andric
__kmp_test_hle_lock_with_checks(kmp_dyna_lock_t * lck,kmp_int32 gtid)27510b57cec5SDimitry Andric static int __kmp_test_hle_lock_with_checks(kmp_dyna_lock_t *lck,
27520b57cec5SDimitry Andric kmp_int32 gtid) {
27530b57cec5SDimitry Andric return __kmp_test_hle_lock(lck, gtid); // TODO: add checks
27540b57cec5SDimitry Andric }
27550b57cec5SDimitry Andric
__kmp_init_rtm_queuing_lock(kmp_queuing_lock_t * lck)2756e8d8bef9SDimitry Andric static void __kmp_init_rtm_queuing_lock(kmp_queuing_lock_t *lck) {
27570b57cec5SDimitry Andric __kmp_init_queuing_lock(lck);
27580b57cec5SDimitry Andric }
27590b57cec5SDimitry Andric
__kmp_destroy_rtm_queuing_lock(kmp_queuing_lock_t * lck)2760e8d8bef9SDimitry Andric static void __kmp_destroy_rtm_queuing_lock(kmp_queuing_lock_t *lck) {
27610b57cec5SDimitry Andric __kmp_destroy_queuing_lock(lck);
27620b57cec5SDimitry Andric }
27630b57cec5SDimitry Andric
2764e8d8bef9SDimitry Andric static void
__kmp_destroy_rtm_queuing_lock_with_checks(kmp_queuing_lock_t * lck)2765e8d8bef9SDimitry Andric __kmp_destroy_rtm_queuing_lock_with_checks(kmp_queuing_lock_t *lck) {
27660b57cec5SDimitry Andric __kmp_destroy_queuing_lock_with_checks(lck);
27670b57cec5SDimitry Andric }
27680b57cec5SDimitry Andric
2769e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_acquire_rtm_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)2770e8d8bef9SDimitry Andric static void __kmp_acquire_rtm_queuing_lock(kmp_queuing_lock_t *lck,
2771e8d8bef9SDimitry Andric kmp_int32 gtid) {
27720b57cec5SDimitry Andric unsigned retries = 3, status;
27730b57cec5SDimitry Andric do {
27740b57cec5SDimitry Andric status = _xbegin();
27750b57cec5SDimitry Andric if (status == _XBEGIN_STARTED) {
27760b57cec5SDimitry Andric if (__kmp_is_unlocked_queuing_lock(lck))
27770b57cec5SDimitry Andric return;
27780b57cec5SDimitry Andric _xabort(0xff);
27790b57cec5SDimitry Andric }
27800b57cec5SDimitry Andric if ((status & _XABORT_EXPLICIT) && _XABORT_CODE(status) == 0xff) {
27810b57cec5SDimitry Andric // Wait until lock becomes free
27820b57cec5SDimitry Andric while (!__kmp_is_unlocked_queuing_lock(lck)) {
27830b57cec5SDimitry Andric KMP_YIELD(TRUE);
27840b57cec5SDimitry Andric }
27850b57cec5SDimitry Andric } else if (!(status & _XABORT_RETRY))
27860b57cec5SDimitry Andric break;
27870b57cec5SDimitry Andric } while (retries--);
27880b57cec5SDimitry Andric
27890b57cec5SDimitry Andric // Fall-back non-speculative lock (xchg)
27900b57cec5SDimitry Andric __kmp_acquire_queuing_lock(lck, gtid);
27910b57cec5SDimitry Andric }
27920b57cec5SDimitry Andric
__kmp_acquire_rtm_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)2793e8d8bef9SDimitry Andric static void __kmp_acquire_rtm_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
27940b57cec5SDimitry Andric kmp_int32 gtid) {
2795e8d8bef9SDimitry Andric __kmp_acquire_rtm_queuing_lock(lck, gtid);
27960b57cec5SDimitry Andric }
27970b57cec5SDimitry Andric
2798e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_release_rtm_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)2799e8d8bef9SDimitry Andric static int __kmp_release_rtm_queuing_lock(kmp_queuing_lock_t *lck,
2800e8d8bef9SDimitry Andric kmp_int32 gtid) {
28010b57cec5SDimitry Andric if (__kmp_is_unlocked_queuing_lock(lck)) {
28020b57cec5SDimitry Andric // Releasing from speculation
28030b57cec5SDimitry Andric _xend();
28040b57cec5SDimitry Andric } else {
28050b57cec5SDimitry Andric // Releasing from a real lock
28060b57cec5SDimitry Andric __kmp_release_queuing_lock(lck, gtid);
28070b57cec5SDimitry Andric }
28080b57cec5SDimitry Andric return KMP_LOCK_RELEASED;
28090b57cec5SDimitry Andric }
28100b57cec5SDimitry Andric
__kmp_release_rtm_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)2811e8d8bef9SDimitry Andric static int __kmp_release_rtm_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
28120b57cec5SDimitry Andric kmp_int32 gtid) {
2813e8d8bef9SDimitry Andric return __kmp_release_rtm_queuing_lock(lck, gtid);
28140b57cec5SDimitry Andric }
28150b57cec5SDimitry Andric
2816e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_test_rtm_queuing_lock(kmp_queuing_lock_t * lck,kmp_int32 gtid)2817e8d8bef9SDimitry Andric static int __kmp_test_rtm_queuing_lock(kmp_queuing_lock_t *lck,
2818e8d8bef9SDimitry Andric kmp_int32 gtid) {
28190b57cec5SDimitry Andric unsigned retries = 3, status;
28200b57cec5SDimitry Andric do {
28210b57cec5SDimitry Andric status = _xbegin();
28220b57cec5SDimitry Andric if (status == _XBEGIN_STARTED && __kmp_is_unlocked_queuing_lock(lck)) {
28230b57cec5SDimitry Andric return 1;
28240b57cec5SDimitry Andric }
28250b57cec5SDimitry Andric if (!(status & _XABORT_RETRY))
28260b57cec5SDimitry Andric break;
28270b57cec5SDimitry Andric } while (retries--);
28280b57cec5SDimitry Andric
2829e8d8bef9SDimitry Andric return __kmp_test_queuing_lock(lck, gtid);
28300b57cec5SDimitry Andric }
28310b57cec5SDimitry Andric
__kmp_test_rtm_queuing_lock_with_checks(kmp_queuing_lock_t * lck,kmp_int32 gtid)2832e8d8bef9SDimitry Andric static int __kmp_test_rtm_queuing_lock_with_checks(kmp_queuing_lock_t *lck,
28330b57cec5SDimitry Andric kmp_int32 gtid) {
2834e8d8bef9SDimitry Andric return __kmp_test_rtm_queuing_lock(lck, gtid);
2835e8d8bef9SDimitry Andric }
2836e8d8bef9SDimitry Andric
2837e8d8bef9SDimitry Andric // Reuse kmp_tas_lock_t for TSX lock which use RTM with fall-back spin lock.
2838e8d8bef9SDimitry Andric typedef kmp_tas_lock_t kmp_rtm_spin_lock_t;
2839e8d8bef9SDimitry Andric
__kmp_destroy_rtm_spin_lock(kmp_rtm_spin_lock_t * lck)2840e8d8bef9SDimitry Andric static void __kmp_destroy_rtm_spin_lock(kmp_rtm_spin_lock_t *lck) {
2841e8d8bef9SDimitry Andric KMP_ATOMIC_ST_REL(&lck->lk.poll, 0);
2842e8d8bef9SDimitry Andric }
2843e8d8bef9SDimitry Andric
__kmp_destroy_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t * lck)2844e8d8bef9SDimitry Andric static void __kmp_destroy_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t *lck) {
2845e8d8bef9SDimitry Andric __kmp_destroy_rtm_spin_lock(lck);
2846e8d8bef9SDimitry Andric }
2847e8d8bef9SDimitry Andric
2848e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_acquire_rtm_spin_lock(kmp_rtm_spin_lock_t * lck,kmp_int32 gtid)2849e8d8bef9SDimitry Andric static int __kmp_acquire_rtm_spin_lock(kmp_rtm_spin_lock_t *lck,
2850e8d8bef9SDimitry Andric kmp_int32 gtid) {
2851e8d8bef9SDimitry Andric unsigned retries = 3, status;
2852e8d8bef9SDimitry Andric kmp_int32 lock_free = KMP_LOCK_FREE(rtm_spin);
2853e8d8bef9SDimitry Andric kmp_int32 lock_busy = KMP_LOCK_BUSY(1, rtm_spin);
2854e8d8bef9SDimitry Andric do {
2855e8d8bef9SDimitry Andric status = _xbegin();
2856e8d8bef9SDimitry Andric if (status == _XBEGIN_STARTED) {
2857e8d8bef9SDimitry Andric if (KMP_ATOMIC_LD_RLX(&lck->lk.poll) == lock_free)
2858e8d8bef9SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
2859e8d8bef9SDimitry Andric _xabort(0xff);
2860e8d8bef9SDimitry Andric }
2861e8d8bef9SDimitry Andric if ((status & _XABORT_EXPLICIT) && _XABORT_CODE(status) == 0xff) {
2862e8d8bef9SDimitry Andric // Wait until lock becomes free
2863e8d8bef9SDimitry Andric while (KMP_ATOMIC_LD_RLX(&lck->lk.poll) != lock_free) {
2864e8d8bef9SDimitry Andric KMP_YIELD(TRUE);
2865e8d8bef9SDimitry Andric }
2866e8d8bef9SDimitry Andric } else if (!(status & _XABORT_RETRY))
2867e8d8bef9SDimitry Andric break;
2868e8d8bef9SDimitry Andric } while (retries--);
2869e8d8bef9SDimitry Andric
2870e8d8bef9SDimitry Andric // Fall-back spin lock
2871e8d8bef9SDimitry Andric KMP_FSYNC_PREPARE(lck);
2872e8d8bef9SDimitry Andric kmp_backoff_t backoff = __kmp_spin_backoff_params;
2873e8d8bef9SDimitry Andric while (KMP_ATOMIC_LD_RLX(&lck->lk.poll) != lock_free ||
2874e8d8bef9SDimitry Andric !__kmp_atomic_compare_store_acq(&lck->lk.poll, lock_free, lock_busy)) {
2875e8d8bef9SDimitry Andric __kmp_spin_backoff(&backoff);
2876e8d8bef9SDimitry Andric }
2877e8d8bef9SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
2878e8d8bef9SDimitry Andric return KMP_LOCK_ACQUIRED_FIRST;
2879e8d8bef9SDimitry Andric }
2880e8d8bef9SDimitry Andric
__kmp_acquire_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t * lck,kmp_int32 gtid)2881e8d8bef9SDimitry Andric static int __kmp_acquire_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t *lck,
2882e8d8bef9SDimitry Andric kmp_int32 gtid) {
2883e8d8bef9SDimitry Andric return __kmp_acquire_rtm_spin_lock(lck, gtid);
2884e8d8bef9SDimitry Andric }
2885e8d8bef9SDimitry Andric
2886e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_release_rtm_spin_lock(kmp_rtm_spin_lock_t * lck,kmp_int32 gtid)2887e8d8bef9SDimitry Andric static int __kmp_release_rtm_spin_lock(kmp_rtm_spin_lock_t *lck,
2888e8d8bef9SDimitry Andric kmp_int32 gtid) {
2889e8d8bef9SDimitry Andric if (KMP_ATOMIC_LD_RLX(&lck->lk.poll) == KMP_LOCK_FREE(rtm_spin)) {
2890e8d8bef9SDimitry Andric // Releasing from speculation
2891e8d8bef9SDimitry Andric _xend();
2892e8d8bef9SDimitry Andric } else {
2893e8d8bef9SDimitry Andric // Releasing from a real lock
2894e8d8bef9SDimitry Andric KMP_FSYNC_RELEASING(lck);
2895e8d8bef9SDimitry Andric KMP_ATOMIC_ST_REL(&lck->lk.poll, KMP_LOCK_FREE(rtm_spin));
2896e8d8bef9SDimitry Andric }
2897e8d8bef9SDimitry Andric return KMP_LOCK_RELEASED;
2898e8d8bef9SDimitry Andric }
2899e8d8bef9SDimitry Andric
__kmp_release_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t * lck,kmp_int32 gtid)2900e8d8bef9SDimitry Andric static int __kmp_release_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t *lck,
2901e8d8bef9SDimitry Andric kmp_int32 gtid) {
2902e8d8bef9SDimitry Andric return __kmp_release_rtm_spin_lock(lck, gtid);
2903e8d8bef9SDimitry Andric }
2904e8d8bef9SDimitry Andric
2905e8d8bef9SDimitry Andric KMP_ATTRIBUTE_TARGET_RTM
__kmp_test_rtm_spin_lock(kmp_rtm_spin_lock_t * lck,kmp_int32 gtid)2906e8d8bef9SDimitry Andric static int __kmp_test_rtm_spin_lock(kmp_rtm_spin_lock_t *lck, kmp_int32 gtid) {
2907e8d8bef9SDimitry Andric unsigned retries = 3, status;
2908e8d8bef9SDimitry Andric kmp_int32 lock_free = KMP_LOCK_FREE(rtm_spin);
2909e8d8bef9SDimitry Andric kmp_int32 lock_busy = KMP_LOCK_BUSY(1, rtm_spin);
2910e8d8bef9SDimitry Andric do {
2911e8d8bef9SDimitry Andric status = _xbegin();
2912e8d8bef9SDimitry Andric if (status == _XBEGIN_STARTED &&
2913e8d8bef9SDimitry Andric KMP_ATOMIC_LD_RLX(&lck->lk.poll) == lock_free) {
2914e8d8bef9SDimitry Andric return TRUE;
2915e8d8bef9SDimitry Andric }
2916e8d8bef9SDimitry Andric if (!(status & _XABORT_RETRY))
2917e8d8bef9SDimitry Andric break;
2918e8d8bef9SDimitry Andric } while (retries--);
2919e8d8bef9SDimitry Andric
2920e8d8bef9SDimitry Andric if (KMP_ATOMIC_LD_RLX(&lck->lk.poll) == lock_free &&
2921e8d8bef9SDimitry Andric __kmp_atomic_compare_store_acq(&lck->lk.poll, lock_free, lock_busy)) {
2922e8d8bef9SDimitry Andric KMP_FSYNC_ACQUIRED(lck);
2923e8d8bef9SDimitry Andric return TRUE;
2924e8d8bef9SDimitry Andric }
2925e8d8bef9SDimitry Andric return FALSE;
2926e8d8bef9SDimitry Andric }
2927e8d8bef9SDimitry Andric
__kmp_test_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t * lck,kmp_int32 gtid)2928e8d8bef9SDimitry Andric static int __kmp_test_rtm_spin_lock_with_checks(kmp_rtm_spin_lock_t *lck,
2929e8d8bef9SDimitry Andric kmp_int32 gtid) {
2930e8d8bef9SDimitry Andric return __kmp_test_rtm_spin_lock(lck, gtid);
29310b57cec5SDimitry Andric }
29320b57cec5SDimitry Andric
29330b57cec5SDimitry Andric #endif // KMP_USE_TSX
29340b57cec5SDimitry Andric
29350b57cec5SDimitry Andric // Entry functions for indirect locks (first element of direct lock jump tables)
29360b57cec5SDimitry Andric static void __kmp_init_indirect_lock(kmp_dyna_lock_t *l,
29370b57cec5SDimitry Andric kmp_dyna_lockseq_t tag);
29380b57cec5SDimitry Andric static void __kmp_destroy_indirect_lock(kmp_dyna_lock_t *lock);
29390b57cec5SDimitry Andric static int __kmp_set_indirect_lock(kmp_dyna_lock_t *lock, kmp_int32);
29400b57cec5SDimitry Andric static int __kmp_unset_indirect_lock(kmp_dyna_lock_t *lock, kmp_int32);
29410b57cec5SDimitry Andric static int __kmp_test_indirect_lock(kmp_dyna_lock_t *lock, kmp_int32);
29420b57cec5SDimitry Andric static int __kmp_set_indirect_lock_with_checks(kmp_dyna_lock_t *lock,
29430b57cec5SDimitry Andric kmp_int32);
29440b57cec5SDimitry Andric static int __kmp_unset_indirect_lock_with_checks(kmp_dyna_lock_t *lock,
29450b57cec5SDimitry Andric kmp_int32);
29460b57cec5SDimitry Andric static int __kmp_test_indirect_lock_with_checks(kmp_dyna_lock_t *lock,
29470b57cec5SDimitry Andric kmp_int32);
29480b57cec5SDimitry Andric
29490b57cec5SDimitry Andric // Lock function definitions for the union parameter type
29500b57cec5SDimitry Andric #define KMP_FOREACH_LOCK_KIND(m, a) m(ticket, a) m(queuing, a) m(drdpa, a)
29510b57cec5SDimitry Andric
29520b57cec5SDimitry Andric #define expand1(lk, op) \
29530b57cec5SDimitry Andric static void __kmp_##op##_##lk##_##lock(kmp_user_lock_p lock) { \
29540b57cec5SDimitry Andric __kmp_##op##_##lk##_##lock(&lock->lk); \
29550b57cec5SDimitry Andric }
29560b57cec5SDimitry Andric #define expand2(lk, op) \
29570b57cec5SDimitry Andric static int __kmp_##op##_##lk##_##lock(kmp_user_lock_p lock, \
29580b57cec5SDimitry Andric kmp_int32 gtid) { \
29590b57cec5SDimitry Andric return __kmp_##op##_##lk##_##lock(&lock->lk, gtid); \
29600b57cec5SDimitry Andric }
29610b57cec5SDimitry Andric #define expand3(lk, op) \
29620b57cec5SDimitry Andric static void __kmp_set_##lk##_##lock_flags(kmp_user_lock_p lock, \
29630b57cec5SDimitry Andric kmp_lock_flags_t flags) { \
29640b57cec5SDimitry Andric __kmp_set_##lk##_lock_flags(&lock->lk, flags); \
29650b57cec5SDimitry Andric }
29660b57cec5SDimitry Andric #define expand4(lk, op) \
29670b57cec5SDimitry Andric static void __kmp_set_##lk##_##lock_location(kmp_user_lock_p lock, \
29680b57cec5SDimitry Andric const ident_t *loc) { \
29690b57cec5SDimitry Andric __kmp_set_##lk##_lock_location(&lock->lk, loc); \
29700b57cec5SDimitry Andric }
29710b57cec5SDimitry Andric
29720b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand1, init)
29730b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand1, init_nested)
29740b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand1, destroy)
29750b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand1, destroy_nested)
29760b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand2, acquire)
29770b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand2, acquire_nested)
29780b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand2, release)
29790b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand2, release_nested)
29800b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand2, test)
29810b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand2, test_nested)
29820b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand3, )
29830b57cec5SDimitry Andric KMP_FOREACH_LOCK_KIND(expand4, )
29840b57cec5SDimitry Andric
29850b57cec5SDimitry Andric #undef expand1
29860b57cec5SDimitry Andric #undef expand2
29870b57cec5SDimitry Andric #undef expand3
29880b57cec5SDimitry Andric #undef expand4
29890b57cec5SDimitry Andric
29900b57cec5SDimitry Andric // Jump tables for the indirect lock functions
29910b57cec5SDimitry Andric // Only fill in the odd entries, that avoids the need to shift out the low bit
29920b57cec5SDimitry Andric
29930b57cec5SDimitry Andric // init functions
29940b57cec5SDimitry Andric #define expand(l, op) 0, __kmp_init_direct_lock,
29950b57cec5SDimitry Andric void (*__kmp_direct_init[])(kmp_dyna_lock_t *, kmp_dyna_lockseq_t) = {
29960b57cec5SDimitry Andric __kmp_init_indirect_lock, 0, KMP_FOREACH_D_LOCK(expand, init)};
29970b57cec5SDimitry Andric #undef expand
29980b57cec5SDimitry Andric
29990b57cec5SDimitry Andric // destroy functions
30000b57cec5SDimitry Andric #define expand(l, op) 0, (void (*)(kmp_dyna_lock_t *))__kmp_##op##_##l##_lock,
30010b57cec5SDimitry Andric static void (*direct_destroy[])(kmp_dyna_lock_t *) = {
30020b57cec5SDimitry Andric __kmp_destroy_indirect_lock, 0, KMP_FOREACH_D_LOCK(expand, destroy)};
30030b57cec5SDimitry Andric #undef expand
30040b57cec5SDimitry Andric #define expand(l, op) \
30050b57cec5SDimitry Andric 0, (void (*)(kmp_dyna_lock_t *))__kmp_destroy_##l##_lock_with_checks,
30060b57cec5SDimitry Andric static void (*direct_destroy_check[])(kmp_dyna_lock_t *) = {
30070b57cec5SDimitry Andric __kmp_destroy_indirect_lock, 0, KMP_FOREACH_D_LOCK(expand, destroy)};
30080b57cec5SDimitry Andric #undef expand
30090b57cec5SDimitry Andric
30100b57cec5SDimitry Andric // set/acquire functions
30110b57cec5SDimitry Andric #define expand(l, op) \
30120b57cec5SDimitry Andric 0, (int (*)(kmp_dyna_lock_t *, kmp_int32))__kmp_##op##_##l##_lock,
30130b57cec5SDimitry Andric static int (*direct_set[])(kmp_dyna_lock_t *, kmp_int32) = {
30140b57cec5SDimitry Andric __kmp_set_indirect_lock, 0, KMP_FOREACH_D_LOCK(expand, acquire)};
30150b57cec5SDimitry Andric #undef expand
30160b57cec5SDimitry Andric #define expand(l, op) \
30170b57cec5SDimitry Andric 0, (int (*)(kmp_dyna_lock_t *, kmp_int32))__kmp_##op##_##l##_lock_with_checks,
30180b57cec5SDimitry Andric static int (*direct_set_check[])(kmp_dyna_lock_t *, kmp_int32) = {
30190b57cec5SDimitry Andric __kmp_set_indirect_lock_with_checks, 0,
30200b57cec5SDimitry Andric KMP_FOREACH_D_LOCK(expand, acquire)};
30210b57cec5SDimitry Andric #undef expand
30220b57cec5SDimitry Andric
30230b57cec5SDimitry Andric // unset/release and test functions
30240b57cec5SDimitry Andric #define expand(l, op) \
30250b57cec5SDimitry Andric 0, (int (*)(kmp_dyna_lock_t *, kmp_int32))__kmp_##op##_##l##_lock,
30260b57cec5SDimitry Andric static int (*direct_unset[])(kmp_dyna_lock_t *, kmp_int32) = {
30270b57cec5SDimitry Andric __kmp_unset_indirect_lock, 0, KMP_FOREACH_D_LOCK(expand, release)};
30280b57cec5SDimitry Andric static int (*direct_test[])(kmp_dyna_lock_t *, kmp_int32) = {
30290b57cec5SDimitry Andric __kmp_test_indirect_lock, 0, KMP_FOREACH_D_LOCK(expand, test)};
30300b57cec5SDimitry Andric #undef expand
30310b57cec5SDimitry Andric #define expand(l, op) \
30320b57cec5SDimitry Andric 0, (int (*)(kmp_dyna_lock_t *, kmp_int32))__kmp_##op##_##l##_lock_with_checks,
30330b57cec5SDimitry Andric static int (*direct_unset_check[])(kmp_dyna_lock_t *, kmp_int32) = {
30340b57cec5SDimitry Andric __kmp_unset_indirect_lock_with_checks, 0,
30350b57cec5SDimitry Andric KMP_FOREACH_D_LOCK(expand, release)};
30360b57cec5SDimitry Andric static int (*direct_test_check[])(kmp_dyna_lock_t *, kmp_int32) = {
30370b57cec5SDimitry Andric __kmp_test_indirect_lock_with_checks, 0, KMP_FOREACH_D_LOCK(expand, test)};
30380b57cec5SDimitry Andric #undef expand
30390b57cec5SDimitry Andric
30400b57cec5SDimitry Andric // Exposes only one set of jump tables (*lock or *lock_with_checks).
3041489b1cf2SDimitry Andric void (**__kmp_direct_destroy)(kmp_dyna_lock_t *) = 0;
3042489b1cf2SDimitry Andric int (**__kmp_direct_set)(kmp_dyna_lock_t *, kmp_int32) = 0;
3043489b1cf2SDimitry Andric int (**__kmp_direct_unset)(kmp_dyna_lock_t *, kmp_int32) = 0;
3044489b1cf2SDimitry Andric int (**__kmp_direct_test)(kmp_dyna_lock_t *, kmp_int32) = 0;
30450b57cec5SDimitry Andric
30460b57cec5SDimitry Andric // Jump tables for the indirect lock functions
30470b57cec5SDimitry Andric #define expand(l, op) (void (*)(kmp_user_lock_p)) __kmp_##op##_##l##_##lock,
30480b57cec5SDimitry Andric void (*__kmp_indirect_init[])(kmp_user_lock_p) = {
30490b57cec5SDimitry Andric KMP_FOREACH_I_LOCK(expand, init)};
30500b57cec5SDimitry Andric #undef expand
30510b57cec5SDimitry Andric
30520b57cec5SDimitry Andric #define expand(l, op) (void (*)(kmp_user_lock_p)) __kmp_##op##_##l##_##lock,
30530b57cec5SDimitry Andric static void (*indirect_destroy[])(kmp_user_lock_p) = {
30540b57cec5SDimitry Andric KMP_FOREACH_I_LOCK(expand, destroy)};
30550b57cec5SDimitry Andric #undef expand
30560b57cec5SDimitry Andric #define expand(l, op) \
30570b57cec5SDimitry Andric (void (*)(kmp_user_lock_p)) __kmp_##op##_##l##_##lock_with_checks,
30580b57cec5SDimitry Andric static void (*indirect_destroy_check[])(kmp_user_lock_p) = {
30590b57cec5SDimitry Andric KMP_FOREACH_I_LOCK(expand, destroy)};
30600b57cec5SDimitry Andric #undef expand
30610b57cec5SDimitry Andric
30620b57cec5SDimitry Andric // set/acquire functions
30630b57cec5SDimitry Andric #define expand(l, op) \
30640b57cec5SDimitry Andric (int (*)(kmp_user_lock_p, kmp_int32)) __kmp_##op##_##l##_##lock,
30650b57cec5SDimitry Andric static int (*indirect_set[])(kmp_user_lock_p,
30660b57cec5SDimitry Andric kmp_int32) = {KMP_FOREACH_I_LOCK(expand, acquire)};
30670b57cec5SDimitry Andric #undef expand
30680b57cec5SDimitry Andric #define expand(l, op) \
30690b57cec5SDimitry Andric (int (*)(kmp_user_lock_p, kmp_int32)) __kmp_##op##_##l##_##lock_with_checks,
30700b57cec5SDimitry Andric static int (*indirect_set_check[])(kmp_user_lock_p, kmp_int32) = {
30710b57cec5SDimitry Andric KMP_FOREACH_I_LOCK(expand, acquire)};
30720b57cec5SDimitry Andric #undef expand
30730b57cec5SDimitry Andric
30740b57cec5SDimitry Andric // unset/release and test functions
30750b57cec5SDimitry Andric #define expand(l, op) \
30760b57cec5SDimitry Andric (int (*)(kmp_user_lock_p, kmp_int32)) __kmp_##op##_##l##_##lock,
30770b57cec5SDimitry Andric static int (*indirect_unset[])(kmp_user_lock_p, kmp_int32) = {
30780b57cec5SDimitry Andric KMP_FOREACH_I_LOCK(expand, release)};
30790b57cec5SDimitry Andric static int (*indirect_test[])(kmp_user_lock_p,
30800b57cec5SDimitry Andric kmp_int32) = {KMP_FOREACH_I_LOCK(expand, test)};
30810b57cec5SDimitry Andric #undef expand
30820b57cec5SDimitry Andric #define expand(l, op) \
30830b57cec5SDimitry Andric (int (*)(kmp_user_lock_p, kmp_int32)) __kmp_##op##_##l##_##lock_with_checks,
30840b57cec5SDimitry Andric static int (*indirect_unset_check[])(kmp_user_lock_p, kmp_int32) = {
30850b57cec5SDimitry Andric KMP_FOREACH_I_LOCK(expand, release)};
30860b57cec5SDimitry Andric static int (*indirect_test_check[])(kmp_user_lock_p, kmp_int32) = {
30870b57cec5SDimitry Andric KMP_FOREACH_I_LOCK(expand, test)};
30880b57cec5SDimitry Andric #undef expand
30890b57cec5SDimitry Andric
30900b57cec5SDimitry Andric // Exposes only one jump tables (*lock or *lock_with_checks).
3091489b1cf2SDimitry Andric void (**__kmp_indirect_destroy)(kmp_user_lock_p) = 0;
3092489b1cf2SDimitry Andric int (**__kmp_indirect_set)(kmp_user_lock_p, kmp_int32) = 0;
3093489b1cf2SDimitry Andric int (**__kmp_indirect_unset)(kmp_user_lock_p, kmp_int32) = 0;
3094489b1cf2SDimitry Andric int (**__kmp_indirect_test)(kmp_user_lock_p, kmp_int32) = 0;
30950b57cec5SDimitry Andric
30960b57cec5SDimitry Andric // Lock index table.
30970b57cec5SDimitry Andric kmp_indirect_lock_table_t __kmp_i_lock_table;
30980b57cec5SDimitry Andric
30990b57cec5SDimitry Andric // Size of indirect locks.
31000b57cec5SDimitry Andric static kmp_uint32 __kmp_indirect_lock_size[KMP_NUM_I_LOCKS] = {0};
31010b57cec5SDimitry Andric
31020b57cec5SDimitry Andric // Jump tables for lock accessor/modifier.
31030b57cec5SDimitry Andric void (*__kmp_indirect_set_location[KMP_NUM_I_LOCKS])(kmp_user_lock_p,
31040b57cec5SDimitry Andric const ident_t *) = {0};
31050b57cec5SDimitry Andric void (*__kmp_indirect_set_flags[KMP_NUM_I_LOCKS])(kmp_user_lock_p,
31060b57cec5SDimitry Andric kmp_lock_flags_t) = {0};
31070b57cec5SDimitry Andric const ident_t *(*__kmp_indirect_get_location[KMP_NUM_I_LOCKS])(
31080b57cec5SDimitry Andric kmp_user_lock_p) = {0};
31090b57cec5SDimitry Andric kmp_lock_flags_t (*__kmp_indirect_get_flags[KMP_NUM_I_LOCKS])(
31100b57cec5SDimitry Andric kmp_user_lock_p) = {0};
31110b57cec5SDimitry Andric
31120b57cec5SDimitry Andric // Use different lock pools for different lock types.
31130b57cec5SDimitry Andric static kmp_indirect_lock_t *__kmp_indirect_lock_pool[KMP_NUM_I_LOCKS] = {0};
31140b57cec5SDimitry Andric
31150b57cec5SDimitry Andric // User lock allocator for dynamically dispatched indirect locks. Every entry of
31165ffd83dbSDimitry Andric // the indirect lock table holds the address and type of the allocated indirect
31170b57cec5SDimitry Andric // lock (kmp_indirect_lock_t), and the size of the table doubles when it is
31180b57cec5SDimitry Andric // full. A destroyed indirect lock object is returned to the reusable pool of
31190b57cec5SDimitry Andric // locks, unique to each lock type.
__kmp_allocate_indirect_lock(void ** user_lock,kmp_int32 gtid,kmp_indirect_locktag_t tag)31200b57cec5SDimitry Andric kmp_indirect_lock_t *__kmp_allocate_indirect_lock(void **user_lock,
31210b57cec5SDimitry Andric kmp_int32 gtid,
31220b57cec5SDimitry Andric kmp_indirect_locktag_t tag) {
31230b57cec5SDimitry Andric kmp_indirect_lock_t *lck;
3124349cc55cSDimitry Andric kmp_lock_index_t idx, table_idx;
31250b57cec5SDimitry Andric
31260b57cec5SDimitry Andric __kmp_acquire_lock(&__kmp_global_lock, gtid);
31270b57cec5SDimitry Andric
31280b57cec5SDimitry Andric if (__kmp_indirect_lock_pool[tag] != NULL) {
31290b57cec5SDimitry Andric // Reuse the allocated and destroyed lock object
31300b57cec5SDimitry Andric lck = __kmp_indirect_lock_pool[tag];
31310b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *))
31320b57cec5SDimitry Andric idx = lck->lock->pool.index;
31330b57cec5SDimitry Andric __kmp_indirect_lock_pool[tag] = (kmp_indirect_lock_t *)lck->lock->pool.next;
31340b57cec5SDimitry Andric KA_TRACE(20, ("__kmp_allocate_indirect_lock: reusing an existing lock %p\n",
31350b57cec5SDimitry Andric lck));
31360b57cec5SDimitry Andric } else {
3137349cc55cSDimitry Andric kmp_uint32 row, col;
3138349cc55cSDimitry Andric kmp_indirect_lock_table_t *lock_table = &__kmp_i_lock_table;
3139349cc55cSDimitry Andric idx = 0;
3140349cc55cSDimitry Andric // Find location in list of lock tables to put new lock
3141349cc55cSDimitry Andric while (1) {
3142349cc55cSDimitry Andric table_idx = lock_table->next; // index within this table
3143349cc55cSDimitry Andric idx += lock_table->next; // global index within list of tables
3144349cc55cSDimitry Andric if (table_idx < lock_table->nrow_ptrs * KMP_I_LOCK_CHUNK) {
3145349cc55cSDimitry Andric row = table_idx / KMP_I_LOCK_CHUNK;
3146349cc55cSDimitry Andric col = table_idx % KMP_I_LOCK_CHUNK;
3147349cc55cSDimitry Andric // Allocate a new row of locks if necessary
3148349cc55cSDimitry Andric if (!lock_table->table[row]) {
3149349cc55cSDimitry Andric lock_table->table[row] = (kmp_indirect_lock_t *)__kmp_allocate(
3150349cc55cSDimitry Andric sizeof(kmp_indirect_lock_t) * KMP_I_LOCK_CHUNK);
31510b57cec5SDimitry Andric }
3152349cc55cSDimitry Andric break;
3153349cc55cSDimitry Andric }
3154349cc55cSDimitry Andric // Allocate a new lock table if necessary with double the capacity
3155349cc55cSDimitry Andric if (!lock_table->next_table) {
3156349cc55cSDimitry Andric kmp_indirect_lock_table_t *next_table =
3157349cc55cSDimitry Andric (kmp_indirect_lock_table_t *)__kmp_allocate(
3158349cc55cSDimitry Andric sizeof(kmp_indirect_lock_table_t));
3159349cc55cSDimitry Andric next_table->table = (kmp_indirect_lock_t **)__kmp_allocate(
3160349cc55cSDimitry Andric sizeof(kmp_indirect_lock_t *) * 2 * lock_table->nrow_ptrs);
3161349cc55cSDimitry Andric next_table->nrow_ptrs = 2 * lock_table->nrow_ptrs;
3162349cc55cSDimitry Andric next_table->next = 0;
3163349cc55cSDimitry Andric next_table->next_table = nullptr;
3164349cc55cSDimitry Andric lock_table->next_table = next_table;
3165349cc55cSDimitry Andric }
3166349cc55cSDimitry Andric lock_table = lock_table->next_table;
3167349cc55cSDimitry Andric KMP_ASSERT(lock_table);
3168349cc55cSDimitry Andric }
3169349cc55cSDimitry Andric lock_table->next++;
3170349cc55cSDimitry Andric
3171349cc55cSDimitry Andric lck = &lock_table->table[row][col];
31720b57cec5SDimitry Andric // Allocate a new base lock object
31730b57cec5SDimitry Andric lck->lock = (kmp_user_lock_p)__kmp_allocate(__kmp_indirect_lock_size[tag]);
31740b57cec5SDimitry Andric KA_TRACE(20,
31750b57cec5SDimitry Andric ("__kmp_allocate_indirect_lock: allocated a new lock %p\n", lck));
31760b57cec5SDimitry Andric }
31770b57cec5SDimitry Andric
31780b57cec5SDimitry Andric __kmp_release_lock(&__kmp_global_lock, gtid);
31790b57cec5SDimitry Andric
31800b57cec5SDimitry Andric lck->type = tag;
31810b57cec5SDimitry Andric
31820b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *)) {
3183*74626c16SDimitry Andric *(kmp_lock_index_t *)&(((kmp_base_tas_lock_t *)user_lock)->poll) =
3184*74626c16SDimitry Andric idx << 1; // indirect lock word must be even
31850b57cec5SDimitry Andric } else {
31860b57cec5SDimitry Andric *((kmp_indirect_lock_t **)user_lock) = lck;
31870b57cec5SDimitry Andric }
31880b57cec5SDimitry Andric
31890b57cec5SDimitry Andric return lck;
31900b57cec5SDimitry Andric }
31910b57cec5SDimitry Andric
31920b57cec5SDimitry Andric // User lock lookup for dynamically dispatched locks.
31930b57cec5SDimitry Andric static __forceinline kmp_indirect_lock_t *
__kmp_lookup_indirect_lock(void ** user_lock,const char * func)31940b57cec5SDimitry Andric __kmp_lookup_indirect_lock(void **user_lock, const char *func) {
31950b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
31960b57cec5SDimitry Andric kmp_indirect_lock_t *lck = NULL;
31970b57cec5SDimitry Andric if (user_lock == NULL) {
31980b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
31990b57cec5SDimitry Andric }
32000b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *)) {
32010b57cec5SDimitry Andric kmp_lock_index_t idx = KMP_EXTRACT_I_INDEX(user_lock);
3202349cc55cSDimitry Andric lck = __kmp_get_i_lock(idx);
32030b57cec5SDimitry Andric } else {
32040b57cec5SDimitry Andric lck = *((kmp_indirect_lock_t **)user_lock);
32050b57cec5SDimitry Andric }
32060b57cec5SDimitry Andric if (lck == NULL) {
32070b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
32080b57cec5SDimitry Andric }
32090b57cec5SDimitry Andric return lck;
32100b57cec5SDimitry Andric } else {
32110b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *)) {
3212349cc55cSDimitry Andric return __kmp_get_i_lock(KMP_EXTRACT_I_INDEX(user_lock));
32130b57cec5SDimitry Andric } else {
32140b57cec5SDimitry Andric return *((kmp_indirect_lock_t **)user_lock);
32150b57cec5SDimitry Andric }
32160b57cec5SDimitry Andric }
32170b57cec5SDimitry Andric }
32180b57cec5SDimitry Andric
__kmp_init_indirect_lock(kmp_dyna_lock_t * lock,kmp_dyna_lockseq_t seq)32190b57cec5SDimitry Andric static void __kmp_init_indirect_lock(kmp_dyna_lock_t *lock,
32200b57cec5SDimitry Andric kmp_dyna_lockseq_t seq) {
32210b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
3222349cc55cSDimitry Andric if (seq == lockseq_adaptive && !__kmp_cpuinfo.flags.rtm) {
32230b57cec5SDimitry Andric KMP_WARNING(AdaptiveNotSupported, "kmp_lockseq_t", "adaptive");
32240b57cec5SDimitry Andric seq = lockseq_queuing;
32250b57cec5SDimitry Andric }
32260b57cec5SDimitry Andric #endif
32270b57cec5SDimitry Andric #if KMP_USE_TSX
3228349cc55cSDimitry Andric if (seq == lockseq_rtm_queuing && !__kmp_cpuinfo.flags.rtm) {
32290b57cec5SDimitry Andric seq = lockseq_queuing;
32300b57cec5SDimitry Andric }
32310b57cec5SDimitry Andric #endif
32320b57cec5SDimitry Andric kmp_indirect_locktag_t tag = KMP_GET_I_TAG(seq);
32330b57cec5SDimitry Andric kmp_indirect_lock_t *l =
32340b57cec5SDimitry Andric __kmp_allocate_indirect_lock((void **)lock, __kmp_entry_gtid(), tag);
32350b57cec5SDimitry Andric KMP_I_LOCK_FUNC(l, init)(l->lock);
32360b57cec5SDimitry Andric KA_TRACE(
32370b57cec5SDimitry Andric 20, ("__kmp_init_indirect_lock: initialized indirect lock with type#%d\n",
32380b57cec5SDimitry Andric seq));
32390b57cec5SDimitry Andric }
32400b57cec5SDimitry Andric
__kmp_destroy_indirect_lock(kmp_dyna_lock_t * lock)32410b57cec5SDimitry Andric static void __kmp_destroy_indirect_lock(kmp_dyna_lock_t *lock) {
32420b57cec5SDimitry Andric kmp_uint32 gtid = __kmp_entry_gtid();
32430b57cec5SDimitry Andric kmp_indirect_lock_t *l =
32440b57cec5SDimitry Andric __kmp_lookup_indirect_lock((void **)lock, "omp_destroy_lock");
32450b57cec5SDimitry Andric KMP_I_LOCK_FUNC(l, destroy)(l->lock);
32460b57cec5SDimitry Andric kmp_indirect_locktag_t tag = l->type;
32470b57cec5SDimitry Andric
32480b57cec5SDimitry Andric __kmp_acquire_lock(&__kmp_global_lock, gtid);
32490b57cec5SDimitry Andric
32500b57cec5SDimitry Andric // Use the base lock's space to keep the pool chain.
32510b57cec5SDimitry Andric l->lock->pool.next = (kmp_user_lock_p)__kmp_indirect_lock_pool[tag];
32520b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *)) {
32530b57cec5SDimitry Andric l->lock->pool.index = KMP_EXTRACT_I_INDEX(lock);
32540b57cec5SDimitry Andric }
32550b57cec5SDimitry Andric __kmp_indirect_lock_pool[tag] = l;
32560b57cec5SDimitry Andric
32570b57cec5SDimitry Andric __kmp_release_lock(&__kmp_global_lock, gtid);
32580b57cec5SDimitry Andric }
32590b57cec5SDimitry Andric
__kmp_set_indirect_lock(kmp_dyna_lock_t * lock,kmp_int32 gtid)32600b57cec5SDimitry Andric static int __kmp_set_indirect_lock(kmp_dyna_lock_t *lock, kmp_int32 gtid) {
32610b57cec5SDimitry Andric kmp_indirect_lock_t *l = KMP_LOOKUP_I_LOCK(lock);
32620b57cec5SDimitry Andric return KMP_I_LOCK_FUNC(l, set)(l->lock, gtid);
32630b57cec5SDimitry Andric }
32640b57cec5SDimitry Andric
__kmp_unset_indirect_lock(kmp_dyna_lock_t * lock,kmp_int32 gtid)32650b57cec5SDimitry Andric static int __kmp_unset_indirect_lock(kmp_dyna_lock_t *lock, kmp_int32 gtid) {
32660b57cec5SDimitry Andric kmp_indirect_lock_t *l = KMP_LOOKUP_I_LOCK(lock);
32670b57cec5SDimitry Andric return KMP_I_LOCK_FUNC(l, unset)(l->lock, gtid);
32680b57cec5SDimitry Andric }
32690b57cec5SDimitry Andric
__kmp_test_indirect_lock(kmp_dyna_lock_t * lock,kmp_int32 gtid)32700b57cec5SDimitry Andric static int __kmp_test_indirect_lock(kmp_dyna_lock_t *lock, kmp_int32 gtid) {
32710b57cec5SDimitry Andric kmp_indirect_lock_t *l = KMP_LOOKUP_I_LOCK(lock);
32720b57cec5SDimitry Andric return KMP_I_LOCK_FUNC(l, test)(l->lock, gtid);
32730b57cec5SDimitry Andric }
32740b57cec5SDimitry Andric
__kmp_set_indirect_lock_with_checks(kmp_dyna_lock_t * lock,kmp_int32 gtid)32750b57cec5SDimitry Andric static int __kmp_set_indirect_lock_with_checks(kmp_dyna_lock_t *lock,
32760b57cec5SDimitry Andric kmp_int32 gtid) {
32770b57cec5SDimitry Andric kmp_indirect_lock_t *l =
32780b57cec5SDimitry Andric __kmp_lookup_indirect_lock((void **)lock, "omp_set_lock");
32790b57cec5SDimitry Andric return KMP_I_LOCK_FUNC(l, set)(l->lock, gtid);
32800b57cec5SDimitry Andric }
32810b57cec5SDimitry Andric
__kmp_unset_indirect_lock_with_checks(kmp_dyna_lock_t * lock,kmp_int32 gtid)32820b57cec5SDimitry Andric static int __kmp_unset_indirect_lock_with_checks(kmp_dyna_lock_t *lock,
32830b57cec5SDimitry Andric kmp_int32 gtid) {
32840b57cec5SDimitry Andric kmp_indirect_lock_t *l =
32850b57cec5SDimitry Andric __kmp_lookup_indirect_lock((void **)lock, "omp_unset_lock");
32860b57cec5SDimitry Andric return KMP_I_LOCK_FUNC(l, unset)(l->lock, gtid);
32870b57cec5SDimitry Andric }
32880b57cec5SDimitry Andric
__kmp_test_indirect_lock_with_checks(kmp_dyna_lock_t * lock,kmp_int32 gtid)32890b57cec5SDimitry Andric static int __kmp_test_indirect_lock_with_checks(kmp_dyna_lock_t *lock,
32900b57cec5SDimitry Andric kmp_int32 gtid) {
32910b57cec5SDimitry Andric kmp_indirect_lock_t *l =
32920b57cec5SDimitry Andric __kmp_lookup_indirect_lock((void **)lock, "omp_test_lock");
32930b57cec5SDimitry Andric return KMP_I_LOCK_FUNC(l, test)(l->lock, gtid);
32940b57cec5SDimitry Andric }
32950b57cec5SDimitry Andric
32960b57cec5SDimitry Andric kmp_dyna_lockseq_t __kmp_user_lock_seq = lockseq_queuing;
32970b57cec5SDimitry Andric
32980b57cec5SDimitry Andric // This is used only in kmp_error.cpp when consistency checking is on.
__kmp_get_user_lock_owner(kmp_user_lock_p lck,kmp_uint32 seq)32990b57cec5SDimitry Andric kmp_int32 __kmp_get_user_lock_owner(kmp_user_lock_p lck, kmp_uint32 seq) {
33000b57cec5SDimitry Andric switch (seq) {
33010b57cec5SDimitry Andric case lockseq_tas:
33020b57cec5SDimitry Andric case lockseq_nested_tas:
33030b57cec5SDimitry Andric return __kmp_get_tas_lock_owner((kmp_tas_lock_t *)lck);
33040b57cec5SDimitry Andric #if KMP_USE_FUTEX
33050b57cec5SDimitry Andric case lockseq_futex:
33060b57cec5SDimitry Andric case lockseq_nested_futex:
33070b57cec5SDimitry Andric return __kmp_get_futex_lock_owner((kmp_futex_lock_t *)lck);
33080b57cec5SDimitry Andric #endif
33090b57cec5SDimitry Andric case lockseq_ticket:
33100b57cec5SDimitry Andric case lockseq_nested_ticket:
33110b57cec5SDimitry Andric return __kmp_get_ticket_lock_owner((kmp_ticket_lock_t *)lck);
33120b57cec5SDimitry Andric case lockseq_queuing:
33130b57cec5SDimitry Andric case lockseq_nested_queuing:
33140b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
33150b57cec5SDimitry Andric case lockseq_adaptive:
33160b57cec5SDimitry Andric #endif
33170b57cec5SDimitry Andric return __kmp_get_queuing_lock_owner((kmp_queuing_lock_t *)lck);
33180b57cec5SDimitry Andric case lockseq_drdpa:
33190b57cec5SDimitry Andric case lockseq_nested_drdpa:
33200b57cec5SDimitry Andric return __kmp_get_drdpa_lock_owner((kmp_drdpa_lock_t *)lck);
33210b57cec5SDimitry Andric default:
33220b57cec5SDimitry Andric return 0;
33230b57cec5SDimitry Andric }
33240b57cec5SDimitry Andric }
33250b57cec5SDimitry Andric
33260b57cec5SDimitry Andric // Initializes data for dynamic user locks.
__kmp_init_dynamic_user_locks()33270b57cec5SDimitry Andric void __kmp_init_dynamic_user_locks() {
33280b57cec5SDimitry Andric // Initialize jump table for the lock functions
33290b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
33300b57cec5SDimitry Andric __kmp_direct_set = direct_set_check;
33310b57cec5SDimitry Andric __kmp_direct_unset = direct_unset_check;
33320b57cec5SDimitry Andric __kmp_direct_test = direct_test_check;
33330b57cec5SDimitry Andric __kmp_direct_destroy = direct_destroy_check;
33340b57cec5SDimitry Andric __kmp_indirect_set = indirect_set_check;
33350b57cec5SDimitry Andric __kmp_indirect_unset = indirect_unset_check;
33360b57cec5SDimitry Andric __kmp_indirect_test = indirect_test_check;
33370b57cec5SDimitry Andric __kmp_indirect_destroy = indirect_destroy_check;
33380b57cec5SDimitry Andric } else {
33390b57cec5SDimitry Andric __kmp_direct_set = direct_set;
33400b57cec5SDimitry Andric __kmp_direct_unset = direct_unset;
33410b57cec5SDimitry Andric __kmp_direct_test = direct_test;
33420b57cec5SDimitry Andric __kmp_direct_destroy = direct_destroy;
33430b57cec5SDimitry Andric __kmp_indirect_set = indirect_set;
33440b57cec5SDimitry Andric __kmp_indirect_unset = indirect_unset;
33450b57cec5SDimitry Andric __kmp_indirect_test = indirect_test;
33460b57cec5SDimitry Andric __kmp_indirect_destroy = indirect_destroy;
33470b57cec5SDimitry Andric }
33480b57cec5SDimitry Andric // If the user locks have already been initialized, then return. Allow the
33490b57cec5SDimitry Andric // switch between different KMP_CONSISTENCY_CHECK values, but do not allocate
33500b57cec5SDimitry Andric // new lock tables if they have already been allocated.
33510b57cec5SDimitry Andric if (__kmp_init_user_locks)
33520b57cec5SDimitry Andric return;
33530b57cec5SDimitry Andric
33540b57cec5SDimitry Andric // Initialize lock index table
3355349cc55cSDimitry Andric __kmp_i_lock_table.nrow_ptrs = KMP_I_LOCK_TABLE_INIT_NROW_PTRS;
3356349cc55cSDimitry Andric __kmp_i_lock_table.table = (kmp_indirect_lock_t **)__kmp_allocate(
3357349cc55cSDimitry Andric sizeof(kmp_indirect_lock_t *) * KMP_I_LOCK_TABLE_INIT_NROW_PTRS);
33580b57cec5SDimitry Andric *(__kmp_i_lock_table.table) = (kmp_indirect_lock_t *)__kmp_allocate(
33590b57cec5SDimitry Andric KMP_I_LOCK_CHUNK * sizeof(kmp_indirect_lock_t));
33600b57cec5SDimitry Andric __kmp_i_lock_table.next = 0;
3361349cc55cSDimitry Andric __kmp_i_lock_table.next_table = nullptr;
33620b57cec5SDimitry Andric
33630b57cec5SDimitry Andric // Indirect lock size
33640b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_ticket] = sizeof(kmp_ticket_lock_t);
33650b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_queuing] = sizeof(kmp_queuing_lock_t);
33660b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
33670b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_adaptive] = sizeof(kmp_adaptive_lock_t);
33680b57cec5SDimitry Andric #endif
33690b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_drdpa] = sizeof(kmp_drdpa_lock_t);
33700b57cec5SDimitry Andric #if KMP_USE_TSX
3371e8d8bef9SDimitry Andric __kmp_indirect_lock_size[locktag_rtm_queuing] = sizeof(kmp_queuing_lock_t);
33720b57cec5SDimitry Andric #endif
33730b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_nested_tas] = sizeof(kmp_tas_lock_t);
33740b57cec5SDimitry Andric #if KMP_USE_FUTEX
33750b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_nested_futex] = sizeof(kmp_futex_lock_t);
33760b57cec5SDimitry Andric #endif
33770b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_nested_ticket] = sizeof(kmp_ticket_lock_t);
33780b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_nested_queuing] = sizeof(kmp_queuing_lock_t);
33790b57cec5SDimitry Andric __kmp_indirect_lock_size[locktag_nested_drdpa] = sizeof(kmp_drdpa_lock_t);
33800b57cec5SDimitry Andric
33810b57cec5SDimitry Andric // Initialize lock accessor/modifier
33820b57cec5SDimitry Andric #define fill_jumps(table, expand, sep) \
33830b57cec5SDimitry Andric { \
33840b57cec5SDimitry Andric table[locktag##sep##ticket] = expand(ticket); \
33850b57cec5SDimitry Andric table[locktag##sep##queuing] = expand(queuing); \
33860b57cec5SDimitry Andric table[locktag##sep##drdpa] = expand(drdpa); \
33870b57cec5SDimitry Andric }
33880b57cec5SDimitry Andric
33890b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
33900b57cec5SDimitry Andric #define fill_table(table, expand) \
33910b57cec5SDimitry Andric { \
33920b57cec5SDimitry Andric fill_jumps(table, expand, _); \
33930b57cec5SDimitry Andric table[locktag_adaptive] = expand(queuing); \
33940b57cec5SDimitry Andric fill_jumps(table, expand, _nested_); \
33950b57cec5SDimitry Andric }
33960b57cec5SDimitry Andric #else
33970b57cec5SDimitry Andric #define fill_table(table, expand) \
33980b57cec5SDimitry Andric { \
33990b57cec5SDimitry Andric fill_jumps(table, expand, _); \
34000b57cec5SDimitry Andric fill_jumps(table, expand, _nested_); \
34010b57cec5SDimitry Andric }
34020b57cec5SDimitry Andric #endif // KMP_USE_ADAPTIVE_LOCKS
34030b57cec5SDimitry Andric
34040b57cec5SDimitry Andric #define expand(l) \
34050b57cec5SDimitry Andric (void (*)(kmp_user_lock_p, const ident_t *)) __kmp_set_##l##_lock_location
34060b57cec5SDimitry Andric fill_table(__kmp_indirect_set_location, expand);
34070b57cec5SDimitry Andric #undef expand
34080b57cec5SDimitry Andric #define expand(l) \
34090b57cec5SDimitry Andric (void (*)(kmp_user_lock_p, kmp_lock_flags_t)) __kmp_set_##l##_lock_flags
34100b57cec5SDimitry Andric fill_table(__kmp_indirect_set_flags, expand);
34110b57cec5SDimitry Andric #undef expand
34120b57cec5SDimitry Andric #define expand(l) \
34130b57cec5SDimitry Andric (const ident_t *(*)(kmp_user_lock_p)) __kmp_get_##l##_lock_location
34140b57cec5SDimitry Andric fill_table(__kmp_indirect_get_location, expand);
34150b57cec5SDimitry Andric #undef expand
34160b57cec5SDimitry Andric #define expand(l) \
34170b57cec5SDimitry Andric (kmp_lock_flags_t(*)(kmp_user_lock_p)) __kmp_get_##l##_lock_flags
34180b57cec5SDimitry Andric fill_table(__kmp_indirect_get_flags, expand);
34190b57cec5SDimitry Andric #undef expand
34200b57cec5SDimitry Andric
34210b57cec5SDimitry Andric __kmp_init_user_locks = TRUE;
34220b57cec5SDimitry Andric }
34230b57cec5SDimitry Andric
34240b57cec5SDimitry Andric // Clean up the lock table.
__kmp_cleanup_indirect_user_locks()34250b57cec5SDimitry Andric void __kmp_cleanup_indirect_user_locks() {
34260b57cec5SDimitry Andric int k;
34270b57cec5SDimitry Andric
34280b57cec5SDimitry Andric // Clean up locks in the pools first (they were already destroyed before going
34290b57cec5SDimitry Andric // into the pools).
34300b57cec5SDimitry Andric for (k = 0; k < KMP_NUM_I_LOCKS; ++k) {
34310b57cec5SDimitry Andric kmp_indirect_lock_t *l = __kmp_indirect_lock_pool[k];
34320b57cec5SDimitry Andric while (l != NULL) {
34330b57cec5SDimitry Andric kmp_indirect_lock_t *ll = l;
34340b57cec5SDimitry Andric l = (kmp_indirect_lock_t *)l->lock->pool.next;
34350b57cec5SDimitry Andric KA_TRACE(20, ("__kmp_cleanup_indirect_user_locks: freeing %p from pool\n",
34360b57cec5SDimitry Andric ll));
34370b57cec5SDimitry Andric __kmp_free(ll->lock);
34380b57cec5SDimitry Andric ll->lock = NULL;
34390b57cec5SDimitry Andric }
34400b57cec5SDimitry Andric __kmp_indirect_lock_pool[k] = NULL;
34410b57cec5SDimitry Andric }
34420b57cec5SDimitry Andric // Clean up the remaining undestroyed locks.
3443349cc55cSDimitry Andric kmp_indirect_lock_table_t *ptr = &__kmp_i_lock_table;
3444349cc55cSDimitry Andric while (ptr) {
3445349cc55cSDimitry Andric for (kmp_uint32 row = 0; row < ptr->nrow_ptrs; ++row) {
3446349cc55cSDimitry Andric if (!ptr->table[row])
3447349cc55cSDimitry Andric continue;
3448349cc55cSDimitry Andric for (kmp_uint32 col = 0; col < KMP_I_LOCK_CHUNK; ++col) {
3449349cc55cSDimitry Andric kmp_indirect_lock_t *l = &ptr->table[row][col];
3450349cc55cSDimitry Andric if (l->lock) {
34510b57cec5SDimitry Andric // Locks not destroyed explicitly need to be destroyed here.
34520b57cec5SDimitry Andric KMP_I_LOCK_FUNC(l, destroy)(l->lock);
3453349cc55cSDimitry Andric KA_TRACE(20, ("__kmp_cleanup_indirect_user_locks: destroy/freeing %p "
3454349cc55cSDimitry Andric "from table\n",
34550b57cec5SDimitry Andric l));
34560b57cec5SDimitry Andric __kmp_free(l->lock);
34570b57cec5SDimitry Andric }
34580b57cec5SDimitry Andric }
3459349cc55cSDimitry Andric __kmp_free(ptr->table[row]);
3460349cc55cSDimitry Andric }
3461349cc55cSDimitry Andric kmp_indirect_lock_table_t *next_table = ptr->next_table;
3462349cc55cSDimitry Andric if (ptr != &__kmp_i_lock_table)
3463349cc55cSDimitry Andric __kmp_free(ptr);
3464349cc55cSDimitry Andric ptr = next_table;
3465349cc55cSDimitry Andric }
34660b57cec5SDimitry Andric
34670b57cec5SDimitry Andric __kmp_init_user_locks = FALSE;
34680b57cec5SDimitry Andric }
34690b57cec5SDimitry Andric
34700b57cec5SDimitry Andric enum kmp_lock_kind __kmp_user_lock_kind = lk_default;
34710b57cec5SDimitry Andric int __kmp_num_locks_in_block = 1; // FIXME - tune this value
34720b57cec5SDimitry Andric
34730b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
34740b57cec5SDimitry Andric
__kmp_init_tas_lock_with_checks(kmp_tas_lock_t * lck)34750b57cec5SDimitry Andric static void __kmp_init_tas_lock_with_checks(kmp_tas_lock_t *lck) {
34760b57cec5SDimitry Andric __kmp_init_tas_lock(lck);
34770b57cec5SDimitry Andric }
34780b57cec5SDimitry Andric
__kmp_init_nested_tas_lock_with_checks(kmp_tas_lock_t * lck)34790b57cec5SDimitry Andric static void __kmp_init_nested_tas_lock_with_checks(kmp_tas_lock_t *lck) {
34800b57cec5SDimitry Andric __kmp_init_nested_tas_lock(lck);
34810b57cec5SDimitry Andric }
34820b57cec5SDimitry Andric
34830b57cec5SDimitry Andric #if KMP_USE_FUTEX
__kmp_init_futex_lock_with_checks(kmp_futex_lock_t * lck)34840b57cec5SDimitry Andric static void __kmp_init_futex_lock_with_checks(kmp_futex_lock_t *lck) {
34850b57cec5SDimitry Andric __kmp_init_futex_lock(lck);
34860b57cec5SDimitry Andric }
34870b57cec5SDimitry Andric
__kmp_init_nested_futex_lock_with_checks(kmp_futex_lock_t * lck)34880b57cec5SDimitry Andric static void __kmp_init_nested_futex_lock_with_checks(kmp_futex_lock_t *lck) {
34890b57cec5SDimitry Andric __kmp_init_nested_futex_lock(lck);
34900b57cec5SDimitry Andric }
34910b57cec5SDimitry Andric #endif
34920b57cec5SDimitry Andric
__kmp_is_ticket_lock_initialized(kmp_ticket_lock_t * lck)34930b57cec5SDimitry Andric static int __kmp_is_ticket_lock_initialized(kmp_ticket_lock_t *lck) {
34940b57cec5SDimitry Andric return lck == lck->lk.self;
34950b57cec5SDimitry Andric }
34960b57cec5SDimitry Andric
__kmp_init_ticket_lock_with_checks(kmp_ticket_lock_t * lck)34970b57cec5SDimitry Andric static void __kmp_init_ticket_lock_with_checks(kmp_ticket_lock_t *lck) {
34980b57cec5SDimitry Andric __kmp_init_ticket_lock(lck);
34990b57cec5SDimitry Andric }
35000b57cec5SDimitry Andric
__kmp_init_nested_ticket_lock_with_checks(kmp_ticket_lock_t * lck)35010b57cec5SDimitry Andric static void __kmp_init_nested_ticket_lock_with_checks(kmp_ticket_lock_t *lck) {
35020b57cec5SDimitry Andric __kmp_init_nested_ticket_lock(lck);
35030b57cec5SDimitry Andric }
35040b57cec5SDimitry Andric
__kmp_is_queuing_lock_initialized(kmp_queuing_lock_t * lck)35050b57cec5SDimitry Andric static int __kmp_is_queuing_lock_initialized(kmp_queuing_lock_t *lck) {
35060b57cec5SDimitry Andric return lck == lck->lk.initialized;
35070b57cec5SDimitry Andric }
35080b57cec5SDimitry Andric
__kmp_init_queuing_lock_with_checks(kmp_queuing_lock_t * lck)35090b57cec5SDimitry Andric static void __kmp_init_queuing_lock_with_checks(kmp_queuing_lock_t *lck) {
35100b57cec5SDimitry Andric __kmp_init_queuing_lock(lck);
35110b57cec5SDimitry Andric }
35120b57cec5SDimitry Andric
35130b57cec5SDimitry Andric static void
__kmp_init_nested_queuing_lock_with_checks(kmp_queuing_lock_t * lck)35140b57cec5SDimitry Andric __kmp_init_nested_queuing_lock_with_checks(kmp_queuing_lock_t *lck) {
35150b57cec5SDimitry Andric __kmp_init_nested_queuing_lock(lck);
35160b57cec5SDimitry Andric }
35170b57cec5SDimitry Andric
35180b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
__kmp_init_adaptive_lock_with_checks(kmp_adaptive_lock_t * lck)35190b57cec5SDimitry Andric static void __kmp_init_adaptive_lock_with_checks(kmp_adaptive_lock_t *lck) {
35200b57cec5SDimitry Andric __kmp_init_adaptive_lock(lck);
35210b57cec5SDimitry Andric }
35220b57cec5SDimitry Andric #endif
35230b57cec5SDimitry Andric
__kmp_is_drdpa_lock_initialized(kmp_drdpa_lock_t * lck)35240b57cec5SDimitry Andric static int __kmp_is_drdpa_lock_initialized(kmp_drdpa_lock_t *lck) {
35250b57cec5SDimitry Andric return lck == lck->lk.initialized;
35260b57cec5SDimitry Andric }
35270b57cec5SDimitry Andric
__kmp_init_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck)35280b57cec5SDimitry Andric static void __kmp_init_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck) {
35290b57cec5SDimitry Andric __kmp_init_drdpa_lock(lck);
35300b57cec5SDimitry Andric }
35310b57cec5SDimitry Andric
__kmp_init_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t * lck)35320b57cec5SDimitry Andric static void __kmp_init_nested_drdpa_lock_with_checks(kmp_drdpa_lock_t *lck) {
35330b57cec5SDimitry Andric __kmp_init_nested_drdpa_lock(lck);
35340b57cec5SDimitry Andric }
35350b57cec5SDimitry Andric
35360b57cec5SDimitry Andric /* user locks
35370b57cec5SDimitry Andric * They are implemented as a table of function pointers which are set to the
35380b57cec5SDimitry Andric * lock functions of the appropriate kind, once that has been determined. */
35390b57cec5SDimitry Andric
35400b57cec5SDimitry Andric enum kmp_lock_kind __kmp_user_lock_kind = lk_default;
35410b57cec5SDimitry Andric
35420b57cec5SDimitry Andric size_t __kmp_base_user_lock_size = 0;
35430b57cec5SDimitry Andric size_t __kmp_user_lock_size = 0;
35440b57cec5SDimitry Andric
35450b57cec5SDimitry Andric kmp_int32 (*__kmp_get_user_lock_owner_)(kmp_user_lock_p lck) = NULL;
35460b57cec5SDimitry Andric int (*__kmp_acquire_user_lock_with_checks_)(kmp_user_lock_p lck,
35470b57cec5SDimitry Andric kmp_int32 gtid) = NULL;
35480b57cec5SDimitry Andric
35490b57cec5SDimitry Andric int (*__kmp_test_user_lock_with_checks_)(kmp_user_lock_p lck,
35500b57cec5SDimitry Andric kmp_int32 gtid) = NULL;
35510b57cec5SDimitry Andric int (*__kmp_release_user_lock_with_checks_)(kmp_user_lock_p lck,
35520b57cec5SDimitry Andric kmp_int32 gtid) = NULL;
35530b57cec5SDimitry Andric void (*__kmp_init_user_lock_with_checks_)(kmp_user_lock_p lck) = NULL;
35540b57cec5SDimitry Andric void (*__kmp_destroy_user_lock_)(kmp_user_lock_p lck) = NULL;
35550b57cec5SDimitry Andric void (*__kmp_destroy_user_lock_with_checks_)(kmp_user_lock_p lck) = NULL;
35560b57cec5SDimitry Andric int (*__kmp_acquire_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
35570b57cec5SDimitry Andric kmp_int32 gtid) = NULL;
35580b57cec5SDimitry Andric
35590b57cec5SDimitry Andric int (*__kmp_test_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
35600b57cec5SDimitry Andric kmp_int32 gtid) = NULL;
35610b57cec5SDimitry Andric int (*__kmp_release_nested_user_lock_with_checks_)(kmp_user_lock_p lck,
35620b57cec5SDimitry Andric kmp_int32 gtid) = NULL;
35630b57cec5SDimitry Andric void (*__kmp_init_nested_user_lock_with_checks_)(kmp_user_lock_p lck) = NULL;
35640b57cec5SDimitry Andric void (*__kmp_destroy_nested_user_lock_with_checks_)(kmp_user_lock_p lck) = NULL;
35650b57cec5SDimitry Andric
35660b57cec5SDimitry Andric int (*__kmp_is_user_lock_initialized_)(kmp_user_lock_p lck) = NULL;
35670b57cec5SDimitry Andric const ident_t *(*__kmp_get_user_lock_location_)(kmp_user_lock_p lck) = NULL;
35680b57cec5SDimitry Andric void (*__kmp_set_user_lock_location_)(kmp_user_lock_p lck,
35690b57cec5SDimitry Andric const ident_t *loc) = NULL;
35700b57cec5SDimitry Andric kmp_lock_flags_t (*__kmp_get_user_lock_flags_)(kmp_user_lock_p lck) = NULL;
35710b57cec5SDimitry Andric void (*__kmp_set_user_lock_flags_)(kmp_user_lock_p lck,
35720b57cec5SDimitry Andric kmp_lock_flags_t flags) = NULL;
35730b57cec5SDimitry Andric
__kmp_set_user_lock_vptrs(kmp_lock_kind_t user_lock_kind)35740b57cec5SDimitry Andric void __kmp_set_user_lock_vptrs(kmp_lock_kind_t user_lock_kind) {
35750b57cec5SDimitry Andric switch (user_lock_kind) {
35760b57cec5SDimitry Andric case lk_default:
35770b57cec5SDimitry Andric default:
35780b57cec5SDimitry Andric KMP_ASSERT(0);
35790b57cec5SDimitry Andric
35800b57cec5SDimitry Andric case lk_tas: {
35810b57cec5SDimitry Andric __kmp_base_user_lock_size = sizeof(kmp_base_tas_lock_t);
35820b57cec5SDimitry Andric __kmp_user_lock_size = sizeof(kmp_tas_lock_t);
35830b57cec5SDimitry Andric
35840b57cec5SDimitry Andric __kmp_get_user_lock_owner_ =
35850b57cec5SDimitry Andric (kmp_int32(*)(kmp_user_lock_p))(&__kmp_get_tas_lock_owner);
35860b57cec5SDimitry Andric
35870b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
35880b57cec5SDimitry Andric KMP_BIND_USER_LOCK_WITH_CHECKS(tas);
35890b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(tas);
35900b57cec5SDimitry Andric } else {
35910b57cec5SDimitry Andric KMP_BIND_USER_LOCK(tas);
35920b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK(tas);
35930b57cec5SDimitry Andric }
35940b57cec5SDimitry Andric
35950b57cec5SDimitry Andric __kmp_destroy_user_lock_ =
35960b57cec5SDimitry Andric (void (*)(kmp_user_lock_p))(&__kmp_destroy_tas_lock);
35970b57cec5SDimitry Andric
35980b57cec5SDimitry Andric __kmp_is_user_lock_initialized_ = (int (*)(kmp_user_lock_p))NULL;
35990b57cec5SDimitry Andric
36000b57cec5SDimitry Andric __kmp_get_user_lock_location_ = (const ident_t *(*)(kmp_user_lock_p))NULL;
36010b57cec5SDimitry Andric
36020b57cec5SDimitry Andric __kmp_set_user_lock_location_ =
36030b57cec5SDimitry Andric (void (*)(kmp_user_lock_p, const ident_t *))NULL;
36040b57cec5SDimitry Andric
36050b57cec5SDimitry Andric __kmp_get_user_lock_flags_ = (kmp_lock_flags_t(*)(kmp_user_lock_p))NULL;
36060b57cec5SDimitry Andric
36070b57cec5SDimitry Andric __kmp_set_user_lock_flags_ =
36080b57cec5SDimitry Andric (void (*)(kmp_user_lock_p, kmp_lock_flags_t))NULL;
36090b57cec5SDimitry Andric } break;
36100b57cec5SDimitry Andric
36110b57cec5SDimitry Andric #if KMP_USE_FUTEX
36120b57cec5SDimitry Andric
36130b57cec5SDimitry Andric case lk_futex: {
36140b57cec5SDimitry Andric __kmp_base_user_lock_size = sizeof(kmp_base_futex_lock_t);
36150b57cec5SDimitry Andric __kmp_user_lock_size = sizeof(kmp_futex_lock_t);
36160b57cec5SDimitry Andric
36170b57cec5SDimitry Andric __kmp_get_user_lock_owner_ =
36180b57cec5SDimitry Andric (kmp_int32(*)(kmp_user_lock_p))(&__kmp_get_futex_lock_owner);
36190b57cec5SDimitry Andric
36200b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
36210b57cec5SDimitry Andric KMP_BIND_USER_LOCK_WITH_CHECKS(futex);
36220b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(futex);
36230b57cec5SDimitry Andric } else {
36240b57cec5SDimitry Andric KMP_BIND_USER_LOCK(futex);
36250b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK(futex);
36260b57cec5SDimitry Andric }
36270b57cec5SDimitry Andric
36280b57cec5SDimitry Andric __kmp_destroy_user_lock_ =
36290b57cec5SDimitry Andric (void (*)(kmp_user_lock_p))(&__kmp_destroy_futex_lock);
36300b57cec5SDimitry Andric
36310b57cec5SDimitry Andric __kmp_is_user_lock_initialized_ = (int (*)(kmp_user_lock_p))NULL;
36320b57cec5SDimitry Andric
36330b57cec5SDimitry Andric __kmp_get_user_lock_location_ = (const ident_t *(*)(kmp_user_lock_p))NULL;
36340b57cec5SDimitry Andric
36350b57cec5SDimitry Andric __kmp_set_user_lock_location_ =
36360b57cec5SDimitry Andric (void (*)(kmp_user_lock_p, const ident_t *))NULL;
36370b57cec5SDimitry Andric
36380b57cec5SDimitry Andric __kmp_get_user_lock_flags_ = (kmp_lock_flags_t(*)(kmp_user_lock_p))NULL;
36390b57cec5SDimitry Andric
36400b57cec5SDimitry Andric __kmp_set_user_lock_flags_ =
36410b57cec5SDimitry Andric (void (*)(kmp_user_lock_p, kmp_lock_flags_t))NULL;
36420b57cec5SDimitry Andric } break;
36430b57cec5SDimitry Andric
36440b57cec5SDimitry Andric #endif // KMP_USE_FUTEX
36450b57cec5SDimitry Andric
36460b57cec5SDimitry Andric case lk_ticket: {
36470b57cec5SDimitry Andric __kmp_base_user_lock_size = sizeof(kmp_base_ticket_lock_t);
36480b57cec5SDimitry Andric __kmp_user_lock_size = sizeof(kmp_ticket_lock_t);
36490b57cec5SDimitry Andric
36500b57cec5SDimitry Andric __kmp_get_user_lock_owner_ =
36510b57cec5SDimitry Andric (kmp_int32(*)(kmp_user_lock_p))(&__kmp_get_ticket_lock_owner);
36520b57cec5SDimitry Andric
36530b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
36540b57cec5SDimitry Andric KMP_BIND_USER_LOCK_WITH_CHECKS(ticket);
36550b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(ticket);
36560b57cec5SDimitry Andric } else {
36570b57cec5SDimitry Andric KMP_BIND_USER_LOCK(ticket);
36580b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK(ticket);
36590b57cec5SDimitry Andric }
36600b57cec5SDimitry Andric
36610b57cec5SDimitry Andric __kmp_destroy_user_lock_ =
36620b57cec5SDimitry Andric (void (*)(kmp_user_lock_p))(&__kmp_destroy_ticket_lock);
36630b57cec5SDimitry Andric
36640b57cec5SDimitry Andric __kmp_is_user_lock_initialized_ =
36650b57cec5SDimitry Andric (int (*)(kmp_user_lock_p))(&__kmp_is_ticket_lock_initialized);
36660b57cec5SDimitry Andric
36670b57cec5SDimitry Andric __kmp_get_user_lock_location_ =
36680b57cec5SDimitry Andric (const ident_t *(*)(kmp_user_lock_p))(&__kmp_get_ticket_lock_location);
36690b57cec5SDimitry Andric
36700b57cec5SDimitry Andric __kmp_set_user_lock_location_ = (void (*)(
36710b57cec5SDimitry Andric kmp_user_lock_p, const ident_t *))(&__kmp_set_ticket_lock_location);
36720b57cec5SDimitry Andric
36730b57cec5SDimitry Andric __kmp_get_user_lock_flags_ =
36740b57cec5SDimitry Andric (kmp_lock_flags_t(*)(kmp_user_lock_p))(&__kmp_get_ticket_lock_flags);
36750b57cec5SDimitry Andric
36760b57cec5SDimitry Andric __kmp_set_user_lock_flags_ = (void (*)(kmp_user_lock_p, kmp_lock_flags_t))(
36770b57cec5SDimitry Andric &__kmp_set_ticket_lock_flags);
36780b57cec5SDimitry Andric } break;
36790b57cec5SDimitry Andric
36800b57cec5SDimitry Andric case lk_queuing: {
36810b57cec5SDimitry Andric __kmp_base_user_lock_size = sizeof(kmp_base_queuing_lock_t);
36820b57cec5SDimitry Andric __kmp_user_lock_size = sizeof(kmp_queuing_lock_t);
36830b57cec5SDimitry Andric
36840b57cec5SDimitry Andric __kmp_get_user_lock_owner_ =
36850b57cec5SDimitry Andric (kmp_int32(*)(kmp_user_lock_p))(&__kmp_get_queuing_lock_owner);
36860b57cec5SDimitry Andric
36870b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
36880b57cec5SDimitry Andric KMP_BIND_USER_LOCK_WITH_CHECKS(queuing);
36890b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(queuing);
36900b57cec5SDimitry Andric } else {
36910b57cec5SDimitry Andric KMP_BIND_USER_LOCK(queuing);
36920b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK(queuing);
36930b57cec5SDimitry Andric }
36940b57cec5SDimitry Andric
36950b57cec5SDimitry Andric __kmp_destroy_user_lock_ =
36960b57cec5SDimitry Andric (void (*)(kmp_user_lock_p))(&__kmp_destroy_queuing_lock);
36970b57cec5SDimitry Andric
36980b57cec5SDimitry Andric __kmp_is_user_lock_initialized_ =
36990b57cec5SDimitry Andric (int (*)(kmp_user_lock_p))(&__kmp_is_queuing_lock_initialized);
37000b57cec5SDimitry Andric
37010b57cec5SDimitry Andric __kmp_get_user_lock_location_ =
37020b57cec5SDimitry Andric (const ident_t *(*)(kmp_user_lock_p))(&__kmp_get_queuing_lock_location);
37030b57cec5SDimitry Andric
37040b57cec5SDimitry Andric __kmp_set_user_lock_location_ = (void (*)(
37050b57cec5SDimitry Andric kmp_user_lock_p, const ident_t *))(&__kmp_set_queuing_lock_location);
37060b57cec5SDimitry Andric
37070b57cec5SDimitry Andric __kmp_get_user_lock_flags_ =
37080b57cec5SDimitry Andric (kmp_lock_flags_t(*)(kmp_user_lock_p))(&__kmp_get_queuing_lock_flags);
37090b57cec5SDimitry Andric
37100b57cec5SDimitry Andric __kmp_set_user_lock_flags_ = (void (*)(kmp_user_lock_p, kmp_lock_flags_t))(
37110b57cec5SDimitry Andric &__kmp_set_queuing_lock_flags);
37120b57cec5SDimitry Andric } break;
37130b57cec5SDimitry Andric
37140b57cec5SDimitry Andric #if KMP_USE_ADAPTIVE_LOCKS
37150b57cec5SDimitry Andric case lk_adaptive: {
37160b57cec5SDimitry Andric __kmp_base_user_lock_size = sizeof(kmp_base_adaptive_lock_t);
37170b57cec5SDimitry Andric __kmp_user_lock_size = sizeof(kmp_adaptive_lock_t);
37180b57cec5SDimitry Andric
37190b57cec5SDimitry Andric __kmp_get_user_lock_owner_ =
37200b57cec5SDimitry Andric (kmp_int32(*)(kmp_user_lock_p))(&__kmp_get_queuing_lock_owner);
37210b57cec5SDimitry Andric
37220b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
37230b57cec5SDimitry Andric KMP_BIND_USER_LOCK_WITH_CHECKS(adaptive);
37240b57cec5SDimitry Andric } else {
37250b57cec5SDimitry Andric KMP_BIND_USER_LOCK(adaptive);
37260b57cec5SDimitry Andric }
37270b57cec5SDimitry Andric
37280b57cec5SDimitry Andric __kmp_destroy_user_lock_ =
37290b57cec5SDimitry Andric (void (*)(kmp_user_lock_p))(&__kmp_destroy_adaptive_lock);
37300b57cec5SDimitry Andric
37310b57cec5SDimitry Andric __kmp_is_user_lock_initialized_ =
37320b57cec5SDimitry Andric (int (*)(kmp_user_lock_p))(&__kmp_is_queuing_lock_initialized);
37330b57cec5SDimitry Andric
37340b57cec5SDimitry Andric __kmp_get_user_lock_location_ =
37350b57cec5SDimitry Andric (const ident_t *(*)(kmp_user_lock_p))(&__kmp_get_queuing_lock_location);
37360b57cec5SDimitry Andric
37370b57cec5SDimitry Andric __kmp_set_user_lock_location_ = (void (*)(
37380b57cec5SDimitry Andric kmp_user_lock_p, const ident_t *))(&__kmp_set_queuing_lock_location);
37390b57cec5SDimitry Andric
37400b57cec5SDimitry Andric __kmp_get_user_lock_flags_ =
37410b57cec5SDimitry Andric (kmp_lock_flags_t(*)(kmp_user_lock_p))(&__kmp_get_queuing_lock_flags);
37420b57cec5SDimitry Andric
37430b57cec5SDimitry Andric __kmp_set_user_lock_flags_ = (void (*)(kmp_user_lock_p, kmp_lock_flags_t))(
37440b57cec5SDimitry Andric &__kmp_set_queuing_lock_flags);
37450b57cec5SDimitry Andric
37460b57cec5SDimitry Andric } break;
37470b57cec5SDimitry Andric #endif // KMP_USE_ADAPTIVE_LOCKS
37480b57cec5SDimitry Andric
37490b57cec5SDimitry Andric case lk_drdpa: {
37500b57cec5SDimitry Andric __kmp_base_user_lock_size = sizeof(kmp_base_drdpa_lock_t);
37510b57cec5SDimitry Andric __kmp_user_lock_size = sizeof(kmp_drdpa_lock_t);
37520b57cec5SDimitry Andric
37530b57cec5SDimitry Andric __kmp_get_user_lock_owner_ =
37540b57cec5SDimitry Andric (kmp_int32(*)(kmp_user_lock_p))(&__kmp_get_drdpa_lock_owner);
37550b57cec5SDimitry Andric
37560b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
37570b57cec5SDimitry Andric KMP_BIND_USER_LOCK_WITH_CHECKS(drdpa);
37580b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(drdpa);
37590b57cec5SDimitry Andric } else {
37600b57cec5SDimitry Andric KMP_BIND_USER_LOCK(drdpa);
37610b57cec5SDimitry Andric KMP_BIND_NESTED_USER_LOCK(drdpa);
37620b57cec5SDimitry Andric }
37630b57cec5SDimitry Andric
37640b57cec5SDimitry Andric __kmp_destroy_user_lock_ =
37650b57cec5SDimitry Andric (void (*)(kmp_user_lock_p))(&__kmp_destroy_drdpa_lock);
37660b57cec5SDimitry Andric
37670b57cec5SDimitry Andric __kmp_is_user_lock_initialized_ =
37680b57cec5SDimitry Andric (int (*)(kmp_user_lock_p))(&__kmp_is_drdpa_lock_initialized);
37690b57cec5SDimitry Andric
37700b57cec5SDimitry Andric __kmp_get_user_lock_location_ =
37710b57cec5SDimitry Andric (const ident_t *(*)(kmp_user_lock_p))(&__kmp_get_drdpa_lock_location);
37720b57cec5SDimitry Andric
37730b57cec5SDimitry Andric __kmp_set_user_lock_location_ = (void (*)(
37740b57cec5SDimitry Andric kmp_user_lock_p, const ident_t *))(&__kmp_set_drdpa_lock_location);
37750b57cec5SDimitry Andric
37760b57cec5SDimitry Andric __kmp_get_user_lock_flags_ =
37770b57cec5SDimitry Andric (kmp_lock_flags_t(*)(kmp_user_lock_p))(&__kmp_get_drdpa_lock_flags);
37780b57cec5SDimitry Andric
37790b57cec5SDimitry Andric __kmp_set_user_lock_flags_ = (void (*)(kmp_user_lock_p, kmp_lock_flags_t))(
37800b57cec5SDimitry Andric &__kmp_set_drdpa_lock_flags);
37810b57cec5SDimitry Andric } break;
37820b57cec5SDimitry Andric }
37830b57cec5SDimitry Andric }
37840b57cec5SDimitry Andric
37850b57cec5SDimitry Andric // ----------------------------------------------------------------------------
37860b57cec5SDimitry Andric // User lock table & lock allocation
37870b57cec5SDimitry Andric
37880b57cec5SDimitry Andric kmp_lock_table_t __kmp_user_lock_table = {1, 0, NULL};
37890b57cec5SDimitry Andric kmp_user_lock_p __kmp_lock_pool = NULL;
37900b57cec5SDimitry Andric
37910b57cec5SDimitry Andric // Lock block-allocation support.
37920b57cec5SDimitry Andric kmp_block_of_locks *__kmp_lock_blocks = NULL;
37930b57cec5SDimitry Andric int __kmp_num_locks_in_block = 1; // FIXME - tune this value
37940b57cec5SDimitry Andric
__kmp_lock_table_insert(kmp_user_lock_p lck)37950b57cec5SDimitry Andric static kmp_lock_index_t __kmp_lock_table_insert(kmp_user_lock_p lck) {
37960b57cec5SDimitry Andric // Assume that kmp_global_lock is held upon entry/exit.
37970b57cec5SDimitry Andric kmp_lock_index_t index;
37980b57cec5SDimitry Andric if (__kmp_user_lock_table.used >= __kmp_user_lock_table.allocated) {
37990b57cec5SDimitry Andric kmp_lock_index_t size;
38000b57cec5SDimitry Andric kmp_user_lock_p *table;
38010b57cec5SDimitry Andric // Reallocate lock table.
38020b57cec5SDimitry Andric if (__kmp_user_lock_table.allocated == 0) {
38030b57cec5SDimitry Andric size = 1024;
38040b57cec5SDimitry Andric } else {
38050b57cec5SDimitry Andric size = __kmp_user_lock_table.allocated * 2;
38060b57cec5SDimitry Andric }
38070b57cec5SDimitry Andric table = (kmp_user_lock_p *)__kmp_allocate(sizeof(kmp_user_lock_p) * size);
38080b57cec5SDimitry Andric KMP_MEMCPY(table + 1, __kmp_user_lock_table.table + 1,
38090b57cec5SDimitry Andric sizeof(kmp_user_lock_p) * (__kmp_user_lock_table.used - 1));
38100b57cec5SDimitry Andric table[0] = (kmp_user_lock_p)__kmp_user_lock_table.table;
38110b57cec5SDimitry Andric // We cannot free the previous table now, since it may be in use by other
38125f757f3fSDimitry Andric // threads. So save the pointer to the previous table in the first
38130b57cec5SDimitry Andric // element of the new table. All the tables will be organized into a list,
38140b57cec5SDimitry Andric // and could be freed when library shutting down.
38150b57cec5SDimitry Andric __kmp_user_lock_table.table = table;
38160b57cec5SDimitry Andric __kmp_user_lock_table.allocated = size;
38170b57cec5SDimitry Andric }
38180b57cec5SDimitry Andric KMP_DEBUG_ASSERT(__kmp_user_lock_table.used <
38190b57cec5SDimitry Andric __kmp_user_lock_table.allocated);
38200b57cec5SDimitry Andric index = __kmp_user_lock_table.used;
38210b57cec5SDimitry Andric __kmp_user_lock_table.table[index] = lck;
38220b57cec5SDimitry Andric ++__kmp_user_lock_table.used;
38230b57cec5SDimitry Andric return index;
38240b57cec5SDimitry Andric }
38250b57cec5SDimitry Andric
__kmp_lock_block_allocate()38260b57cec5SDimitry Andric static kmp_user_lock_p __kmp_lock_block_allocate() {
38270b57cec5SDimitry Andric // Assume that kmp_global_lock is held upon entry/exit.
38280b57cec5SDimitry Andric static int last_index = 0;
38290b57cec5SDimitry Andric if ((last_index >= __kmp_num_locks_in_block) || (__kmp_lock_blocks == NULL)) {
38300b57cec5SDimitry Andric // Restart the index.
38310b57cec5SDimitry Andric last_index = 0;
38320b57cec5SDimitry Andric // Need to allocate a new block.
38330b57cec5SDimitry Andric KMP_DEBUG_ASSERT(__kmp_user_lock_size > 0);
38340b57cec5SDimitry Andric size_t space_for_locks = __kmp_user_lock_size * __kmp_num_locks_in_block;
38350b57cec5SDimitry Andric char *buffer =
38360b57cec5SDimitry Andric (char *)__kmp_allocate(space_for_locks + sizeof(kmp_block_of_locks));
38370b57cec5SDimitry Andric // Set up the new block.
38380b57cec5SDimitry Andric kmp_block_of_locks *new_block =
38390b57cec5SDimitry Andric (kmp_block_of_locks *)(&buffer[space_for_locks]);
38400b57cec5SDimitry Andric new_block->next_block = __kmp_lock_blocks;
38410b57cec5SDimitry Andric new_block->locks = (void *)buffer;
38420b57cec5SDimitry Andric // Publish the new block.
38430b57cec5SDimitry Andric KMP_MB();
38440b57cec5SDimitry Andric __kmp_lock_blocks = new_block;
38450b57cec5SDimitry Andric }
38460b57cec5SDimitry Andric kmp_user_lock_p ret = (kmp_user_lock_p)(&(
38470b57cec5SDimitry Andric ((char *)(__kmp_lock_blocks->locks))[last_index * __kmp_user_lock_size]));
38480b57cec5SDimitry Andric last_index++;
38490b57cec5SDimitry Andric return ret;
38500b57cec5SDimitry Andric }
38510b57cec5SDimitry Andric
38520b57cec5SDimitry Andric // Get memory for a lock. It may be freshly allocated memory or reused memory
38530b57cec5SDimitry Andric // from lock pool.
__kmp_user_lock_allocate(void ** user_lock,kmp_int32 gtid,kmp_lock_flags_t flags)38540b57cec5SDimitry Andric kmp_user_lock_p __kmp_user_lock_allocate(void **user_lock, kmp_int32 gtid,
38550b57cec5SDimitry Andric kmp_lock_flags_t flags) {
38560b57cec5SDimitry Andric kmp_user_lock_p lck;
38570b57cec5SDimitry Andric kmp_lock_index_t index;
38580b57cec5SDimitry Andric KMP_DEBUG_ASSERT(user_lock);
38590b57cec5SDimitry Andric
38600b57cec5SDimitry Andric __kmp_acquire_lock(&__kmp_global_lock, gtid);
38610b57cec5SDimitry Andric
38620b57cec5SDimitry Andric if (__kmp_lock_pool == NULL) {
38630b57cec5SDimitry Andric // Lock pool is empty. Allocate new memory.
38640b57cec5SDimitry Andric
38650b57cec5SDimitry Andric if (__kmp_num_locks_in_block <= 1) { // Tune this cutoff point.
38660b57cec5SDimitry Andric lck = (kmp_user_lock_p)__kmp_allocate(__kmp_user_lock_size);
38670b57cec5SDimitry Andric } else {
38680b57cec5SDimitry Andric lck = __kmp_lock_block_allocate();
38690b57cec5SDimitry Andric }
38700b57cec5SDimitry Andric
38710b57cec5SDimitry Andric // Insert lock in the table so that it can be freed in __kmp_cleanup,
38720b57cec5SDimitry Andric // and debugger has info on all allocated locks.
38730b57cec5SDimitry Andric index = __kmp_lock_table_insert(lck);
38740b57cec5SDimitry Andric } else {
38750b57cec5SDimitry Andric // Pick up lock from pool.
38760b57cec5SDimitry Andric lck = __kmp_lock_pool;
38770b57cec5SDimitry Andric index = __kmp_lock_pool->pool.index;
38780b57cec5SDimitry Andric __kmp_lock_pool = __kmp_lock_pool->pool.next;
38790b57cec5SDimitry Andric }
38800b57cec5SDimitry Andric
38810b57cec5SDimitry Andric // We could potentially differentiate between nested and regular locks
38820b57cec5SDimitry Andric // here, and do the lock table lookup for regular locks only.
38830b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *)) {
38840b57cec5SDimitry Andric *((kmp_lock_index_t *)user_lock) = index;
38850b57cec5SDimitry Andric } else {
38860b57cec5SDimitry Andric *((kmp_user_lock_p *)user_lock) = lck;
38870b57cec5SDimitry Andric }
38880b57cec5SDimitry Andric
38890b57cec5SDimitry Andric // mark the lock if it is critical section lock.
38900b57cec5SDimitry Andric __kmp_set_user_lock_flags(lck, flags);
38910b57cec5SDimitry Andric
38920b57cec5SDimitry Andric __kmp_release_lock(&__kmp_global_lock, gtid); // AC: TODO move this line upper
38930b57cec5SDimitry Andric
38940b57cec5SDimitry Andric return lck;
38950b57cec5SDimitry Andric }
38960b57cec5SDimitry Andric
38970b57cec5SDimitry Andric // Put lock's memory to pool for reusing.
__kmp_user_lock_free(void ** user_lock,kmp_int32 gtid,kmp_user_lock_p lck)38980b57cec5SDimitry Andric void __kmp_user_lock_free(void **user_lock, kmp_int32 gtid,
38990b57cec5SDimitry Andric kmp_user_lock_p lck) {
39000b57cec5SDimitry Andric KMP_DEBUG_ASSERT(user_lock != NULL);
39010b57cec5SDimitry Andric KMP_DEBUG_ASSERT(lck != NULL);
39020b57cec5SDimitry Andric
39030b57cec5SDimitry Andric __kmp_acquire_lock(&__kmp_global_lock, gtid);
39040b57cec5SDimitry Andric
39050b57cec5SDimitry Andric lck->pool.next = __kmp_lock_pool;
39060b57cec5SDimitry Andric __kmp_lock_pool = lck;
39070b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *)) {
39080b57cec5SDimitry Andric kmp_lock_index_t index = *((kmp_lock_index_t *)user_lock);
39090b57cec5SDimitry Andric KMP_DEBUG_ASSERT(0 < index && index <= __kmp_user_lock_table.used);
39100b57cec5SDimitry Andric lck->pool.index = index;
39110b57cec5SDimitry Andric }
39120b57cec5SDimitry Andric
39130b57cec5SDimitry Andric __kmp_release_lock(&__kmp_global_lock, gtid);
39140b57cec5SDimitry Andric }
39150b57cec5SDimitry Andric
__kmp_lookup_user_lock(void ** user_lock,char const * func)39160b57cec5SDimitry Andric kmp_user_lock_p __kmp_lookup_user_lock(void **user_lock, char const *func) {
39170b57cec5SDimitry Andric kmp_user_lock_p lck = NULL;
39180b57cec5SDimitry Andric
39190b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
39200b57cec5SDimitry Andric if (user_lock == NULL) {
39210b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
39220b57cec5SDimitry Andric }
39230b57cec5SDimitry Andric }
39240b57cec5SDimitry Andric
39250b57cec5SDimitry Andric if (OMP_LOCK_T_SIZE < sizeof(void *)) {
39260b57cec5SDimitry Andric kmp_lock_index_t index = *((kmp_lock_index_t *)user_lock);
39270b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
39280b57cec5SDimitry Andric if (!(0 < index && index < __kmp_user_lock_table.used)) {
39290b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
39300b57cec5SDimitry Andric }
39310b57cec5SDimitry Andric }
39320b57cec5SDimitry Andric KMP_DEBUG_ASSERT(0 < index && index < __kmp_user_lock_table.used);
39330b57cec5SDimitry Andric KMP_DEBUG_ASSERT(__kmp_user_lock_size > 0);
39340b57cec5SDimitry Andric lck = __kmp_user_lock_table.table[index];
39350b57cec5SDimitry Andric } else {
39360b57cec5SDimitry Andric lck = *((kmp_user_lock_p *)user_lock);
39370b57cec5SDimitry Andric }
39380b57cec5SDimitry Andric
39390b57cec5SDimitry Andric if (__kmp_env_consistency_check) {
39400b57cec5SDimitry Andric if (lck == NULL) {
39410b57cec5SDimitry Andric KMP_FATAL(LockIsUninitialized, func);
39420b57cec5SDimitry Andric }
39430b57cec5SDimitry Andric }
39440b57cec5SDimitry Andric
39450b57cec5SDimitry Andric return lck;
39460b57cec5SDimitry Andric }
39470b57cec5SDimitry Andric
__kmp_cleanup_user_locks(void)39480b57cec5SDimitry Andric void __kmp_cleanup_user_locks(void) {
39490b57cec5SDimitry Andric // Reset lock pool. Don't worry about lock in the pool--we will free them when
39500b57cec5SDimitry Andric // iterating through lock table (it includes all the locks, dead or alive).
39510b57cec5SDimitry Andric __kmp_lock_pool = NULL;
39520b57cec5SDimitry Andric
39530b57cec5SDimitry Andric #define IS_CRITICAL(lck) \
39540b57cec5SDimitry Andric ((__kmp_get_user_lock_flags_ != NULL) && \
39550b57cec5SDimitry Andric ((*__kmp_get_user_lock_flags_)(lck)&kmp_lf_critical_section))
39560b57cec5SDimitry Andric
39570b57cec5SDimitry Andric // Loop through lock table, free all locks.
39580b57cec5SDimitry Andric // Do not free item [0], it is reserved for lock tables list.
39590b57cec5SDimitry Andric //
39600b57cec5SDimitry Andric // FIXME - we are iterating through a list of (pointers to) objects of type
39610b57cec5SDimitry Andric // union kmp_user_lock, but we have no way of knowing whether the base type is
39620b57cec5SDimitry Andric // currently "pool" or whatever the global user lock type is.
39630b57cec5SDimitry Andric //
39640b57cec5SDimitry Andric // We are relying on the fact that for all of the user lock types
39650b57cec5SDimitry Andric // (except "tas"), the first field in the lock struct is the "initialized"
39660b57cec5SDimitry Andric // field, which is set to the address of the lock object itself when
39670b57cec5SDimitry Andric // the lock is initialized. When the union is of type "pool", the
39680b57cec5SDimitry Andric // first field is a pointer to the next object in the free list, which
39690b57cec5SDimitry Andric // will not be the same address as the object itself.
39700b57cec5SDimitry Andric //
39710b57cec5SDimitry Andric // This means that the check (*__kmp_is_user_lock_initialized_)(lck) will fail
39720b57cec5SDimitry Andric // for "pool" objects on the free list. This must happen as the "location"
39730b57cec5SDimitry Andric // field of real user locks overlaps the "index" field of "pool" objects.
39740b57cec5SDimitry Andric //
39750b57cec5SDimitry Andric // It would be better to run through the free list, and remove all "pool"
39760b57cec5SDimitry Andric // objects from the lock table before executing this loop. However,
39770b57cec5SDimitry Andric // "pool" objects do not always have their index field set (only on
39780b57cec5SDimitry Andric // lin_32e), and I don't want to search the lock table for the address
39790b57cec5SDimitry Andric // of every "pool" object on the free list.
39800b57cec5SDimitry Andric while (__kmp_user_lock_table.used > 1) {
39810b57cec5SDimitry Andric const ident *loc;
39820b57cec5SDimitry Andric
39830b57cec5SDimitry Andric // reduce __kmp_user_lock_table.used before freeing the lock,
39840b57cec5SDimitry Andric // so that state of locks is consistent
39850b57cec5SDimitry Andric kmp_user_lock_p lck =
39860b57cec5SDimitry Andric __kmp_user_lock_table.table[--__kmp_user_lock_table.used];
39870b57cec5SDimitry Andric
39880b57cec5SDimitry Andric if ((__kmp_is_user_lock_initialized_ != NULL) &&
39890b57cec5SDimitry Andric (*__kmp_is_user_lock_initialized_)(lck)) {
39900b57cec5SDimitry Andric // Issue a warning if: KMP_CONSISTENCY_CHECK AND lock is initialized AND
39910b57cec5SDimitry Andric // it is NOT a critical section (user is not responsible for destroying
39920b57cec5SDimitry Andric // criticals) AND we know source location to report.
39930b57cec5SDimitry Andric if (__kmp_env_consistency_check && (!IS_CRITICAL(lck)) &&
39940b57cec5SDimitry Andric ((loc = __kmp_get_user_lock_location(lck)) != NULL) &&
39950b57cec5SDimitry Andric (loc->psource != NULL)) {
3996e8d8bef9SDimitry Andric kmp_str_loc_t str_loc = __kmp_str_loc_init(loc->psource, false);
39970b57cec5SDimitry Andric KMP_WARNING(CnsLockNotDestroyed, str_loc.file, str_loc.line);
39980b57cec5SDimitry Andric __kmp_str_loc_free(&str_loc);
39990b57cec5SDimitry Andric }
40000b57cec5SDimitry Andric
40010b57cec5SDimitry Andric #ifdef KMP_DEBUG
40020b57cec5SDimitry Andric if (IS_CRITICAL(lck)) {
40030b57cec5SDimitry Andric KA_TRACE(
40040b57cec5SDimitry Andric 20,
40050b57cec5SDimitry Andric ("__kmp_cleanup_user_locks: free critical section lock %p (%p)\n",
40060b57cec5SDimitry Andric lck, *(void **)lck));
40070b57cec5SDimitry Andric } else {
40080b57cec5SDimitry Andric KA_TRACE(20, ("__kmp_cleanup_user_locks: free lock %p (%p)\n", lck,
40090b57cec5SDimitry Andric *(void **)lck));
40100b57cec5SDimitry Andric }
40110b57cec5SDimitry Andric #endif // KMP_DEBUG
40120b57cec5SDimitry Andric
40130b57cec5SDimitry Andric // Cleanup internal lock dynamic resources (for drdpa locks particularly).
40140b57cec5SDimitry Andric __kmp_destroy_user_lock(lck);
40150b57cec5SDimitry Andric }
40160b57cec5SDimitry Andric
40170b57cec5SDimitry Andric // Free the lock if block allocation of locks is not used.
40180b57cec5SDimitry Andric if (__kmp_lock_blocks == NULL) {
40190b57cec5SDimitry Andric __kmp_free(lck);
40200b57cec5SDimitry Andric }
40210b57cec5SDimitry Andric }
40220b57cec5SDimitry Andric
40230b57cec5SDimitry Andric #undef IS_CRITICAL
40240b57cec5SDimitry Andric
40250b57cec5SDimitry Andric // delete lock table(s).
40260b57cec5SDimitry Andric kmp_user_lock_p *table_ptr = __kmp_user_lock_table.table;
40270b57cec5SDimitry Andric __kmp_user_lock_table.table = NULL;
40280b57cec5SDimitry Andric __kmp_user_lock_table.allocated = 0;
40290b57cec5SDimitry Andric
40300b57cec5SDimitry Andric while (table_ptr != NULL) {
40310b57cec5SDimitry Andric // In the first element we saved the pointer to the previous
40320b57cec5SDimitry Andric // (smaller) lock table.
40330b57cec5SDimitry Andric kmp_user_lock_p *next = (kmp_user_lock_p *)(table_ptr[0]);
40340b57cec5SDimitry Andric __kmp_free(table_ptr);
40350b57cec5SDimitry Andric table_ptr = next;
40360b57cec5SDimitry Andric }
40370b57cec5SDimitry Andric
40380b57cec5SDimitry Andric // Free buffers allocated for blocks of locks.
40390b57cec5SDimitry Andric kmp_block_of_locks_t *block_ptr = __kmp_lock_blocks;
40400b57cec5SDimitry Andric __kmp_lock_blocks = NULL;
40410b57cec5SDimitry Andric
40420b57cec5SDimitry Andric while (block_ptr != NULL) {
40430b57cec5SDimitry Andric kmp_block_of_locks_t *next = block_ptr->next_block;
40440b57cec5SDimitry Andric __kmp_free(block_ptr->locks);
40450b57cec5SDimitry Andric // *block_ptr itself was allocated at the end of the locks vector.
40460b57cec5SDimitry Andric block_ptr = next;
40470b57cec5SDimitry Andric }
40480b57cec5SDimitry Andric
40490b57cec5SDimitry Andric TCW_4(__kmp_init_user_locks, FALSE);
40500b57cec5SDimitry Andric }
40510b57cec5SDimitry Andric
40520b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
4053