/***************************************************************************** Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ /**************************************************//** @file include/os0atomics.ic The interface to the operating system synchronization primitives. Created 2012-09-23 Sunny Bains (Split from include/os0sync.ic) *******************************************************/ #ifdef _WIN32 #include /* Use inline functions to make 64 and 32 bit versions of windows atomic functions so that typecasts are evaluated at compile time. Take advantage that lint is either __int64 or long int and windows atomic functions work on __int64 and LONG */ /**********************************************************//** Atomic compare and exchange of unsigned integers. @return value found before the exchange. If it is not equal to old_value the exchange did not happen. */ UNIV_INLINE lint win_cmp_and_xchg_lint( /*==================*/ volatile lint* ptr, /*!< in/out: source/destination */ lint new_val, /*!< in: exchange value */ lint old_val) /*!< in: value to compare to */ { # ifdef _WIN64 return(InterlockedCompareExchange64(ptr, new_val, old_val)); # else return(InterlockedCompareExchange(ptr, new_val, old_val)); # endif /* _WIN64 */ } /**********************************************************//** Atomic addition of signed integers. @return Initial value of the variable pointed to by ptr */ UNIV_INLINE lint win_xchg_and_add( /*=============*/ volatile lint* ptr, /*!< in/out: address of destination */ lint val) /*!< in: number to be added */ { #ifdef _WIN64 return(InterlockedExchangeAdd64(ptr, val)); #else return(InterlockedExchangeAdd(ptr, val)); #endif /* _WIN64 */ } /**********************************************************//** Atomic compare and exchange of unsigned integers. @return value found before the exchange. If it is not equal to old_value the exchange did not happen. */ UNIV_INLINE ulint win_cmp_and_xchg_ulint( /*===================*/ volatile ulint* ptr, /*!< in/out: source/destination */ ulint new_val, /*!< in: exchange value */ ulint old_val) /*!< in: value to compare to */ { return((ulint) win_cmp_and_xchg_lint( (volatile lint*) ptr, (lint) new_val, (lint) old_val)); } /**********************************************************//** Atomic compare and exchange of 32-bit unsigned integers. @return value found before the exchange. If it is not equal to old_value the exchange did not happen. */ UNIV_INLINE DWORD win_cmp_and_xchg_dword( /*===================*/ volatile DWORD* ptr, /*!< in/out: source/destination */ DWORD new_val, /*!< in: exchange value */ DWORD old_val) /*!< in: value to compare to */ { ut_ad(sizeof(DWORD) == sizeof(LONG)); /* We assume this. */ return(InterlockedCompareExchange( (volatile LONG*) ptr, (LONG) new_val, (LONG) old_val)); } /** Do an atomic test and set. @param[in,out] ptr Memory location to set @param[in] new_val new value @return old value of memory location. */ UNIV_INLINE lock_word_t os_atomic_test_and_set( volatile lock_word_t* ptr, lock_word_t new_val) { return(InterlockedExchange(ptr, new_val)); } /** Do an atomic compare and set @param[in,out] ptr Memory location to set @param[in] old_val old value to compare @param[in] new_val new value to set @return the value of ptr before the operation. */ UNIV_INLINE lock_word_t os_atomic_val_compare_and_swap( volatile lock_word_t* ptr, lock_word_t old_val, lock_word_t new_val) { return(static_cast(win_cmp_and_xchg_lint( reinterpret_cast(ptr), static_cast(new_val), static_cast(old_val)))); } #elif defined(HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE) /** Do an atomic test and set. @param[in,out] ptr Memory location to set @param[in] new_val new value @return old value of memory location. */ UNIV_INLINE lock_word_t os_atomic_test_and_set( volatile lock_word_t* ptr, lock_word_t new_val) { lock_word_t ret; /* Silence a compiler warning about unused ptr. */ (void) ptr; #if defined(__powerpc__) || defined(__aarch64__) __atomic_exchange(ptr, &new_val, &ret, __ATOMIC_SEQ_CST); #else __atomic_exchange(ptr, &new_val, &ret, __ATOMIC_RELEASE); #endif return(ret); } /** Do an atomic compare and set @param[in,out] ptr Memory location to set @param[in] old_val old value to compare @param[in] new_val new value to set @return the value of ptr before the operation. */ UNIV_INLINE lock_word_t os_atomic_val_compare_and_swap( volatile lock_word_t* ptr, lock_word_t old_val, lock_word_t new_val) { /* Silence a compiler warning about unused ptr. */ (void) ptr; #if defined(__powerpc__) || defined(__aarch64__) __atomic_compare_exchange(ptr, &old_val, &new_val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); #else __atomic_compare_exchange(ptr, &old_val, &new_val, false, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE); #endif return(old_val); } #elif defined(IB_STRONG_MEMORY_MODEL) /** Do an atomic test and set. @param[in,out] ptr Memory location to set @param[in] new_val new value @return old value of memory location. */ UNIV_INLINE lock_word_t os_atomic_test_and_set( volatile lock_word_t* ptr, lock_word_t new_val) { return(__sync_lock_test_and_set(ptr, new_val)); } /** Do an atomic compare and set @param[in,out] ptr Memory location to set @param[in] old_val old value to compare @param[in] new_val new value to set @return the value of ptr before the operation. */ UNIV_INLINE lock_word_t os_atomic_val_compare_and_swap( volatile lock_word_t* ptr, lock_word_t old_val, lock_word_t new_val) { return(__sync_val_compare_and_swap(ptr, old_val, new_val)); } #else #error "Unsupported platform" #endif /* _WIN32 */