Name stack+tls VMAs with PR_SET_VMA_ANON_NAME

Bionic creates a single thread mapping to hold a thread's stack and static
TLS memory. Use PR_SET_VMA_ANON_NAME to name this region
"stack_and_tls:tid". dumpsys meminfo can report this region as "Stack"
memory.

The main thread's memory is instead named stack_and_tls:main, and the VMA
is renamed to stack_and_tls:main in a post-fork child.

For the main thread, and threads using pthread_attr_setstack, Bionic still
creates the stack_and_tls mapping, but it only has TLS memory in it.

Bug: http://b/134795155
Test: run "dumpsys meminfo" and verify that this CL increases the reported
  stack memory usage from about 4MB to 21MB.
Change-Id: Id1f39ff083329e83426130b4ef94222ffacb90ae
Merged-In: Id1f39ff083329e83426130b4ef94222ffacb90ae
This commit is contained in:
Ryan Prichard 2019-06-17 17:57:19 -07:00
parent 9cf76012aa
commit 03cef383ba
4 changed files with 39 additions and 0 deletions

View File

@ -135,8 +135,11 @@ extern "C" void __libc_init_main_thread_final() {
main_thread.mmap_base = mapping.mmap_base;
main_thread.mmap_size = mapping.mmap_size;
main_thread.mmap_base_unguarded = mapping.mmap_base_unguarded;
main_thread.mmap_size_unguarded = mapping.mmap_size_unguarded;
__set_tls(&new_tcb->tls_slot(0));
__set_stack_and_tls_vma_name(true);
__free_temp_bionic_tls(temp_tls);
}

View File

@ -55,6 +55,10 @@ int fork() {
// fork, close all of their fds blindly, and then exec.
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED);
// Reset the stack_and_tls VMA name so it doesn't end with a tid from the
// parent process.
__set_stack_and_tls_vma_name(true);
__bionic_atfork_run_child();
} else {
__bionic_atfork_run_parent();

View File

@ -254,6 +254,8 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
ThreadMapping result = {};
result.mmap_base = space;
result.mmap_size = mmap_size;
result.mmap_base_unguarded = space + stack_guard_size;
result.mmap_size_unguarded = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE;
result.static_tls = space + mmap_size - PTHREAD_GUARD_SIZE - layout.size();
result.stack_base = space;
result.stack_top = result.static_tls;
@ -315,12 +317,33 @@ static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** chi
thread->attr = *attr;
thread->mmap_base = mapping.mmap_base;
thread->mmap_size = mapping.mmap_size;
thread->mmap_base_unguarded = mapping.mmap_base_unguarded;
thread->mmap_size_unguarded = mapping.mmap_size_unguarded;
*tcbp = tcb;
*child_stack = stack_top;
return 0;
}
void __set_stack_and_tls_vma_name(bool is_main_thread) {
// Name the thread's stack-and-tls area to help with debugging. This mapped area also includes
// static TLS data, which is typically a few pages (e.g. bionic_tls).
pthread_internal_t* thread = __get_thread();
const char* name;
if (is_main_thread) {
name = "stack_and_tls:main";
} else {
// The kernel doesn't copy the name string, but this variable will last at least as long as the
// mapped area. The mapped area's VMAs are unmapped with a single call to munmap.
auto& name_buffer = thread->vma_name_buffer;
static_assert(arraysize(name_buffer) >= arraysize("stack_and_tls:") + 11 + 1);
async_safe_format_buffer(name_buffer, arraysize(name_buffer), "stack_and_tls:%d", thread->tid);
name = name_buffer;
}
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->mmap_base_unguarded, thread->mmap_size_unguarded,
name);
}
__attribute__((no_sanitize("hwaddress")))
static int __pthread_start(void* arg) {
pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
@ -333,6 +356,7 @@ static int __pthread_start(void* arg) {
// accesses previously made by the creating thread are visible to us.
thread->startup_handshake_lock.lock();
__set_stack_and_tls_vma_name(false);
__init_additional_stacks(thread);
void* result = thread->start_routine(thread->start_routine_arg);

View File

@ -129,6 +129,11 @@ class pthread_internal_t {
void* mmap_base;
size_t mmap_size;
// The location of the VMA to label as the thread's stack_and_tls.
void* mmap_base_unguarded;
size_t mmap_size_unguarded;
char vma_name_buffer[32];
thread_local_dtor* thread_local_dtors;
/*
@ -147,6 +152,8 @@ class pthread_internal_t {
struct ThreadMapping {
char* mmap_base;
size_t mmap_size;
char* mmap_base_unguarded;
size_t mmap_size_unguarded;
char* static_tls;
char* stack_base;
@ -162,6 +169,7 @@ __LIBC_HIDDEN__ void __free_temp_bionic_tls(bionic_tls* tls);
__LIBC_HIDDEN__ void __init_additional_stacks(pthread_internal_t*);
__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread);
__LIBC_HIDDEN__ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size);
__LIBC_HIDDEN__ void __set_stack_and_tls_vma_name(bool is_main_thread);
__LIBC_HIDDEN__ pthread_t __pthread_internal_add(pthread_internal_t* thread);
__LIBC_HIDDEN__ pthread_internal_t* __pthread_internal_find(pthread_t pthread_id, const char* caller);