blob: 1eac3b1a5c403f5cd9174c42b84ce17eec03d21c [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2 * one_time_construction.cpp
3 *
4 * Copyright 2006 The Android Open Source Project
5 *
6 * This file contains C++ ABI support functions for one time
7 * constructors as defined in the "Run-time ABI for the ARM Architecture"
8 * section 4.4.2
9 */
10
11#include <stddef.h>
12#include <sys/atomics.h>
Fengwei Yinee18fb42012-03-28 17:25:17 +080013#include <endian.h>
David 'Digit' Turnerd4667802010-06-11 13:18:41 -070014#include <bionic_futex.h>
15#include <bionic_atomic_inline.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080016
Fengwei Yinee18fb42012-03-28 17:25:17 +080017// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for
18// one time construction:
19//
20// ARM C++ ABI defines the LSB of guard variable should be tested
21// by compiler-generated code before calling __cxa_guard_acquire et al.
22//
23// The Itanium/x86 C++ ABI defines the low-order _byte_ should be
24// tested instead.
25//
26// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit
27// aligned for x86.
28//
29// Reference documentation:
30//
31// section 3.2.3 of ARM IHI 0041C (for ARM)
32// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86).
33//
34// There is no C++ ABI available for other ARCH. But the gcc source
35// shows all other ARCH follow the definition of Itanium/x86 C++ ABI.
36
37
38#if defined(__arm__)
39// The ARM C++ ABI mandates that guard variable are
40// 32-bit aligned, 32-bit values. And only its LSB is tested by
41// the compiler-generated code before calling
42// __cxa_guard_acquire.
43//
44typedef union {
45 int volatile state;
46 int32_t aligner;
47} _guard_t;
48
49const static int ready = 0x1;
50const static int pending = 0x2;
51const static int waiting = 0x6;
52
53#else // GCC sources indicates all none-arm follow the same ABI
54// The Itanium/x86 C++ ABI mandates that guard variables
55// are 64-bit aligned, 64-bit values. Also, the least-significant
56// byte is tested by the compiler-generated code before, we calling
57// __cxa_guard_acquire. We can access it through the first
58// 32-bit word in the union below.
59//
60typedef union {
61 int volatile state;
62 int64_t aligner;
63} _guard_t;
64
65const static int ready = letoh32(0x1);
66const static int pending = letoh32(0x100);
67const static int waiting = letoh32(0x10000);
68#endif
69
70extern "C" int __cxa_guard_acquire(_guard_t* gv)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080071{
Fengwei Yinee18fb42012-03-28 17:25:17 +080072 // 0 -> pending, return 1
73 // pending -> waiting, wait and return 0
74 // waiting: untouched, wait and return 0
75 // ready: untouched, return 0
76
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080077retry:
Elliott Hughes762a4fe2012-04-16 14:40:26 -070078 if (__bionic_cmpxchg(0, pending, &gv->state) == 0) {
David 'Digit' Turnerd4667802010-06-11 13:18:41 -070079 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080080 return 1;
David 'Digit' Turnerd4667802010-06-11 13:18:41 -070081 }
Elliott Hughes762a4fe2012-04-16 14:40:26 -070082 __bionic_cmpxchg(pending, waiting, &gv->state); // Indicate there is a waiter
Fengwei Yinee18fb42012-03-28 17:25:17 +080083 __futex_wait(&gv->state, waiting, NULL);
David 'Digit' Turnerd4667802010-06-11 13:18:41 -070084
Fengwei Yinee18fb42012-03-28 17:25:17 +080085 if (gv->state != ready) // __cxa_guard_abort was called, let every thread try since there is no return code for this condition
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080086 goto retry;
David 'Digit' Turnerd4667802010-06-11 13:18:41 -070087
88 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080089 return 0;
90}
91
Fengwei Yinee18fb42012-03-28 17:25:17 +080092extern "C" void __cxa_guard_release(_guard_t* gv)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080093{
Fengwei Yinee18fb42012-03-28 17:25:17 +080094 // pending -> ready
95 // waiting -> ready, and wake
96
David 'Digit' Turnerd4667802010-06-11 13:18:41 -070097 ANDROID_MEMBAR_FULL();
Elliott Hughes762a4fe2012-04-16 14:40:26 -070098 if (__bionic_cmpxchg(pending, ready, &gv->state) == 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080099 return;
David 'Digit' Turnerd4667802010-06-11 13:18:41 -0700100 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800101
Fengwei Yinee18fb42012-03-28 17:25:17 +0800102 gv->state = ready;
103 __futex_wake(&gv->state, 0x7fffffff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800104}
105
Fengwei Yinee18fb42012-03-28 17:25:17 +0800106extern "C" void __cxa_guard_abort(_guard_t* gv)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800107{
David 'Digit' Turnerd4667802010-06-11 13:18:41 -0700108 ANDROID_MEMBAR_FULL();
Fengwei Yinee18fb42012-03-28 17:25:17 +0800109 gv->state= 0;
110 __futex_wake(&gv->state, 0x7fffffff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800111}