Merge "Add a thread-properties API (Based on proposal at https://sourceware.org/glibc/wiki/ThreadPropertiesAPI)" am: d4d7efc1f8
Original change: https://android-review.googlesource.com/c/platform/bionic/+/1360925 Change-Id: I984cdfc8e5e0273ece8dba4fa82de824f40cd2d9
This commit is contained in:
commit
eb1a99cbfb
15 changed files with 536 additions and 1 deletions
|
@ -1238,6 +1238,7 @@ cc_library_static {
|
|||
"bionic/pthread_setname_np.cpp",
|
||||
"bionic/pthread_setschedparam.cpp",
|
||||
"bionic/pthread_spinlock.cpp",
|
||||
"bionic/sys_thread_properties.cpp",
|
||||
|
||||
// The following implementations depend on pthread data or implementation,
|
||||
// so we can't include them in libc_ndk.a.
|
||||
|
|
|
@ -394,6 +394,26 @@ void BionicAllocator::free(void* ptr) {
|
|||
}
|
||||
}
|
||||
|
||||
size_t BionicAllocator::get_chunk_size(void* ptr) {
|
||||
if (ptr == nullptr) return 0;
|
||||
|
||||
page_info* info = get_page_info_unchecked(ptr);
|
||||
if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) {
|
||||
// Invalid pointer (mismatched signature)
|
||||
return 0;
|
||||
}
|
||||
if (info->type == kLargeObject) {
|
||||
return info->allocated_size - (static_cast<char*>(ptr) - reinterpret_cast<char*>(info));
|
||||
}
|
||||
|
||||
BionicSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
|
||||
if (allocator != info->allocator_addr) {
|
||||
// Invalid pointer.
|
||||
return 0;
|
||||
}
|
||||
return allocator->get_block_size();
|
||||
}
|
||||
|
||||
BionicSmallObjectAllocator* BionicAllocator::get_small_object_allocator(uint32_t type) {
|
||||
if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) {
|
||||
async_safe_fatal("invalid type: %u", type);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "private/bionic_elf_tls.h"
|
||||
|
||||
#include <async_safe/CHECK.h>
|
||||
#include <async_safe/log.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
@ -269,6 +270,12 @@ static void update_tls_dtv(bionic_tcb* tcb) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (modules.on_destruction_cb != nullptr) {
|
||||
void* dtls_begin = dtv->modules[i];
|
||||
void* dtls_end =
|
||||
static_cast<void*>(static_cast<char*>(dtls_begin) + allocator.get_chunk_size(dtls_begin));
|
||||
modules.on_destruction_cb(dtls_begin, dtls_end);
|
||||
}
|
||||
allocator.free(dtv->modules[i]);
|
||||
dtv->modules[i] = nullptr;
|
||||
}
|
||||
|
@ -297,6 +304,12 @@ __attribute__((noinline)) static void* tls_get_addr_slow_path(const TlsIndex* ti
|
|||
memcpy(mod_ptr, segment.init_ptr, segment.init_size);
|
||||
}
|
||||
dtv->modules[module_idx] = mod_ptr;
|
||||
|
||||
// Reports the allocation to the listener, if any.
|
||||
if (modules.on_creation_cb != nullptr) {
|
||||
modules.on_creation_cb(mod_ptr,
|
||||
static_cast<void*>(static_cast<char*>(mod_ptr) + segment.size));
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<char*>(mod_ptr) + ti->offset;
|
||||
|
@ -351,6 +364,14 @@ void __free_dynamic_tls(bionic_tcb* tcb) {
|
|||
// This module's TLS memory is allocated statically, so don't free it here.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (modules.on_destruction_cb != nullptr) {
|
||||
void* dtls_begin = dtv->modules[i];
|
||||
void* dtls_end =
|
||||
static_cast<void*>(static_cast<char*>(dtls_begin) + allocator.get_chunk_size(dtls_begin));
|
||||
modules.on_destruction_cb(dtls_begin, dtls_end);
|
||||
}
|
||||
|
||||
allocator.free(dtv->modules[i]);
|
||||
}
|
||||
|
||||
|
@ -364,3 +385,22 @@ void __free_dynamic_tls(bionic_tcb* tcb) {
|
|||
// Clear the DTV slot. The DTV must not be used again with this thread.
|
||||
tcb->tls_slot(TLS_SLOT_DTV) = nullptr;
|
||||
}
|
||||
|
||||
// Invokes all the registered thread_exit callbacks, if any.
|
||||
void __notify_thread_exit_callbacks() {
|
||||
TlsModules& modules = __libc_shared_globals()->tls_modules;
|
||||
if (modules.first_thread_exit_callback == nullptr) {
|
||||
// If there is no first_thread_exit_callback, there shouldn't be a tail.
|
||||
CHECK(modules.thread_exit_callback_tail_node == nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Callbacks are supposed to be invoked in the reverse order
|
||||
// in which they were registered.
|
||||
CallbackHolder* node = modules.thread_exit_callback_tail_node;
|
||||
while (node != nullptr) {
|
||||
node->cb();
|
||||
node = node->prev;
|
||||
}
|
||||
modules.first_thread_exit_callback();
|
||||
}
|
||||
|
|
|
@ -147,6 +147,7 @@ static void layout_static_tls(KernelArgumentBlock& args) {
|
|||
mod.first_generation = kTlsGenerationFirst;
|
||||
|
||||
modules.module_count = 1;
|
||||
modules.static_module_count = 1;
|
||||
modules.module_table = &mod;
|
||||
} else {
|
||||
layout.reserve_exe_segment_and_tcb(nullptr, progname);
|
||||
|
|
|
@ -112,7 +112,6 @@ void pthread_exit(void* return_value) {
|
|||
munmap(thread->shadow_call_stack_guard_region, SCS_GUARD_REGION_SIZE);
|
||||
#endif
|
||||
|
||||
// Free the ELF TLS DTV and all dynamically-allocated ELF TLS memory.
|
||||
__free_dynamic_tls(__get_bionic_tcb());
|
||||
|
||||
if (old_state == THREAD_DETACHED) {
|
||||
|
@ -128,6 +127,7 @@ void pthread_exit(void* return_value) {
|
|||
if (thread->mmap_size != 0) {
|
||||
// We need to free mapped space for detached threads when they exit.
|
||||
// That's not something we can do in C.
|
||||
__notify_thread_exit_callbacks();
|
||||
__hwasan_thread_exit();
|
||||
_exit_with_stack_teardown(thread->mmap_base, thread->mmap_size);
|
||||
}
|
||||
|
@ -135,6 +135,8 @@ void pthread_exit(void* return_value) {
|
|||
|
||||
// No need to free mapped space. Either there was no space mapped, or it is left for
|
||||
// the pthread_join caller to clean up.
|
||||
__notify_thread_exit_callbacks();
|
||||
__hwasan_thread_exit();
|
||||
|
||||
__exit(0);
|
||||
}
|
||||
|
|
133
libc/bionic/sys_thread_properties.cpp
Normal file
133
libc/bionic/sys_thread_properties.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/thread_properties.h>
|
||||
|
||||
#include <async_safe/CHECK.h>
|
||||
#include <async_safe/log.h>
|
||||
|
||||
#include <elf.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "private/bionic_elf_tls.h"
|
||||
#include "private/bionic_globals.h"
|
||||
#include "private/bionic_tls.h"
|
||||
#include "pthread_internal.h"
|
||||
|
||||
void __libc_get_static_tls_bounds(void** stls_begin, void** stls_end) {
|
||||
const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
|
||||
*stls_begin = reinterpret_cast<char*>(__get_bionic_tcb()) - layout.offset_bionic_tcb();
|
||||
*stls_end = reinterpret_cast<char*>(*stls_begin) + layout.size();
|
||||
}
|
||||
|
||||
void __libc_register_thread_exit_callback(thread_exit_cb_t cb) {
|
||||
TlsModules& modules = __libc_shared_globals()->tls_modules;
|
||||
|
||||
if (modules.first_thread_exit_callback == nullptr) {
|
||||
modules.first_thread_exit_callback = cb;
|
||||
return;
|
||||
};
|
||||
|
||||
BionicAllocator& allocator = __libc_shared_globals()->tls_allocator;
|
||||
CallbackHolder* new_node =
|
||||
reinterpret_cast<CallbackHolder*>(allocator.alloc(sizeof(CallbackHolder)));
|
||||
new_node->cb = cb;
|
||||
new_node->prev = modules.thread_exit_callback_tail_node;
|
||||
modules.thread_exit_callback_tail_node = new_node;
|
||||
}
|
||||
|
||||
static inline __always_inline bionic_tcb* __get_bionic_tcb_for_thread(pid_t tid) {
|
||||
// If tid is same as self, then we don't need ptrace.
|
||||
if (gettid() == tid) return __get_bionic_tcb();
|
||||
|
||||
// Find the thread-pointer register for the given thread.
|
||||
void** tp_reg = nullptr;
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
struct user_regs_struct regs;
|
||||
struct iovec pt_iov = {
|
||||
.iov_base = ®s,
|
||||
.iov_len = sizeof(regs),
|
||||
};
|
||||
if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
|
||||
#if defined(__x86_64__)
|
||||
tp_reg = reinterpret_cast<void**>(regs.fs);
|
||||
#elif defined(__i386__)
|
||||
tp_reg = reinterpret_cast<void**>(regs.xgs);
|
||||
#endif
|
||||
}
|
||||
#elif defined(__aarch64__) || defined(__arm__)
|
||||
uint64_t reg;
|
||||
struct iovec pt_iov {
|
||||
.iov_base = ®, .iov_len = sizeof(reg),
|
||||
};
|
||||
|
||||
if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) == 0) {
|
||||
tp_reg = reinterpret_cast<void**>(reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tp_reg == nullptr) {
|
||||
async_safe_write_log(ANDROID_LOG_FATAL, "libc",
|
||||
"__get_bionic_tcb_for_thread failed to read thread register.");
|
||||
}
|
||||
|
||||
return reinterpret_cast<bionic_tcb*>(&tp_reg[MIN_TLS_SLOT]);
|
||||
}
|
||||
|
||||
void __libc_iterate_dynamic_tls(pid_t tid,
|
||||
void (*cb)(void* __dynamic_tls_begin, void* __dynamic_tls_end,
|
||||
size_t __dso_id, void* __arg),
|
||||
void* arg) {
|
||||
TlsModules& modules = __libc_shared_globals()->tls_modules;
|
||||
bionic_tcb* const tcb = __get_bionic_tcb_for_thread(tid);
|
||||
TlsDtv* const dtv = __get_tcb_dtv(tcb);
|
||||
BionicAllocator& allocator = __libc_shared_globals()->tls_allocator;
|
||||
|
||||
for (size_t i = modules.static_module_count; i < dtv->count; ++i) {
|
||||
void* dtls_begin = dtv->modules[i];
|
||||
if (dtls_begin == nullptr) continue;
|
||||
void* dtls_end =
|
||||
static_cast<void*>(static_cast<char*>(dtls_begin) + allocator.get_chunk_size(dtls_begin));
|
||||
size_t dso_id = __tls_module_idx_to_id(i);
|
||||
|
||||
cb(dtls_begin, dtls_end, dso_id, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void __libc_register_dynamic_tls_listeners(dtls_listener_t on_creation,
|
||||
dtls_listener_t on_destruction) {
|
||||
TlsModules& tls_modules = __libc_shared_globals()->tls_modules;
|
||||
tls_modules.on_creation_cb = on_creation;
|
||||
tls_modules.on_destruction_cb = on_destruction;
|
||||
}
|
97
libc/include/sys/thread_properties.h
Normal file
97
libc/include/sys/thread_properties.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file thread_properties.h
|
||||
* @brief Thread properties API.
|
||||
*
|
||||
* https://sourceware.org/glibc/wiki/ThreadPropertiesAPI
|
||||
* API for querying various properties of the current thread, used mostly by
|
||||
* the sanitizers.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Gets the bounds of static TLS for the current thread.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*/
|
||||
void __libc_get_static_tls_bounds(void** __static_tls_begin,
|
||||
void** __static_tls_end) __INTRODUCED_IN(31);
|
||||
|
||||
|
||||
/**
|
||||
* Registers callback to be called right before the thread is dead.
|
||||
* The callbacks are chained, they are called in the order opposite to the order
|
||||
* they were registered.
|
||||
*
|
||||
* The callbacks must be registered only before any threads were created.
|
||||
* No signals may arrive during the calls to these callbacks.
|
||||
* The callbacks may not access the thread's dynamic TLS because they will have
|
||||
* been freed by the time these callbacks are invoked.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*/
|
||||
void __libc_register_thread_exit_callback(void (*__cb)(void)) __INTRODUCED_IN(31);
|
||||
|
||||
/**
|
||||
* Iterates over all dynamic TLS chunks for the given thread.
|
||||
* The thread should have been suspended. It is undefined-behaviour if there is concurrent
|
||||
* modification of the target thread's dynamic TLS.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*/
|
||||
void __libc_iterate_dynamic_tls(pid_t __tid,
|
||||
void (*__cb)(void* __dynamic_tls_begin,
|
||||
void* __dynamic_tls_end,
|
||||
size_t __dso_id,
|
||||
void* __arg),
|
||||
void* __arg) __INTRODUCED_IN(31);
|
||||
|
||||
/**
|
||||
* Register on_creation and on_destruction callbacks, which will be called after a dynamic
|
||||
* TLS creation and before a dynamic TLS destruction, respectively.
|
||||
*
|
||||
* Available since API level 31.
|
||||
*/
|
||||
void __libc_register_dynamic_tls_listeners(
|
||||
void (*__on_creation)(void* __dynamic_tls_begin,
|
||||
void* __dynamic_tls_end),
|
||||
void (*__on_destruction)(void* __dynamic_tls_begin,
|
||||
void* __dynamic_tls_end)) __INTRODUCED_IN(31);
|
||||
|
||||
__END_DECLS
|
|
@ -1554,6 +1554,10 @@ LIBC_S { # introduced=S
|
|||
global:
|
||||
ffsl;
|
||||
ffsll;
|
||||
__libc_get_static_tls_bounds;
|
||||
__libc_register_thread_exit_callback;
|
||||
__libc_iterate_dynamic_tls;
|
||||
__libc_register_dynamic_tls_listeners;
|
||||
} LIBC_R;
|
||||
|
||||
LIBC_PRIVATE {
|
||||
|
|
|
@ -110,6 +110,11 @@ class BionicAllocator {
|
|||
// Note that this implementation of realloc never shrinks allocation
|
||||
void* realloc(void* ptr, size_t size);
|
||||
void free(void* ptr);
|
||||
|
||||
// Returns the size of the given allocated heap chunk, if it is valid.
|
||||
// Otherwise, this may return 0 or cause a segfault if the pointer is invalid.
|
||||
size_t get_chunk_size(void* ptr);
|
||||
|
||||
private:
|
||||
void* alloc_mmap(size_t align, size_t size);
|
||||
inline void* alloc_impl(size_t align, size_t size);
|
||||
|
|
|
@ -111,6 +111,18 @@ struct TlsModule {
|
|||
void* soinfo_ptr = nullptr;
|
||||
};
|
||||
|
||||
// Signature of the callbacks that will be called after DTLS creation and
|
||||
// before DTLS destruction.
|
||||
typedef void (*dtls_listener_t)(void* dynamic_tls_begin, void* dynamic_tls_end);
|
||||
|
||||
// Signature of the thread-exit callbacks.
|
||||
typedef void (*thread_exit_cb_t)(void);
|
||||
|
||||
struct CallbackHolder {
|
||||
thread_exit_cb_t cb;
|
||||
CallbackHolder* prev;
|
||||
};
|
||||
|
||||
// Table of the ELF TLS modules. Either the dynamic linker or the static
|
||||
// initialization code prepares this table, and it's then used during thread
|
||||
// creation and for dynamic TLS lookups.
|
||||
|
@ -128,7 +140,20 @@ struct TlsModules {
|
|||
// Pointer to a block of TlsModule objects. The first module has ID 1 and
|
||||
// is stored at index 0 in this table.
|
||||
size_t module_count = 0;
|
||||
size_t static_module_count = 0;
|
||||
TlsModule* module_table = nullptr;
|
||||
|
||||
// Callback to be invoked after a dynamic TLS allocation.
|
||||
dtls_listener_t on_creation_cb = nullptr;
|
||||
|
||||
// Callback to be invoked before a dynamic TLS deallocation.
|
||||
dtls_listener_t on_destruction_cb = nullptr;
|
||||
|
||||
// The first thread-exit callback; inlined to avoid allocation.
|
||||
thread_exit_cb_t first_thread_exit_callback = nullptr;
|
||||
|
||||
// The additional callbacks, if any.
|
||||
CallbackHolder* thread_exit_callback_tail_node = nullptr;
|
||||
};
|
||||
|
||||
void __init_static_tls(void* static_tls);
|
||||
|
@ -175,3 +200,4 @@ extern "C" void* TLS_GET_ADDR(const TlsIndex* ti) TLS_GET_ADDR_CCONV;
|
|||
|
||||
struct bionic_tcb;
|
||||
void __free_dynamic_tls(bionic_tcb* tcb);
|
||||
void __notify_thread_exit_callbacks();
|
||||
|
|
|
@ -128,6 +128,8 @@ void linker_setup_exe_static_tls(const char* progname) {
|
|||
void linker_finalize_static_tls() {
|
||||
g_static_tls_finished = true;
|
||||
__libc_shared_globals()->static_tls_layout.finish_layout();
|
||||
TlsModules& modules = __libc_shared_globals()->tls_modules;
|
||||
modules.static_module_count = modules.module_count;
|
||||
}
|
||||
|
||||
void register_soinfo_tls(soinfo* si) {
|
||||
|
|
|
@ -79,6 +79,22 @@ cc_test_library {
|
|||
shared_libs: ["libtest_elftls_shared_var"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "thread_exit_cb_helper.cpp",
|
||||
defaults: ["bionic_testlib_defaults"],
|
||||
srcs: ["thread_exit_cb_helper.cpp"],
|
||||
cflags: ["-fno-emulated-tls"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "tls_properties_helper",
|
||||
defaults: ["bionic_testlib_defaults"],
|
||||
srcs: ["tls_properties_helper.cpp"],
|
||||
cflags: ["-fno-emulated-tls"],
|
||||
shared_libs: ["libtest_elftls_shared_var"],
|
||||
}
|
||||
|
||||
|
||||
cc_test_library {
|
||||
name: "libtest_elftls_dynamic_filler_1",
|
||||
defaults: ["bionic_testlib_defaults"],
|
||||
|
|
66
tests/libs/thread_exit_cb_helper.cpp
Normal file
66
tests/libs/thread_exit_cb_helper.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Prevent tests from being compiled with glibc because thread_properties.h
|
||||
// only exists in Bionic.
|
||||
#if defined(__BIONIC__)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/thread_properties.h>
|
||||
|
||||
// Helper binary for testing thread_exit_cb registration.
|
||||
|
||||
void exit_cb_1() {
|
||||
printf("exit_cb_1 called ");
|
||||
}
|
||||
|
||||
void exit_cb_2() {
|
||||
printf("exit_cb_2 called ");
|
||||
}
|
||||
|
||||
void exit_cb_3() {
|
||||
printf("exit_cb_3 called");
|
||||
}
|
||||
|
||||
void test_register_thread_exit_cb() {
|
||||
// Register the exit-cb in reverse order (3,2,1)
|
||||
// so that they'd be called in 1,2,3 order.
|
||||
__libc_register_thread_exit_callback(&exit_cb_3);
|
||||
__libc_register_thread_exit_callback(&exit_cb_2);
|
||||
__libc_register_thread_exit_callback(&exit_cb_1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_register_thread_exit_cb();
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
#endif // __BIONIC__
|
75
tests/libs/tls_properties_helper.cpp
Normal file
75
tests/libs/tls_properties_helper.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Prevent tests from being compiled with glibc because thread_properties.h
|
||||
// only exists in Bionic.
|
||||
#if defined(__BIONIC__)
|
||||
|
||||
#include <sys/thread_properties.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h> // for gettid
|
||||
|
||||
// Helper binary to use TLS-related functions in thread_properties
|
||||
|
||||
// Tests __get_static_tls_bound.
|
||||
void test_static_tls_bounds() {
|
||||
void* start_addr;
|
||||
void* end_addr;
|
||||
|
||||
__libc_get_static_tls_bounds(reinterpret_cast<void**>(&start_addr),
|
||||
reinterpret_cast<void**>(&end_addr));
|
||||
printf("done_get_static_tls_bounds\n");
|
||||
}
|
||||
|
||||
// Tests iterate_dynamic tls chunks.
|
||||
// Export a var from the shared so.
|
||||
__thread char large_tls_var[4 * 1024 * 1024];
|
||||
void test_iter_tls() {
|
||||
void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
|
||||
|
||||
int i = 0;
|
||||
auto cb = [&](void* dtls_begin, void* dtls_end, size_t dso_id, void* arg) {
|
||||
printf("iterate_cb i = %d\n", i++);
|
||||
};
|
||||
__libc_iterate_dynamic_tls(gettid(), cb, nullptr);
|
||||
printf("done_iterate_dynamic_tls\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_static_tls_bounds();
|
||||
test_iter_tls();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
#endif // __BIONIC__
|
47
tests/sys_thread_properties_test.cpp
Normal file
47
tests/sys_thread_properties_test.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "gtest_globals.h"
|
||||
#include "utils.h"
|
||||
|
||||
TEST(thread_properties_test, iterate_dts) {
|
||||
#if defined(__BIONIC__)
|
||||
const char expected_out[] =
|
||||
"got test_static_tls_bounds\niterate_cb i = 0\ndone_iterate_dynamic_tls\n";
|
||||
std::string helper = GetTestLibRoot() + "tls_properties_helper/tls_properties_helper";
|
||||
chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
|
||||
|
||||
ExecTestHelper eth;
|
||||
eth.SetArgs({helper.c_str(), nullptr});
|
||||
eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, expected_out);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(thread_properties_test, thread_exit_cb) {
|
||||
#if defined(__BIONIC__)
|
||||
// tests/libs/thread_exit_cb_helper.cpp
|
||||
const char expected_out[] = "exit_cb_1 called exit_cb_2 called exit_cb_3 called";
|
||||
std::string helper = GetTestLibRoot() + "thread_exit_cb_helper/thread_exit_cb_helper";
|
||||
chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
|
||||
|
||||
ExecTestHelper eth;
|
||||
eth.SetArgs({helper.c_str(), nullptr});
|
||||
eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, expected_out);
|
||||
|
||||
#endif
|
||||
}
|
Loading…
Reference in a new issue