8231612: 100% cpu on arm32 in Service Thread

Reviewed-by: kbarrett, dsamersoff
This commit is contained in:
Aleksei Voitylov 2019-12-18 14:36:49 +03:00
parent 995fbebd81
commit f58a8cbed2

View File

@ -36,6 +36,7 @@
#include "metaprogramming/removePointer.hpp" #include "metaprogramming/removePointer.hpp"
#include "runtime/orderAccess.hpp" #include "runtime/orderAccess.hpp"
#include "utilities/align.hpp" #include "utilities/align.hpp"
#include "utilities/bytes.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
enum atomic_memory_order { enum atomic_memory_order {
@ -578,6 +579,8 @@ struct Atomic::PlatformCmpxchg {
// as a base class, requiring it be complete. The definition is later // as a base class, requiring it be complete. The definition is later
// in this file, near the other definitions related to cmpxchg. // in this file, near the other definitions related to cmpxchg.
struct Atomic::CmpxchgByteUsingInt { struct Atomic::CmpxchgByteUsingInt {
static uint8_t get_byte_in_int(uint32_t n, uint32_t idx);
static uint32_t set_byte_in_int(uint32_t n, uint8_t b, uint32_t idx);
template<typename T> template<typename T>
T operator()(T volatile* dest, T operator()(T volatile* dest,
T compare_value, T compare_value,
@ -845,6 +848,19 @@ inline T Atomic::cmpxchg_using_helper(Fn fn,
PrimitiveConversions::cast<Type>(compare_value))); PrimitiveConversions::cast<Type>(compare_value)));
} }
inline uint32_t Atomic::CmpxchgByteUsingInt::set_byte_in_int(uint32_t n,
uint8_t b,
uint32_t idx) {
int bitsIdx = BitsPerByte * idx;
return (n & ~(0xff << bitsIdx)) | (b << bitsIdx);
}
inline uint8_t Atomic::CmpxchgByteUsingInt::get_byte_in_int(uint32_t n,
uint32_t idx) {
int bitsIdx = BitsPerByte * idx;
return (uint8_t)(n >> bitsIdx);
}
template<typename T> template<typename T>
inline T Atomic::CmpxchgByteUsingInt::operator()(T volatile* dest, inline T Atomic::CmpxchgByteUsingInt::operator()(T volatile* dest,
T compare_value, T compare_value,
@ -856,20 +872,21 @@ inline T Atomic::CmpxchgByteUsingInt::operator()(T volatile* dest,
volatile uint32_t* aligned_dest volatile uint32_t* aligned_dest
= reinterpret_cast<volatile uint32_t*>(align_down(dest, sizeof(uint32_t))); = reinterpret_cast<volatile uint32_t*>(align_down(dest, sizeof(uint32_t)));
size_t offset = pointer_delta(dest, aligned_dest, 1); size_t offset = pointer_delta(dest, aligned_dest, 1);
uint32_t cur = *aligned_dest;
uint8_t* cur_as_bytes = reinterpret_cast<uint8_t*>(&cur); uint32_t idx = (Endian::NATIVE == Endian::BIG)
? (sizeof(uint32_t) - 1 - offset)
: offset;
// current value may not be what we are looking for, so force it // current value may not be what we are looking for, so force it
// to that value so the initial cmpxchg will fail if it is different // to that value so the initial cmpxchg will fail if it is different
cur_as_bytes[offset] = canon_compare_value; uint32_t cur = set_byte_in_int(Atomic::load(aligned_dest), canon_compare_value, idx);
// always execute a real cmpxchg so that we get the required memory // always execute a real cmpxchg so that we get the required memory
// barriers even on initial failure // barriers even on initial failure
do { do {
// value to swap in matches current value ... // value to swap in matches current value
uint32_t new_value = cur; // except for the one byte we want to update
// ... except for the one byte we want to update uint32_t new_value = set_byte_in_int(cur, canon_exchange_value, idx);
reinterpret_cast<uint8_t*>(&new_value)[offset] = canon_exchange_value;
uint32_t res = cmpxchg(aligned_dest, cur, new_value, order); uint32_t res = cmpxchg(aligned_dest, cur, new_value, order);
if (res == cur) break; // success if (res == cur) break; // success
@ -878,9 +895,9 @@ inline T Atomic::CmpxchgByteUsingInt::operator()(T volatile* dest,
// our view of the current int // our view of the current int
cur = res; cur = res;
// if our byte is still as cur we loop and try again // if our byte is still as cur we loop and try again
} while (cur_as_bytes[offset] == canon_compare_value); } while (get_byte_in_int(cur, idx) == canon_compare_value);
return PrimitiveConversions::cast<T>(cur_as_bytes[offset]); return PrimitiveConversions::cast<T>(get_byte_in_int(cur, idx));
} }
// Handle xchg for integral and enum types. // Handle xchg for integral and enum types.