1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stddef.h> 18#include <endian.h> 19 20#include "private/bionic_atomic_inline.h" 21#include "private/bionic_futex.h" 22 23// This file contains C++ ABI support functions for one time 24// constructors as defined in the "Run-time ABI for the ARM Architecture" 25// section 4.4.2 26// 27// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for 28// one time construction: 29// 30// ARM C++ ABI defines the LSB of guard variable should be tested 31// by compiler-generated code before calling __cxa_guard_acquire et al. 32// 33// The Itanium/x86 C++ ABI defines the low-order _byte_ should be 34// tested instead. 35// 36// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit 37// aligned for x86. 38// 39// Reference documentation: 40// 41// section 3.2.3 of ARM IHI 0041C (for ARM) 42// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86). 43// 44// There is no C++ ABI available for other ARCH. But the gcc source 45// shows all other ARCH follow the definition of Itanium/x86 C++ ABI. 46 47#if defined(__arm__) 48// The ARM C++ ABI mandates that guard variables are 32-bit aligned, 32-bit 49// values. The LSB is tested by the compiler-generated code before calling 50// __cxa_guard_acquire. 51union _guard_t { 52 int volatile state; 53 int32_t aligner; 54}; 55 56const static int ready = 0x1; 57const static int pending = 0x2; 58const static int waiting = 0x6; 59 60#else 61// The Itanium/x86 C++ ABI (used by all other architectures) mandates that 62// guard variables are 64-bit aligned, 64-bit values. The LSB is tested by 63// the compiler-generated code before calling __cxa_guard_acquire. 64union _guard_t { 65 int volatile state; 66 int64_t aligner; 67}; 68 69const static int ready = letoh32(0x1); 70const static int pending = letoh32(0x100); 71const static int waiting = letoh32(0x10000); 72#endif 73 74extern "C" int __cxa_guard_acquire(_guard_t* gv) { 75 // 0 -> pending, return 1 76 // pending -> waiting, wait and return 0 77 // waiting: untouched, wait and return 0 78 // ready: untouched, return 0 79 80retry: 81 if (__bionic_cmpxchg(0, pending, &gv->state) == 0) { 82 ANDROID_MEMBAR_FULL(); 83 return 1; 84 } 85 __bionic_cmpxchg(pending, waiting, &gv->state); // Indicate there is a waiter 86 __futex_wait(&gv->state, waiting, NULL); 87 88 if (gv->state != ready) { 89 // __cxa_guard_abort was called, let every thread try since there is no return code for this condition 90 goto retry; 91 } 92 93 ANDROID_MEMBAR_FULL(); 94 return 0; 95} 96 97extern "C" void __cxa_guard_release(_guard_t* gv) { 98 // pending -> ready 99 // waiting -> ready, and wake 100 101 ANDROID_MEMBAR_FULL(); 102 if (__bionic_cmpxchg(pending, ready, &gv->state) == 0) { 103 return; 104 } 105 106 gv->state = ready; 107 __futex_wake(&gv->state, 0x7fffffff); 108} 109 110extern "C" void __cxa_guard_abort(_guard_t* gv) { 111 ANDROID_MEMBAR_FULL(); 112 gv->state= 0; 113 __futex_wake(&gv->state, 0x7fffffff); 114} 115