11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright 2006 The Android Open Source Project 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stddef.h> 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/atomics.h> 7ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin#include <endian.h> 852d6233296ec84eb5b58fcbf7bc9da4b96a943aaElliott Hughes#include <private/bionic_futex.h> 952d6233296ec84eb5b58fcbf7bc9da4b96a943aaElliott Hughes#include <private/bionic_atomic_inline.h> 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 11387d4b7de9af2afd0c37a895ff9d012eb1f66156Elliott Hughes// This file contains C++ ABI support functions for one time 12387d4b7de9af2afd0c37a895ff9d012eb1f66156Elliott Hughes// constructors as defined in the "Run-time ABI for the ARM Architecture" 13387d4b7de9af2afd0c37a895ff9d012eb1f66156Elliott Hughes// section 4.4.2 14387d4b7de9af2afd0c37a895ff9d012eb1f66156Elliott Hughes// 15ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for 16ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// one time construction: 17ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 18ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// ARM C++ ABI defines the LSB of guard variable should be tested 19ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// by compiler-generated code before calling __cxa_guard_acquire et al. 20ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 21ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// The Itanium/x86 C++ ABI defines the low-order _byte_ should be 22ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// tested instead. 23ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 24ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit 25ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// aligned for x86. 26ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 27ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// Reference documentation: 28ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 29ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// section 3.2.3 of ARM IHI 0041C (for ARM) 30ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86). 31ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 32ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// There is no C++ ABI available for other ARCH. But the gcc source 33ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// shows all other ARCH follow the definition of Itanium/x86 C++ ABI. 34ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 35ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 36ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin#if defined(__arm__) 37ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// The ARM C++ ABI mandates that guard variable are 38ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 32-bit aligned, 32-bit values. And only its LSB is tested by 39ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// the compiler-generated code before calling 40ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// __cxa_guard_acquire. 41ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 42ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yintypedef union { 43ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin int volatile state; 44ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin int32_t aligner; 45ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin} _guard_t; 46ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 47ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinconst static int ready = 0x1; 48ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinconst static int pending = 0x2; 49ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinconst static int waiting = 0x6; 50ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 51ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin#else // GCC sources indicates all none-arm follow the same ABI 52ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// The Itanium/x86 C++ ABI mandates that guard variables 53ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// are 64-bit aligned, 64-bit values. Also, the least-significant 54ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// byte is tested by the compiler-generated code before, we calling 55ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// __cxa_guard_acquire. We can access it through the first 56ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 32-bit word in the union below. 57ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin// 58ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yintypedef union { 59ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin int volatile state; 60ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin int64_t aligner; 61ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin} _guard_t; 62ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 63ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinconst static int ready = letoh32(0x1); 64ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinconst static int pending = letoh32(0x100); 65ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinconst static int waiting = letoh32(0x10000); 66ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin#endif 67ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 68ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinextern "C" int __cxa_guard_acquire(_guard_t* gv) 691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 70ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin // 0 -> pending, return 1 71ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin // pending -> waiting, wait and return 0 72ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin // waiting: untouched, wait and return 0 73ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin // ready: untouched, return 0 74ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectretry: 76762a4fe2eed6a36b14d3b378c2974ad355d97d54Elliott Hughes if (__bionic_cmpxchg(0, pending, &gv->state) == 0) { 77d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner ANDROID_MEMBAR_FULL(); 781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 1; 79d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner } 80762a4fe2eed6a36b14d3b378c2974ad355d97d54Elliott Hughes __bionic_cmpxchg(pending, waiting, &gv->state); // Indicate there is a waiter 81ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin __futex_wait(&gv->state, waiting, NULL); 82d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner 83ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin if (gv->state != ready) // __cxa_guard_abort was called, let every thread try since there is no return code for this condition 841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project goto retry; 85d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner 86d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner ANDROID_MEMBAR_FULL(); 871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 90ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinextern "C" void __cxa_guard_release(_guard_t* gv) 911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 92ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin // pending -> ready 93ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin // waiting -> ready, and wake 94ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin 95d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner ANDROID_MEMBAR_FULL(); 96762a4fe2eed6a36b14d3b378c2974ad355d97d54Elliott Hughes if (__bionic_cmpxchg(pending, ready, &gv->state) == 0) { 971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return; 98d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner } 991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 100ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin gv->state = ready; 101ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin __futex_wake(&gv->state, 0x7fffffff); 1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 104ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yinextern "C" void __cxa_guard_abort(_guard_t* gv) 1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 106d466780c7cedb41edcf13f28ad900556c6aaa5b2David 'Digit' Turner ANDROID_MEMBAR_FULL(); 107ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin gv->state= 0; 108ee18fb4aacc9b67b397a0b000dda6e350ad5b3f0Fengwei Yin __futex_wake(&gv->state, 0x7fffffff); 1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 110