1 /* 2 * Copyright 2006 The Android Open Source Project 3 */ 4 5 #include <stddef.h> 6 #include <sys/atomics.h> 7 #include <endian.h> 8 #include <private/bionic_futex.h> 9 #include <private/bionic_atomic_inline.h> 10 11 // This file contains C++ ABI support functions for one time 12 // constructors as defined in the "Run-time ABI for the ARM Architecture" 13 // section 4.4.2 14 // 15 // ARM C++ ABI and Itanium/x86 C++ ABI has different definition for 16 // one time construction: 17 // 18 // ARM C++ ABI defines the LSB of guard variable should be tested 19 // by compiler-generated code before calling __cxa_guard_acquire et al. 20 // 21 // The Itanium/x86 C++ ABI defines the low-order _byte_ should be 22 // tested instead. 23 // 24 // Meanwhile, guard variable are 32bit aligned for ARM, and 64bit 25 // aligned for x86. 26 // 27 // Reference documentation: 28 // 29 // section 3.2.3 of ARM IHI 0041C (for ARM) 30 // section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86). 31 // 32 // There is no C++ ABI available for other ARCH. But the gcc source 33 // shows all other ARCH follow the definition of Itanium/x86 C++ ABI. 34 35 36 #if defined(__arm__) 37 // The ARM C++ ABI mandates that guard variable are 38 // 32-bit aligned, 32-bit values. And only its LSB is tested by 39 // the compiler-generated code before calling 40 // __cxa_guard_acquire. 41 // 42 typedef union { 43 int volatile state; 44 int32_t aligner; 45 } _guard_t; 46 47 const static int ready = 0x1; 48 const static int pending = 0x2; 49 const static int waiting = 0x6; 50 51 #else // GCC sources indicates all none-arm follow the same ABI 52 // The Itanium/x86 C++ ABI mandates that guard variables 53 // are 64-bit aligned, 64-bit values. Also, the least-significant 54 // byte is tested by the compiler-generated code before, we calling 55 // __cxa_guard_acquire. We can access it through the first 56 // 32-bit word in the union below. 57 // 58 typedef union { 59 int volatile state; 60 int64_t aligner; 61 } _guard_t; 62 63 const static int ready = letoh32(0x1); 64 const static int pending = letoh32(0x100); 65 const static int waiting = letoh32(0x10000); 66 #endif 67 68 extern "C" int __cxa_guard_acquire(_guard_t* gv) 69 { 70 // 0 -> pending, return 1 71 // pending -> waiting, wait and return 0 72 // waiting: untouched, wait and return 0 73 // ready: untouched, return 0 74 75 retry: 76 if (__bionic_cmpxchg(0, pending, &gv->state) == 0) { 77 ANDROID_MEMBAR_FULL(); 78 return 1; 79 } 80 __bionic_cmpxchg(pending, waiting, &gv->state); // Indicate there is a waiter 81 __futex_wait(&gv->state, waiting, NULL); 82 83 if (gv->state != ready) // __cxa_guard_abort was called, let every thread try since there is no return code for this condition 84 goto retry; 85 86 ANDROID_MEMBAR_FULL(); 87 return 0; 88 } 89 90 extern "C" void __cxa_guard_release(_guard_t* gv) 91 { 92 // pending -> ready 93 // waiting -> ready, and wake 94 95 ANDROID_MEMBAR_FULL(); 96 if (__bionic_cmpxchg(pending, ready, &gv->state) == 0) { 97 return; 98 } 99 100 gv->state = ready; 101 __futex_wake(&gv->state, 0x7fffffff); 102 } 103 104 extern "C" void __cxa_guard_abort(_guard_t* gv) 105 { 106 ANDROID_MEMBAR_FULL(); 107 gv->state= 0; 108 __futex_wake(&gv->state, 0x7fffffff); 109 } 110