Merge "Add tests for dynamic ELF TLS"
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index bac3d88..6182ed8 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -82,7 +82,7 @@
     return;
   }
 
-  TEMP_FAILURE_RETRY(write(trace_marker_fd, "E", 1));
+  TEMP_FAILURE_RETRY(write(trace_marker_fd, "E|", 2));
 }
 
 ScopedTrace::ScopedTrace(const char* message) : called_end_(false) {
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index d1aa1ea..fc65e15 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -562,13 +562,7 @@
   }
 }
 
-static void* LoadSharedLibrary(const char* shared_lib, const char* prefix, MallocDispatch* dispatch_table) {
-  void* impl_handle = dlopen(shared_lib, RTLD_NOW | RTLD_LOCAL);
-  if (impl_handle == nullptr) {
-    error_log("%s: Unable to open shared library %s: %s", getprogname(), shared_lib, dlerror());
-    return nullptr;
-  }
-
+static bool InitSharedLibrary(void* impl_handle, const char* shared_lib, const char* prefix, MallocDispatch* dispatch_table) {
   static constexpr const char* names[] = {
     "initialize",
     "finalize",
@@ -583,48 +577,61 @@
     g_functions[i] = dlsym(impl_handle, symbol);
     if (g_functions[i] == nullptr) {
       error_log("%s: %s routine not found in %s", getprogname(), symbol, shared_lib);
-      dlclose(impl_handle);
       ClearGlobalFunctions();
-      return nullptr;
+      return false;
     }
   }
 
   if (!InitMallocFunctions(impl_handle, dispatch_table, prefix)) {
-    dlclose(impl_handle);
     ClearGlobalFunctions();
+    return false;
+  }
+  return true;
+}
+
+static void* LoadSharedLibrary(const char* shared_lib, const char* prefix, MallocDispatch* dispatch_table) {
+  void* impl_handle = dlopen(shared_lib, RTLD_NOW | RTLD_LOCAL);
+  if (impl_handle == nullptr) {
+    error_log("%s: Unable to open shared library %s: %s", getprogname(), shared_lib, dlerror());
     return nullptr;
   }
 
+  if (!InitSharedLibrary(impl_handle, shared_lib, prefix, dispatch_table)) {
+    dlclose(impl_handle);
+    impl_handle = nullptr;
+  }
+
   return impl_handle;
 }
 
 // A function pointer to heapprofds init function. Used to re-initialize
 // heapprofd. This will start a new profiling session and tear down the old
 // one in case it is still active.
-static _Atomic init_func_t g_heapprofd_init_func = nullptr;
+static _Atomic (void*) g_heapprofd_handle = nullptr;
 
 static void install_hooks(libc_globals* globals, const char* options,
                           const char* prefix, const char* shared_lib) {
-  init_func_t init_func = atomic_load(&g_heapprofd_init_func);
-  if (init_func != nullptr) {
-    init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options);
-    info_log("%s: malloc %s re-enabled", getprogname(), prefix);
-    return;
-  }
-
   MallocDispatch dispatch_table;
-  void* impl_handle = LoadSharedLibrary(shared_lib, prefix, &dispatch_table);
-  if (impl_handle == nullptr) {
-    return;
+
+  void* impl_handle = atomic_load(&g_heapprofd_handle);
+  if (impl_handle != nullptr) {
+    if (!InitSharedLibrary(impl_handle, shared_lib, prefix, &dispatch_table)) {
+      return;
+    }
+  } else {
+    impl_handle = LoadSharedLibrary(shared_lib, prefix, &dispatch_table);
+    if (impl_handle == nullptr) {
+      return;
+    }
   }
-  init_func = reinterpret_cast<init_func_t>(g_functions[FUNC_INITIALIZE]);
+  init_func_t init_func = reinterpret_cast<init_func_t>(g_functions[FUNC_INITIALIZE]);
   if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options)) {
+    error_log("%s: failed to enable malloc %s", getprogname(), prefix);
     dlclose(impl_handle);
     ClearGlobalFunctions();
     return;
   }
 
