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