Merge "Document how to run the benchmarks."
diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
index 2200a6c..84e511c 100644
--- a/libc/bionic/pthread_atfork.cpp
+++ b/libc/bionic/pthread_atfork.cpp
@@ -130,13 +130,15 @@
 }
 
 void __bionic_atfork_run_child() {
+  g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+  pthread_mutex_lock(&g_atfork_list_mutex);
   g_atfork_list.walk_forward([](atfork_t* it) {
     if (it->child != nullptr) {
       it->child();
     }
   });
-
-  g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+  pthread_mutex_unlock(&g_atfork_list_mutex);
 }
 
 void __bionic_atfork_run_parent() {
diff --git a/libc/include/android/legacy_fenv_inlines_arm.h b/libc/include/android/legacy_fenv_inlines_arm.h
new file mode 100644
index 0000000..a5bb26b
--- /dev/null
+++ b/libc/include/android/legacy_fenv_inlines_arm.h
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/msun/arm/fenv.c,v 1.1 2004/06/06 10:03:59 das Exp $
+ */
+
+#ifndef ANDROID_LEGACY_FENV_INLINES_ARM_H
+#define ANDROID_LEGACY_FENV_INLINES_ARM_H
+
+#include <fenv.h>
+
+#if __ANDROID_API__ < 21 && defined(__arm__)
+
+__BEGIN_DECLS
+
+#define FPSCR_ENABLE_SHIFT 8
+#define FPSCR_ENABLE_MASK  (FE_ALL_EXCEPT << FPSCR_ENABLE_SHIFT)
+
+#define FPSCR_RMODE_SHIFT 22
+
+static __inline int fegetenv(fenv_t* __envp) {
+  fenv_t _fpscr;
+  __asm__ __volatile__("vmrs %0,fpscr" : "=r" (_fpscr));
+  *__envp = _fpscr;
+  return 0;
+}
+
+static __inline int fesetenv(const fenv_t* __envp) {
+  fenv_t _fpscr = *__envp;
+  __asm__ __volatile__("vmsr fpscr,%0" : :"ri" (_fpscr));
+  return 0;
+}
+
+static __inline int feclearexcept(int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  __fpscr &= ~__excepts;
+  fesetenv(&__fpscr);
+  return 0;
+}
+
+static __inline int fegetexceptflag(fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  *__flagp = __fpscr & __excepts;
+  return 0;
+}
+
+static __inline int fesetexceptflag(const fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  __fpscr &= ~__excepts;
+  __fpscr |= *__flagp & __excepts;
+  fesetenv(&__fpscr);
+  return 0;
+}
+
+static __inline int feraiseexcept(int __excepts) {
+  fexcept_t __ex = __excepts;
+  fesetexceptflag(&__ex, __excepts);
+  return 0;
+}
+
+static __inline int fetestexcept(int __excepts) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  return (__fpscr & __excepts);
+}
+
+static __inline int fegetround(void) {
+  fenv_t _fpscr;
+  fegetenv(&_fpscr);
+  return ((_fpscr >> FPSCR_RMODE_SHIFT) & 0x3);
+}
+
+static __inline int fesetround(int __round) {
+  fenv_t _fpscr;
+  fegetenv(&_fpscr);
+  _fpscr &= ~(0x3 << FPSCR_RMODE_SHIFT);
+  _fpscr |= (__round << FPSCR_RMODE_SHIFT);
+  fesetenv(&_fpscr);
+  return 0;
+}
+
+static __inline int feholdexcept(fenv_t* __envp) {
+  fenv_t __env;
+  fegetenv(&__env);
+  *__envp = __env;
+  __env &= ~(FE_ALL_EXCEPT | FPSCR_ENABLE_MASK);
+  fesetenv(&__env);
+  return 0;
+}
+
+static __inline int feupdateenv(const fenv_t* __envp) {
+  fexcept_t __fpscr;
+  fegetenv(&__fpscr);
+  fesetenv(__envp);
+  feraiseexcept(__fpscr & FE_ALL_EXCEPT);
+  return 0;
+}
+
+static __inline int feenableexcept(int __mask) {
+  fenv_t __old_fpscr, __new_fpscr;
+  fegetenv(&__old_fpscr);
+  __new_fpscr = __old_fpscr | (__mask & FE_ALL_EXCEPT) << FPSCR_ENABLE_SHIFT;
+  fesetenv(&__new_fpscr);
+  return ((__old_fpscr >> FPSCR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fedisableexcept(int __mask) {
+  fenv_t __old_fpscr, __new_fpscr;
+  fegetenv(&__old_fpscr);
+  __new_fpscr = __old_fpscr & ~((__mask & FE_ALL_EXCEPT) << FPSCR_ENABLE_SHIFT);
+  fesetenv(&__new_fpscr);
+  return ((__old_fpscr >> FPSCR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fegetexcept(void) {
+  fenv_t __fpscr;
+  fegetenv(&__fpscr);
+  return ((__fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT);
+}
+
+#undef FPSCR_ENABLE_SHIFT
+#undef FPSCR_ENABLE_MASK
+#undef FPSCR_RMODE_SHIFT
+
+__END_DECLS
+
+#endif /* __ANDROID_API__ < 21 && defined(__arm__) */
+
+#endif /* ANDROID_LEGACY_FENV_INLINES_ARM_H */
diff --git a/libc/include/android/legacy_fenv_inlines_mips.h b/libc/include/android/legacy_fenv_inlines_mips.h
new file mode 100644
index 0000000..ead697c
--- /dev/null
+++ b/libc/include/android/legacy_fenv_inlines_mips.h
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/msun/mips/fenv.c,v 1.1 2008/04/26 12:20:29 imp Exp $
+ */
+
+#ifndef ANDROID_LEGACY_FENV_INLINES_MIPS_H
+#define ANDROID_LEGACY_FENV_INLINES_MIPS_H
+
+#include <fenv.h>
+
+#if __ANDROID_API__ < 21 && (defined(__mips__) && !defined(__LP64__))
+
+__BEGIN_DECLS
+
+#define FCSR_CAUSE_SHIFT 10
+#define FCSR_ENABLE_SHIFT 5
+#define FCSR_ENABLE_MASK (FE_ALL_EXCEPT << FCSR_ENABLE_SHIFT)
+
+#define FCSR_RMASK       0x3
+
+static __inline int fegetenv(fenv_t* __envp) {
+  fenv_t _fcsr = 0;
+#ifdef  __mips_hard_float
+  __asm__ __volatile__("cfc1 %0,$31" : "=r" (_fcsr));
+#endif
+  *__envp = _fcsr;
+  return 0;
+}
+
+static __inline int fesetenv(const fenv_t* __envp) {
+  fenv_t _fcsr = *__envp;
+#ifdef  __mips_hard_float
+  __asm__ __volatile__("ctc1 %0,$31" : : "r" (_fcsr));
+#endif
+  return 0;
+}
+
+static __inline int feclearexcept(int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  __excepts &= FE_ALL_EXCEPT;
+  __fcsr &= ~(__excepts | (__excepts << FCSR_CAUSE_SHIFT));
+  fesetenv(&__fcsr);
+  return 0;
+}
+
+static __inline int fegetexceptflag(fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  *__flagp = __fcsr & __excepts & FE_ALL_EXCEPT;
+  return 0;
+}
+
+static __inline int fesetexceptflag(const fexcept_t* __flagp, int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  /* Ensure that flags are all legal */
+  __excepts &= FE_ALL_EXCEPT;
+  __fcsr &= ~__excepts;
+  __fcsr |= *__flagp & __excepts;
+  fesetenv(&__fcsr);
+  return 0;
+}
+
+static __inline int feraiseexcept(int __excepts) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  /* Ensure that flags are all legal */
+  __excepts &= FE_ALL_EXCEPT;
+  /* Cause bit needs to be set as well for generating the exception*/
+  __fcsr |= __excepts | (__excepts << FCSR_CAUSE_SHIFT);
+  fesetenv(&__fcsr);
+  return 0;
+}
+
+static __inline int fetestexcept(int __excepts) {
+  fexcept_t __FCSR;
+  fegetenv(&__FCSR);
+  return (__FCSR & __excepts & FE_ALL_EXCEPT);
+}
+
+static __inline int fegetround(void) {
+  fenv_t _fcsr;
+  fegetenv(&_fcsr);
+  return (_fcsr & FCSR_RMASK);
+}
+
+static __inline int fesetround(int __round) {
+  fenv_t _fcsr;
+  fegetenv(&_fcsr);
+  _fcsr &= ~FCSR_RMASK;
+  _fcsr |= (__round & FCSR_RMASK);
+  fesetenv(&_fcsr);
+  return 0;
+}
+
+static __inline int feholdexcept(fenv_t* __envp) {
+  fenv_t __env;
+  fegetenv(&__env);
+  *__envp = __env;
+  __env &= ~(FE_ALL_EXCEPT | FCSR_ENABLE_MASK);
+  fesetenv(&__env);
+  return 0;
+}
+
+static __inline int feupdateenv(const fenv_t* __envp) {
+  fexcept_t __fcsr;
+  fegetenv(&__fcsr);
+  fesetenv(__envp);
+  feraiseexcept(__fcsr & FE_ALL_EXCEPT);
+  return 0;
+}
+
+static __inline int feenableexcept(int __mask) {
+  fenv_t __old_fcsr, __new_fcsr;
+  fegetenv(&__old_fcsr);
+  __new_fcsr = __old_fcsr | (__mask & FE_ALL_EXCEPT) << FCSR_ENABLE_SHIFT;
+  fesetenv(&__new_fcsr);
+  return ((__old_fcsr >> FCSR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fedisableexcept(int __mask) {
+  fenv_t __old_fcsr, __new_fcsr;
+  fegetenv(&__old_fcsr);
+  __new_fcsr = __old_fcsr & ~((__mask & FE_ALL_EXCEPT) << FCSR_ENABLE_SHIFT);
+  fesetenv(&__new_fcsr);
+  return ((__old_fcsr >> FCSR_ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static __inline int fegetexcept(void) {
+  fenv_t __fcsr;
+  fegetenv(&__fcsr);
+  return ((__fcsr & FCSR_ENABLE_MASK) >> FCSR_ENABLE_SHIFT);
+}
+
+#undef FCSR_CAUSE_SHIFT
+#undef FCSR_ENABLE_SHIFT
+#undef FCSR_ENABLE_MASK
+#undef FCSR_RMASK
+
+__END_DECLS
+
+#endif /* __ANDROID_API__ < 21 && (defined(__mips__) && !defined(__LP64__)) */
+
+#endif /* ANDROID_LEGACY_FENV_INLINES_MIPS_H */
diff --git a/libc/include/fenv.h b/libc/include/fenv.h
index f1b2b25..241e845 100644
--- a/libc/include/fenv.h
+++ b/libc/include/fenv.h
@@ -36,6 +36,7 @@
 __BEGIN_DECLS
 
 // fenv was always available on x86.
+#if __ANDROID_API__ >= 21 || defined(__i386__)
 int feclearexcept(int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
 int fegetexceptflag(fexcept_t*, int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21)
     __INTRODUCED_IN_X86(9);
@@ -56,6 +57,9 @@
 int feenableexcept(int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
 int fedisableexcept(int) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
 int fegetexcept(void) __INTRODUCED_IN_ARM(21) __INTRODUCED_IN_MIPS(21) __INTRODUCED_IN_X86(9);
+#else
+/* Defined as inlines for pre-21 ARM and MIPS. */
+#endif
 
 /*
  * The following constant represents the default floating-point environment
@@ -70,4 +74,7 @@
 
 __END_DECLS
 
+#include <android/legacy_fenv_inlines_arm.h>
+#include <android/legacy_fenv_inlines_mips.h>
+
 #endif  /* ! _FENV_H_ */
diff --git a/libc/include/sys/limits.h b/libc/include/sys/limits.h
index 5aa3d80..60cc7f7 100644
--- a/libc/include/sys/limits.h
+++ b/libc/include/sys/limits.h
@@ -106,18 +106,12 @@
 #  endif
 # endif
 
-/* Bionic: the following has been optimized out from our processed kernel headers */
-
-#define  CHILD_MAX   999
-#define  OPEN_MAX    256
-
 /* Bionic-specific definitions */
 
 #define  _POSIX_VERSION             200809L   /* Posix C language bindings version */
 #define  _POSIX2_VERSION            -1        /* we don't support Posix command-line tools */
 #define  _XOPEN_VERSION             700       /* by Posix definition */
 
-
 /* >= _POSIX_THREAD_DESTRUCTOR_ITERATIONS */
 #define PTHREAD_DESTRUCTOR_ITERATIONS 4
 /* >= _POSIX_THREAD_KEYS_MAX */
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index f2b7edd..aacf9ae 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -316,7 +316,7 @@
 // PrettyUnitTestResultPrinter. The reason for copy is that PrettyUnitTestResultPrinter
 // is defined and used in gtest.cc, which is hard to reuse.
 static void OnTestIterationStartPrint(const std::vector<TestCase>& testcase_list, size_t iteration,
-                                      int iteration_count) {
+                                      int iteration_count, size_t job_count) {
   if (iteration_count != 1) {
     printf("\nRepeating all tests (iteration %zu) . . .\n\n", iteration);
   }
@@ -328,9 +328,10 @@
     test_count += testcase.TestCount();
   }
 
-  printf("Running %zu %s from %zu %s.\n",
+  printf("Running %zu %s from %zu %s (%zu %s).\n",
          test_count, (test_count == 1) ? "test" : "tests",
-         testcase_count, (testcase_count == 1) ? "test case" : "test cases");
+         testcase_count, (testcase_count == 1) ? "test case" : "test cases",
+         job_count, (job_count == 1) ? "job" : "jobs");
   fflush(stdout);
 }
 
@@ -870,7 +871,7 @@
   for (size_t iteration = 1;
        iteration_count < 0 || iteration <= static_cast<size_t>(iteration_count);
        ++iteration) {
-    OnTestIterationStartPrint(testcase_list, iteration, iteration_count);
+    OnTestIterationStartPrint(testcase_list, iteration, iteration_count, job_count);
     int64_t iteration_start_time_ns = NanoTime();
     time_t epoch_iteration_start_time = time(NULL);
 
diff --git a/tests/pthread_dlfcn_test.cpp b/tests/pthread_dlfcn_test.cpp
index 64423da..1c733fe 100644
--- a/tests/pthread_dlfcn_test.cpp
+++ b/tests/pthread_dlfcn_test.cpp
@@ -37,6 +37,11 @@
 static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; }
 static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; }
 
+static void* g_atfork_test_handle = nullptr;
+static void AtForkPrepare() {}
+static void AtForkParent() {}
+static void AtForkChild() { dlclose(g_atfork_test_handle); g_atfork_test_handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL); }
+
 TEST(pthread, pthread_atfork_with_dlclose) {
   ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
 
@@ -82,3 +87,28 @@
 
   AssertChildExited(pid, 0);
 }
+
+TEST(pthread, pthread_atfork_child_with_dlclose) {
+
+  g_atfork_test_handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(g_atfork_test_handle != nullptr) << dlerror();
+  typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(g_atfork_test_handle, "proxy_pthread_atfork"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  // the library registers 2 additional atfork handlers in a constructor
+
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild));
+
+  pid_t pid = fork();
+
+  ASSERT_NE(-1, pid) << strerror(errno);
+
+  if (pid == 0) {
+    _exit(0);
+  }
+
+  AssertChildExited(pid, 0);
+
+  EXPECT_EQ(0, dlclose(g_atfork_test_handle));
+  g_atfork_test_handle = nullptr;
+}
diff --git a/tests/sys_prctl_test.cpp b/tests/sys_prctl_test.cpp
index 8fdd28f..205db86 100644
--- a/tests/sys_prctl_test.cpp
+++ b/tests/sys_prctl_test.cpp
@@ -53,7 +53,8 @@
     ASSERT_EQ(2, sscanf(lines[i].c_str(), "%" SCNxPTR "-%" SCNxPTR " ", &start, &end))
         << "Failed to parse line: " << lines[i];
     // This will never fail on the first line, so no need to do any special checking.
-    ASSERT_GE(start, last_end) << "Overlapping map detected:\n" << lines[i -1] << lines[i];
+    ASSERT_GE(start, last_end)
+        << "Overlapping map detected:\n" << lines[i -1] << '\n' << lines[i] << '\n';
     last_start = start;
     last_end = end;
   }