Merge "Fix deadlock/timeout in thread unwinding."
diff --git a/docs/32-bit-abi.md b/docs/32-bit-abi.md
index 81afd14..3be6b1a 100644
--- a/docs/32-bit-abi.md
+++ b/docs/32-bit-abi.md
@@ -81,13 +81,23 @@
 in the 64-bit ABI even though they're identical to the non-`64` names.
 
 
-## `time_t` is 32-bit
+## `time_t` is 32-bit on LP32 (y2038)
 
-On 32-bit Android, `time_t` is 32-bit. The header `<time64.h>` and type
-`time64_t` exist as a workaround, but the kernel interfaces exposed on 32-bit
-Android all use the 32-bit `time_t`.
+On 32-bit Android, `time_t` is 32-bit, which will overflow in 2038.
 
-In the 64-bit ABI, `time_t` is 64-bit.
+In the 64-bit ABI, `time_t` is 64-bit, which will not overflow until
+long after the death of the star around which we currently circle.
+
+The header `<time64.h>` and type `time64_t` exist as a workaround,
+but the kernel interfaces exposed on 32-bit Android all use the 32-bit
+`time_t` and `struct timespec`/`struct timeval`. Linux 5.x kernels
+do offer extra interfaces so that 32-bit processes can pass 64-bit
+times to/from the kernel, but we do not plan on adding support for
+these to the C library. Convenient use of the new calls would require
+an equivalent to `_FILE_OFFSET_BITS=64`, which we wouldn't be able
+to globally flip for reasons similar to `_FILE_OFFSET_BITS`, mentioned
+above. All apps are already required to offer 64-bit variants, and we
+expect 64-bit-only devices within the next few years.
 
 
 ## `pthread_mutex_t` is too small for large pids
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index 583bf32..1cdb021 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -85,6 +85,28 @@
 
 extern "C" int __rt_sigaction(int, const struct sigaction64*, struct sigaction64*, size_t);
 
+// sigaction and sigaction64 get interposed in ART: ensure that we don't end up calling
+//     sigchain sigaction -> bionic sigaction -> sigchain sigaction64 -> bionic sigaction64
+// by extracting the implementation of sigaction64 to a static function.
+static int __sigaction64(int signal, const struct sigaction64* bionic_new,
+                         struct sigaction64* bionic_old) {
+  struct sigaction64 kernel_new;
+  if (bionic_new) {
+    kernel_new = *bionic_new;
+#if defined(SA_RESTORER)
+    if (!(kernel_new.sa_flags & SA_RESTORER)) {
+      kernel_new.sa_flags |= SA_RESTORER;
+      kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
+    }
+#endif
+    // Don't filter signals here; if the caller asked for everything to be blocked, we should obey.
+    kernel_new.sa_mask = kernel_new.sa_mask;
+  }
+
+  return __rt_sigaction(signal, bionic_new ? &kernel_new : nullptr, bionic_old,
+                        sizeof(kernel_new.sa_mask));
+}
+
 int sigaction(int signal, const struct sigaction* bionic_new, struct sigaction* bionic_old) {
   // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t,
   // so we have to translate to struct sigaction64 first.
@@ -101,7 +123,7 @@
   }
 
   struct sigaction64 kernel_old;
-  int result = sigaction64(signal, bionic_new ? &kernel_new : nullptr, &kernel_old);
+  int result = __sigaction64(signal, bionic_new ? &kernel_new : nullptr, &kernel_old);
   if (bionic_old) {
     *bionic_old = {};
     bionic_old->sa_flags = kernel_old.sa_flags;
@@ -115,23 +137,7 @@
 }
 
 int sigaction64(int signal, const struct sigaction64* bionic_new, struct sigaction64* bionic_old) {
-  struct sigaction64 kernel_new;
-  if (bionic_new) {
-    kernel_new = *bionic_new;
-#if defined(SA_RESTORER)
-    if (!(kernel_new.sa_flags & SA_RESTORER)) {
-      kernel_new.sa_flags |= SA_RESTORER;
-      kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
-    }
-#endif
-    // Don't filter signals here; if the caller asked for everything to be blocked, we should obey.
-    kernel_new.sa_mask = kernel_new.sa_mask;
-  }
-
-  return __rt_sigaction(signal,
-                        bionic_new ? &kernel_new : nullptr,
-                        bionic_old,
-                        sizeof(kernel_new.sa_mask));
+  return __sigaction64(signal, bionic_new, bionic_old);
 }
 
 #endif
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 3241a1e..1139e53 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -244,7 +244,6 @@
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicui18n.so", RTLD_NOW) != nullptr);
 }
 
-/* TODO: Re-enable test when the cuttlefish build is fixed. http://b/156315785
 TEST(dlfcn, dlopen_system_libicuuc_android_api_level_29) {
   android_set_application_target_sdk_version(29);
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicuuc.so", RTLD_NOW) == nullptr);
@@ -255,7 +254,6 @@
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicuuc.so", RTLD_NOW) == nullptr);
   ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicui18n.so", RTLD_NOW) == nullptr);
 }
-*/
 
 TEST(dlfcn, dlopen_from_zip_absolute_path) {
   const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";