1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker *
5*8d67ca89SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker * are met:
8*8d67ca89SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker * the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker * distribution.
14*8d67ca89SAndroid Build Coastguard Worker *
15*8d67ca89SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker */
28*8d67ca89SAndroid Build Coastguard Worker
29*8d67ca89SAndroid Build Coastguard Worker #include "atexit.h"
30*8d67ca89SAndroid Build Coastguard Worker
31*8d67ca89SAndroid Build Coastguard Worker #include <errno.h>
32*8d67ca89SAndroid Build Coastguard Worker #include <pthread.h>
33*8d67ca89SAndroid Build Coastguard Worker #include <stdint.h>
34*8d67ca89SAndroid Build Coastguard Worker #include <stdlib.h>
35*8d67ca89SAndroid Build Coastguard Worker #include <string.h>
36*8d67ca89SAndroid Build Coastguard Worker #include <sys/mman.h>
37*8d67ca89SAndroid Build Coastguard Worker #include <sys/param.h>
38*8d67ca89SAndroid Build Coastguard Worker #include <sys/prctl.h>
39*8d67ca89SAndroid Build Coastguard Worker
40*8d67ca89SAndroid Build Coastguard Worker #include <async_safe/CHECK.h>
41*8d67ca89SAndroid Build Coastguard Worker #include <async_safe/log.h>
42*8d67ca89SAndroid Build Coastguard Worker
43*8d67ca89SAndroid Build Coastguard Worker #include "platform/bionic/page.h"
44*8d67ca89SAndroid Build Coastguard Worker
45*8d67ca89SAndroid Build Coastguard Worker extern "C" void __libc_stdio_cleanup();
46*8d67ca89SAndroid Build Coastguard Worker extern "C" void __unregister_atfork(void* dso);
47*8d67ca89SAndroid Build Coastguard Worker
48*8d67ca89SAndroid Build Coastguard Worker namespace {
49*8d67ca89SAndroid Build Coastguard Worker
50*8d67ca89SAndroid Build Coastguard Worker struct AtexitEntry {
51*8d67ca89SAndroid Build Coastguard Worker void (*fn)(void*); // the __cxa_atexit callback
52*8d67ca89SAndroid Build Coastguard Worker void* arg; // argument for `fn` callback
53*8d67ca89SAndroid Build Coastguard Worker void* dso; // shared module handle
54*8d67ca89SAndroid Build Coastguard Worker };
55*8d67ca89SAndroid Build Coastguard Worker
56*8d67ca89SAndroid Build Coastguard Worker class AtexitArray {
57*8d67ca89SAndroid Build Coastguard Worker public:
size() const58*8d67ca89SAndroid Build Coastguard Worker size_t size() const { return size_; }
total_appends() const59*8d67ca89SAndroid Build Coastguard Worker uint64_t total_appends() const { return total_appends_; }
operator [](size_t idx) const60*8d67ca89SAndroid Build Coastguard Worker const AtexitEntry& operator[](size_t idx) const { return array_[idx]; }
61*8d67ca89SAndroid Build Coastguard Worker
62*8d67ca89SAndroid Build Coastguard Worker bool append_entry(const AtexitEntry& entry);
63*8d67ca89SAndroid Build Coastguard Worker AtexitEntry extract_entry(size_t idx);
64*8d67ca89SAndroid Build Coastguard Worker void recompact();
65*8d67ca89SAndroid Build Coastguard Worker
66*8d67ca89SAndroid Build Coastguard Worker private:
67*8d67ca89SAndroid Build Coastguard Worker AtexitEntry* array_;
68*8d67ca89SAndroid Build Coastguard Worker size_t size_;
69*8d67ca89SAndroid Build Coastguard Worker size_t extracted_count_;
70*8d67ca89SAndroid Build Coastguard Worker size_t capacity_;
71*8d67ca89SAndroid Build Coastguard Worker
72*8d67ca89SAndroid Build Coastguard Worker // An entry can be appended by a __cxa_finalize callback. Track the number of appends so we
73*8d67ca89SAndroid Build Coastguard Worker // restart concurrent __cxa_finalize passes.
74*8d67ca89SAndroid Build Coastguard Worker uint64_t total_appends_;
75*8d67ca89SAndroid Build Coastguard Worker
page_start_of_index(size_t idx)76*8d67ca89SAndroid Build Coastguard Worker static size_t page_start_of_index(size_t idx) { return page_start(idx * sizeof(AtexitEntry)); }
page_end_of_index(size_t idx)77*8d67ca89SAndroid Build Coastguard Worker static size_t page_end_of_index(size_t idx) { return page_end(idx * sizeof(AtexitEntry)); }
78*8d67ca89SAndroid Build Coastguard Worker
79*8d67ca89SAndroid Build Coastguard Worker // Recompact the array if it will save at least one page of memory at the end.
needs_recompaction() const80*8d67ca89SAndroid Build Coastguard Worker bool needs_recompaction() const {
81*8d67ca89SAndroid Build Coastguard Worker return page_end_of_index(size_ - extracted_count_) < page_end_of_index(size_);
82*8d67ca89SAndroid Build Coastguard Worker }
83*8d67ca89SAndroid Build Coastguard Worker
84*8d67ca89SAndroid Build Coastguard Worker void set_writable(bool writable, size_t start_idx, size_t num_entries);
85*8d67ca89SAndroid Build Coastguard Worker static bool next_capacity(size_t capacity, size_t* result);
86*8d67ca89SAndroid Build Coastguard Worker bool expand_capacity();
87*8d67ca89SAndroid Build Coastguard Worker };
88*8d67ca89SAndroid Build Coastguard Worker
89*8d67ca89SAndroid Build Coastguard Worker } // anonymous namespace
90*8d67ca89SAndroid Build Coastguard Worker
append_entry(const AtexitEntry & entry)91*8d67ca89SAndroid Build Coastguard Worker bool AtexitArray::append_entry(const AtexitEntry& entry) {
92*8d67ca89SAndroid Build Coastguard Worker if (size_ >= capacity_ && !expand_capacity()) return false;
93*8d67ca89SAndroid Build Coastguard Worker
94*8d67ca89SAndroid Build Coastguard Worker size_t idx = size_++;
95*8d67ca89SAndroid Build Coastguard Worker
96*8d67ca89SAndroid Build Coastguard Worker set_writable(true, idx, 1);
97*8d67ca89SAndroid Build Coastguard Worker array_[idx] = entry;
98*8d67ca89SAndroid Build Coastguard Worker ++total_appends_;
99*8d67ca89SAndroid Build Coastguard Worker set_writable(false, idx, 1);
100*8d67ca89SAndroid Build Coastguard Worker
101*8d67ca89SAndroid Build Coastguard Worker return true;
102*8d67ca89SAndroid Build Coastguard Worker }
103*8d67ca89SAndroid Build Coastguard Worker
104*8d67ca89SAndroid Build Coastguard Worker // Extract an entry and return it.
extract_entry(size_t idx)105*8d67ca89SAndroid Build Coastguard Worker AtexitEntry AtexitArray::extract_entry(size_t idx) {
106*8d67ca89SAndroid Build Coastguard Worker AtexitEntry result = array_[idx];
107*8d67ca89SAndroid Build Coastguard Worker
108*8d67ca89SAndroid Build Coastguard Worker set_writable(true, idx, 1);
109*8d67ca89SAndroid Build Coastguard Worker array_[idx] = {};
110*8d67ca89SAndroid Build Coastguard Worker ++extracted_count_;
111*8d67ca89SAndroid Build Coastguard Worker set_writable(false, idx, 1);
112*8d67ca89SAndroid Build Coastguard Worker
113*8d67ca89SAndroid Build Coastguard Worker return result;
114*8d67ca89SAndroid Build Coastguard Worker }
115*8d67ca89SAndroid Build Coastguard Worker
recompact()116*8d67ca89SAndroid Build Coastguard Worker void AtexitArray::recompact() {
117*8d67ca89SAndroid Build Coastguard Worker if (!needs_recompaction()) return;
118*8d67ca89SAndroid Build Coastguard Worker
119*8d67ca89SAndroid Build Coastguard Worker set_writable(true, 0, size_);
120*8d67ca89SAndroid Build Coastguard Worker
121*8d67ca89SAndroid Build Coastguard Worker // Optimization: quickly skip over the initial non-null entries.
122*8d67ca89SAndroid Build Coastguard Worker size_t src = 0, dst = 0;
123*8d67ca89SAndroid Build Coastguard Worker while (src < size_ && array_[src].fn != nullptr) {
124*8d67ca89SAndroid Build Coastguard Worker ++src;
125*8d67ca89SAndroid Build Coastguard Worker ++dst;
126*8d67ca89SAndroid Build Coastguard Worker }
127*8d67ca89SAndroid Build Coastguard Worker
128*8d67ca89SAndroid Build Coastguard Worker // Shift the non-null entries forward, and zero out the removed entries at the end of the array.
129*8d67ca89SAndroid Build Coastguard Worker for (; src < size_; ++src) {
130*8d67ca89SAndroid Build Coastguard Worker const AtexitEntry entry = array_[src];
131*8d67ca89SAndroid Build Coastguard Worker array_[src] = {};
132*8d67ca89SAndroid Build Coastguard Worker if (entry.fn != nullptr) {
133*8d67ca89SAndroid Build Coastguard Worker array_[dst++] = entry;
134*8d67ca89SAndroid Build Coastguard Worker }
135*8d67ca89SAndroid Build Coastguard Worker }
136*8d67ca89SAndroid Build Coastguard Worker
137*8d67ca89SAndroid Build Coastguard Worker // If the table uses fewer pages, clean the pages at the end.
138*8d67ca89SAndroid Build Coastguard Worker size_t old_bytes = page_end_of_index(size_);
139*8d67ca89SAndroid Build Coastguard Worker size_t new_bytes = page_end_of_index(dst);
140*8d67ca89SAndroid Build Coastguard Worker if (new_bytes < old_bytes) {
141*8d67ca89SAndroid Build Coastguard Worker madvise(reinterpret_cast<char*>(array_) + new_bytes, old_bytes - new_bytes, MADV_DONTNEED);
142*8d67ca89SAndroid Build Coastguard Worker }
143*8d67ca89SAndroid Build Coastguard Worker
144*8d67ca89SAndroid Build Coastguard Worker set_writable(false, 0, size_);
145*8d67ca89SAndroid Build Coastguard Worker
146*8d67ca89SAndroid Build Coastguard Worker size_ = dst;
147*8d67ca89SAndroid Build Coastguard Worker extracted_count_ = 0;
148*8d67ca89SAndroid Build Coastguard Worker }
149*8d67ca89SAndroid Build Coastguard Worker
150*8d67ca89SAndroid Build Coastguard Worker // Use mprotect to make the array writable or read-only. Returns true on success. Making the array
151*8d67ca89SAndroid Build Coastguard Worker // read-only could protect against either unintentional or malicious corruption of the array.
set_writable(bool writable,size_t start_idx,size_t num_entries)152*8d67ca89SAndroid Build Coastguard Worker void AtexitArray::set_writable(bool writable, size_t start_idx, size_t num_entries) {
153*8d67ca89SAndroid Build Coastguard Worker if (array_ == nullptr) return;
154*8d67ca89SAndroid Build Coastguard Worker
155*8d67ca89SAndroid Build Coastguard Worker const size_t start_byte = page_start_of_index(start_idx);
156*8d67ca89SAndroid Build Coastguard Worker const size_t stop_byte = page_end_of_index(start_idx + num_entries);
157*8d67ca89SAndroid Build Coastguard Worker const size_t byte_len = stop_byte - start_byte;
158*8d67ca89SAndroid Build Coastguard Worker
159*8d67ca89SAndroid Build Coastguard Worker const int prot = PROT_READ | (writable ? PROT_WRITE : 0);
160*8d67ca89SAndroid Build Coastguard Worker if (mprotect(reinterpret_cast<char*>(array_) + start_byte, byte_len, prot) != 0) {
161*8d67ca89SAndroid Build Coastguard Worker async_safe_fatal("mprotect failed on atexit array: %m");
162*8d67ca89SAndroid Build Coastguard Worker }
163*8d67ca89SAndroid Build Coastguard Worker }
164*8d67ca89SAndroid Build Coastguard Worker
165*8d67ca89SAndroid Build Coastguard Worker // Approximately double the capacity. Returns true if successful (no overflow). AtexitEntry is
166*8d67ca89SAndroid Build Coastguard Worker // smaller than a page, but this function should still be correct even if AtexitEntry were larger
167*8d67ca89SAndroid Build Coastguard Worker // than one.
next_capacity(size_t capacity,size_t * result)168*8d67ca89SAndroid Build Coastguard Worker bool AtexitArray::next_capacity(size_t capacity, size_t* result) {
169*8d67ca89SAndroid Build Coastguard Worker if (capacity == 0) {
170*8d67ca89SAndroid Build Coastguard Worker *result = page_end(sizeof(AtexitEntry)) / sizeof(AtexitEntry);
171*8d67ca89SAndroid Build Coastguard Worker return true;
172*8d67ca89SAndroid Build Coastguard Worker }
173*8d67ca89SAndroid Build Coastguard Worker size_t num_bytes;
174*8d67ca89SAndroid Build Coastguard Worker if (__builtin_mul_overflow(page_end_of_index(capacity), 2, &num_bytes)) {
175*8d67ca89SAndroid Build Coastguard Worker async_safe_format_log(ANDROID_LOG_WARN, "libc", "__cxa_atexit: capacity calculation overflow");
176*8d67ca89SAndroid Build Coastguard Worker return false;
177*8d67ca89SAndroid Build Coastguard Worker }
178*8d67ca89SAndroid Build Coastguard Worker *result = num_bytes / sizeof(AtexitEntry);
179*8d67ca89SAndroid Build Coastguard Worker return true;
180*8d67ca89SAndroid Build Coastguard Worker }
181*8d67ca89SAndroid Build Coastguard Worker
expand_capacity()182*8d67ca89SAndroid Build Coastguard Worker bool AtexitArray::expand_capacity() {
183*8d67ca89SAndroid Build Coastguard Worker size_t new_capacity;
184*8d67ca89SAndroid Build Coastguard Worker if (!next_capacity(capacity_, &new_capacity)) return false;
185*8d67ca89SAndroid Build Coastguard Worker const size_t new_capacity_bytes = page_end_of_index(new_capacity);
186*8d67ca89SAndroid Build Coastguard Worker
187*8d67ca89SAndroid Build Coastguard Worker set_writable(true, 0, capacity_);
188*8d67ca89SAndroid Build Coastguard Worker
189*8d67ca89SAndroid Build Coastguard Worker bool result = false;
190*8d67ca89SAndroid Build Coastguard Worker void* new_pages;
191*8d67ca89SAndroid Build Coastguard Worker if (array_ == nullptr) {
192*8d67ca89SAndroid Build Coastguard Worker new_pages = mmap(nullptr, new_capacity_bytes, PROT_READ | PROT_WRITE,
193*8d67ca89SAndroid Build Coastguard Worker MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
194*8d67ca89SAndroid Build Coastguard Worker } else {
195*8d67ca89SAndroid Build Coastguard Worker // mremap fails if the source buffer crosses a boundary between two VMAs. When a single array
196*8d67ca89SAndroid Build Coastguard Worker // element is modified, the kernel should split then rejoin the buffer's VMA.
197*8d67ca89SAndroid Build Coastguard Worker new_pages = mremap(array_, page_end_of_index(capacity_), new_capacity_bytes, MREMAP_MAYMOVE);
198*8d67ca89SAndroid Build Coastguard Worker }
199*8d67ca89SAndroid Build Coastguard Worker if (new_pages == MAP_FAILED) {
200*8d67ca89SAndroid Build Coastguard Worker async_safe_format_log(ANDROID_LOG_WARN, "libc",
201*8d67ca89SAndroid Build Coastguard Worker "__cxa_atexit: mmap/mremap failed to allocate %zu bytes: %m",
202*8d67ca89SAndroid Build Coastguard Worker new_capacity_bytes);
203*8d67ca89SAndroid Build Coastguard Worker } else {
204*8d67ca89SAndroid Build Coastguard Worker result = true;
205*8d67ca89SAndroid Build Coastguard Worker prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, new_pages, new_capacity_bytes, "atexit handlers");
206*8d67ca89SAndroid Build Coastguard Worker array_ = static_cast<AtexitEntry*>(new_pages);
207*8d67ca89SAndroid Build Coastguard Worker capacity_ = new_capacity;
208*8d67ca89SAndroid Build Coastguard Worker }
209*8d67ca89SAndroid Build Coastguard Worker set_writable(false, 0, capacity_);
210*8d67ca89SAndroid Build Coastguard Worker return result;
211*8d67ca89SAndroid Build Coastguard Worker }
212*8d67ca89SAndroid Build Coastguard Worker
213*8d67ca89SAndroid Build Coastguard Worker static AtexitArray g_array;
214*8d67ca89SAndroid Build Coastguard Worker static pthread_mutex_t g_atexit_lock = PTHREAD_MUTEX_INITIALIZER;
215*8d67ca89SAndroid Build Coastguard Worker
atexit_lock()216*8d67ca89SAndroid Build Coastguard Worker static inline void atexit_lock() {
217*8d67ca89SAndroid Build Coastguard Worker pthread_mutex_lock(&g_atexit_lock);
218*8d67ca89SAndroid Build Coastguard Worker }
219*8d67ca89SAndroid Build Coastguard Worker
atexit_unlock()220*8d67ca89SAndroid Build Coastguard Worker static inline void atexit_unlock() {
221*8d67ca89SAndroid Build Coastguard Worker pthread_mutex_unlock(&g_atexit_lock);
222*8d67ca89SAndroid Build Coastguard Worker }
223*8d67ca89SAndroid Build Coastguard Worker
224*8d67ca89SAndroid Build Coastguard Worker // Register a function to be called either when a library is unloaded (dso != nullptr), or when the
225*8d67ca89SAndroid Build Coastguard Worker // program exits (dso == nullptr). The `dso` argument is typically the address of a hidden
226*8d67ca89SAndroid Build Coastguard Worker // __dso_handle variable. This function is also used as the backend for the atexit function.
227*8d67ca89SAndroid Build Coastguard Worker //
228*8d67ca89SAndroid Build Coastguard Worker // See https://itanium-cxx-abi.github.io/cxx-abi/abi.html#dso-dtor.
229*8d67ca89SAndroid Build Coastguard Worker //
__cxa_atexit(void (* func)(void *),void * arg,void * dso)230*8d67ca89SAndroid Build Coastguard Worker int __cxa_atexit(void (*func)(void*), void* arg, void* dso) {
231*8d67ca89SAndroid Build Coastguard Worker int result = -1;
232*8d67ca89SAndroid Build Coastguard Worker
233*8d67ca89SAndroid Build Coastguard Worker if (func != nullptr) {
234*8d67ca89SAndroid Build Coastguard Worker atexit_lock();
235*8d67ca89SAndroid Build Coastguard Worker if (g_array.append_entry({.fn = func, .arg = arg, .dso = dso})) {
236*8d67ca89SAndroid Build Coastguard Worker result = 0;
237*8d67ca89SAndroid Build Coastguard Worker }
238*8d67ca89SAndroid Build Coastguard Worker atexit_unlock();
239*8d67ca89SAndroid Build Coastguard Worker }
240*8d67ca89SAndroid Build Coastguard Worker
241*8d67ca89SAndroid Build Coastguard Worker return result;
242*8d67ca89SAndroid Build Coastguard Worker }
243*8d67ca89SAndroid Build Coastguard Worker
__cxa_finalize(void * dso)244*8d67ca89SAndroid Build Coastguard Worker void __cxa_finalize(void* dso) {
245*8d67ca89SAndroid Build Coastguard Worker atexit_lock();
246*8d67ca89SAndroid Build Coastguard Worker
247*8d67ca89SAndroid Build Coastguard Worker static uint32_t call_depth = 0;
248*8d67ca89SAndroid Build Coastguard Worker ++call_depth;
249*8d67ca89SAndroid Build Coastguard Worker
250*8d67ca89SAndroid Build Coastguard Worker restart:
251*8d67ca89SAndroid Build Coastguard Worker const uint64_t total_appends = g_array.total_appends();
252*8d67ca89SAndroid Build Coastguard Worker
253*8d67ca89SAndroid Build Coastguard Worker for (ssize_t i = g_array.size() - 1; i >= 0; --i) {
254*8d67ca89SAndroid Build Coastguard Worker if (g_array[i].fn == nullptr || (dso != nullptr && g_array[i].dso != dso)) continue;
255*8d67ca89SAndroid Build Coastguard Worker
256*8d67ca89SAndroid Build Coastguard Worker // Clear the entry in the array because its DSO handle will become invalid, and to avoid calling
257*8d67ca89SAndroid Build Coastguard Worker // an entry again if __cxa_finalize is called recursively.
258*8d67ca89SAndroid Build Coastguard Worker const AtexitEntry entry = g_array.extract_entry(i);
259*8d67ca89SAndroid Build Coastguard Worker
260*8d67ca89SAndroid Build Coastguard Worker atexit_unlock();
261*8d67ca89SAndroid Build Coastguard Worker entry.fn(entry.arg);
262*8d67ca89SAndroid Build Coastguard Worker atexit_lock();
263*8d67ca89SAndroid Build Coastguard Worker
264*8d67ca89SAndroid Build Coastguard Worker if (g_array.total_appends() != total_appends) goto restart;
265*8d67ca89SAndroid Build Coastguard Worker }
266*8d67ca89SAndroid Build Coastguard Worker
267*8d67ca89SAndroid Build Coastguard Worker // Avoid recompaction on recursive calls because it's unnecessary and would require earlier,
268*8d67ca89SAndroid Build Coastguard Worker // concurrent __cxa_finalize calls to restart. Skip recompaction on program exit too
269*8d67ca89SAndroid Build Coastguard Worker // (dso == nullptr), because the memory will be reclaimed soon anyway.
270*8d67ca89SAndroid Build Coastguard Worker --call_depth;
271*8d67ca89SAndroid Build Coastguard Worker if (call_depth == 0 && dso != nullptr) {
272*8d67ca89SAndroid Build Coastguard Worker g_array.recompact();
273*8d67ca89SAndroid Build Coastguard Worker }
274*8d67ca89SAndroid Build Coastguard Worker
275*8d67ca89SAndroid Build Coastguard Worker atexit_unlock();
276*8d67ca89SAndroid Build Coastguard Worker
277*8d67ca89SAndroid Build Coastguard Worker if (dso != nullptr) {
278*8d67ca89SAndroid Build Coastguard Worker __unregister_atfork(dso);
279*8d67ca89SAndroid Build Coastguard Worker } else {
280*8d67ca89SAndroid Build Coastguard Worker // If called via exit(), flush output of all open files.
281*8d67ca89SAndroid Build Coastguard Worker __libc_stdio_cleanup();
282*8d67ca89SAndroid Build Coastguard Worker }
283*8d67ca89SAndroid Build Coastguard Worker }
284