-  atomic_store(&g_heapprofd_init_func, init_func);
   // We assign free  first explicitly to prevent the case where we observe a
   // alloc, but miss the corresponding free because of initialization order.
   //
@@ -636,6 +643,7 @@
   // _Atomic. Assigning to an _Atomic is an atomic_store operation.
   // The assignment is done in declaration order.
   globals->malloc_dispatch = dispatch_table;
+  atomic_store(&g_heapprofd_handle, impl_handle);
 
   info_log("%s: malloc %s enabled", getprogname(), prefix);
 
@@ -761,6 +769,18 @@
 // =============================================================================
 
 #if !defined(LIBC_STATIC)
+bool MallocDispatchReset() {
+  if (!atomic_exchange(&g_heapprofd_init_in_progress, true)) {
+    __libc_globals.mutate([](libc_globals* globals) {
+      globals->malloc_dispatch = __libc_malloc_default_dispatch;
+    });
+    atomic_store(&g_heapprofd_init_in_progress, false);
+    return true;
+  }
+  errno = EAGAIN;
+  return false;
+}
+
 // Marks this process as a profileable zygote child.
 bool HandleInitZygoteChildProfiling() {
   atomic_store_explicit(&gMallocZygoteChildProfileable, true,
@@ -777,6 +797,10 @@
 
 #else
 
+bool MallocDispatchReset() {
+  return true;
+}
+
 bool HandleInitZygoteChildProfiling() {
   return true;
 }
@@ -791,6 +815,13 @@
     }
     return HandleInitZygoteChildProfiling();
   }
+  if (opcode == M_RESET_HOOKS) {
+    if (arg != nullptr || arg_size != 0) {
+      errno = EINVAL;
+      return false;
+    }
+    return MallocDispatchReset();
+  }
 
   errno = ENOTSUP;
   return false;
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index d80906c..b8784b8 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -44,6 +44,7 @@
 #include "private/bionic_globals.h"
 #include "private/bionic_macros.h"
 #include "private/bionic_ssp.h"
+#include "private/bionic_systrace.h"
 #include "private/bionic_tls.h"
 #include "private/ErrnoRestorer.h"
 
@@ -347,6 +348,7 @@
   ErrnoRestorer errno_restorer;
 
   pthread_attr_t thread_attr;
