The preprocessor was used to select a special implementation when building on AIX using XL C++ (strangely, not XL C). This code implemented `cmpxchgi()` by directly reading the old value and then calling `__compare_and_swap()`, an intrinsic that does not provide any sort of memory barrier guarantees. The return value was not used, and the value read prior to the `__compare_and_swap()` call was returned. There is no way that this code could provide the required semantics of the function and it causes observable data races and strange library failures in production under load. XL C/C++ for AIX has provided support for the GCC intrinsic used in the GCC/Clang cases since version 12.1 of the compiler. This version of the compiler is old enough that it doesn't warrant a version check. (The compiler was released 8-Jun-2012, maintenance ended 9-Jul-2019, and service ends 30-Apr-2020.) This change fixes all observed atomic issues and unifies XL C/C++ with GCC/Clang. Relevant XL C/C++ for AIX V12.1 documentation links: - [__compare_and_swap](https://www.ibm.com/support/knowledgecenter/en/SSGH3R_12.1.0/com.ibm.xlcpp121.aix.doc/compiler_ref/bif_compare_and_swap_compare_and_swaplp.html) - [__sync_val_compare_and_swap](https://www.ibm.com/support/knowledgecenter/en/SSGH3R_12.1.0/com.ibm.xlcpp121.aix.doc/compiler_ref/bif_gcc_atomic_val_comp_swap.html) PR-URL: https://github.com/libuv/libuv/pull/2455 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Richard Lau <riclau@uk.ibm.com>
60 lines
2.0 KiB
C
60 lines
2.0 KiB
C
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifndef UV_ATOMIC_OPS_H_
|
|
#define UV_ATOMIC_OPS_H_
|
|
|
|
#include "internal.h" /* UV_UNUSED */
|
|
|
|
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
|
#include <atomic.h>
|
|
#endif
|
|
|
|
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
|
|
UV_UNUSED(static void cpu_relax(void));
|
|
|
|
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
|
|
* issue full memory barriers.
|
|
*/
|
|
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
int out;
|
|
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
|
|
: "=a" (out), "+m" (*(volatile int*) ptr)
|
|
: "r" (newval), "0" (oldval)
|
|
: "memory");
|
|
return out;
|
|
#elif defined(__MVS__)
|
|
unsigned int op4;
|
|
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
|
|
(unsigned int*) ptr, *ptr, &op4))
|
|
return oldval;
|
|
else
|
|
return op4;
|
|
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
|
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
|
|
#else
|
|
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
|
#endif
|
|
}
|
|
|
|
UV_UNUSED(static void cpu_relax(void)) {
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
|
|
#endif
|
|
}
|
|
|
|
#endif /* UV_ATOMIC_OPS_H_ */
|