+  ScopedTrace trace("pthread_create");
   if (attr == nullptr) {
     pthread_attr_init(&thread_attr);
   } else {
diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp
index 9aad458..8e4ca59 100644
--- a/libc/bionic/pthread_join.cpp
+++ b/libc/bionic/pthread_join.cpp
@@ -30,10 +30,12 @@
 
 #include "private/bionic_defs.h"
 #include "private/bionic_futex.h"
+#include "private/bionic_systrace.h"
 #include "pthread_internal.h"
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 int pthread_join(pthread_t t, void** return_value) {
+  ScopedTrace trace("pthread_join");
   if (t == pthread_self()) {
     return EDEADLK;
   }
diff --git a/libc/private/bionic_malloc.h b/libc/private/bionic_malloc.h
index a9fa22d..5f4a75d 100644
--- a/libc/private/bionic_malloc.h
+++ b/libc/private/bionic_malloc.h
@@ -32,11 +32,13 @@
 
 // Opcodes for android_mallopt.
 
-// Marks the calling process as a profileable zygote child, possibly
-// initializing profiling infrastructure.
 enum {
+  // Marks the calling process as a profileable zygote child, possibly
+  // initializing profiling infrastructure.
   M_INIT_ZYGOTE_CHILD_PROFILING = 1,
 #define M_INIT_ZYGOTE_CHILD_PROFILING M_INIT_ZYGOTE_CHILD_PROFILING
+  M_RESET_HOOKS = 2,
+#define M_RESET_HOOKS M_RESET_HOOKS
 };
 
 // Manipulates bionic-specific handling of memory allocation APIs such as
diff --git a/libc/symbol_ordering b/libc/symbol_ordering
index 5b365f0..b672b35 100644
--- a/libc/symbol_ordering
+++ b/libc/symbol_ordering
@@ -86,7 +86,6 @@
 __realloc_hook
 __free_hook
 __memalign_hook
-_ZL21g_heapprofd_init_func
 je_malloc_conf
 malloc_initializer
 a0
diff --git a/tests/Android.bp b/tests/Android.bp
index b979f32..b374c27 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -384,7 +384,7 @@
                 "libdl_test.cpp",
             ],
             static_libs: [
-                "libpagemap",
+                "libmeminfo",
                 "libziparchive",
                 "libLLVMObject",
                 "libLLVMBitReader",
@@ -469,7 +469,7 @@
             static_libs: [
                 // The order of these libraries matters, do not shuffle them.
                 "libbase",
-                "libpagemap",
+                "libmeminfo",
                 "libziparchive",
                 "libz",
                 "libutils",
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 34013a7..c9ecd2e 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -36,7 +36,7 @@
 #include <sys/vfs.h>
 #include <sys/wait.h>
 
-#include <pagemap/pagemap.h>
+#include <meminfo/procmeminfo.h>
 #include <ziparchive/zip_archive.h>
 
 #include "gtest_globals.h"
@@ -488,33 +488,23 @@
 
 void GetPss(bool shared_relro, const char* lib, const char* relro_file, pid_t pid,
             size_t* total_pss) {
-  pm_kernel_t* kernel;
-  ASSERT_EQ(0, pm_kernel_create(&kernel));
-
-  pm_process_t* process;
-  ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
-
-  pm_map_t** maps;
-  size_t num_maps;
-  ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
+  android::meminfo::ProcMemInfo proc_mem(pid);
+  const std::vector<android::meminfo::Vma>& maps = proc_mem.Maps();
+  ASSERT_GT(maps.size(), 0UL);
 
   // Calculate total PSS of the library.
   *total_pss = 0;
   bool saw_relro_file = false;
-  for (size_t i = 0; i < num_maps; ++i) {
-    if (android::base::EndsWith(maps[i]->name, lib) || strcmp(maps[i]->name, relro_file) == 0) {
-      if (strcmp(maps[i]->name, relro_file) == 0) saw_relro_file = true;
+  for (auto& vma : maps) {
+    if (android::base::EndsWith(vma.name, lib) || (vma.name == relro_file)) {
+      if (vma.name == relro_file) {
+          saw_relro_file = true;
+      }
 
-      pm_memusage_t usage;
-      ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
-      *total_pss += usage.pss;
+      *total_pss += vma.usage.pss;
     }
   }
 
-  free(maps);
-  pm_process_destroy(process);
-  pm_kernel_destroy(kernel);
-
   if (shared_relro) ASSERT_TRUE(saw_relro_file);
 }
 
diff --git a/tests/headers/posix/signal_h.c b/tests/headers/posix/signal_h.c
index 661b55e..c2e544e 100644
--- a/tests/headers/posix/signal_h.c
+++ b/tests/headers/posix/signal_h.c
@@ -53,7 +53,7 @@
   STRUCT_MEMBER(struct sigevent, int, sigev_signo);
   STRUCT_MEMBER(struct sigevent, union sigval, sigev_value);
   STRUCT_MEMBER_FUNCTION_POINTER(struct sigevent, void (*f)(union sigval), sigev_notify_function);
-#if defined(__BIONIC__) || defined(__GLIBC__)
+#if defined(__BIONIC__)
   STRUCT_MEMBER(struct sigevent, void*, sigev_notify_attributes);
 #else
   STRUCT_MEMBER(struct sigevent, pthread_attr_t*, sigev_notify_attributes);
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 1c57264..9c6b975 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
+#include <sys/resource.h>
 #include <sys/syscall.h>
 #include <time.h>
 #include <unistd.h>