Merge "Fix missing symbol for debug malloc."
diff --git a/libc/arch-arm/bionic/__bionic_clone.S b/libc/arch-arm/bionic/__bionic_clone.S
index f5cf9e0..a268f9d 100644
--- a/libc/arch-arm/bionic/__bionic_clone.S
+++ b/libc/arch-arm/bionic/__bionic_clone.S
@@ -42,13 +42,14 @@
     # load extra parameters
     ldmfd   ip, {r4, r5, r6}
 
-    # store 'fn' and 'arg' to the child stack
-    str     r5, [r1, #-4]
-    str     r6, [r1, #-8]
+    # Push 'fn' and 'arg' onto the child stack.
+    stmdb   r1!, {r5, r6}
 
-    # System call
+    # Make the system call.
     ldr     r7, =__NR_clone
     swi     #0
+
+    # Are we the child?
     movs    r0, r0
     beq     1f
 
@@ -62,8 +63,8 @@
 1:  # The child.
     # Setting lr to 0 will make the unwinder stop at __start_thread
     mov    lr, #0
-    ldr    r0, [sp, #-4]
-    ldr    r1, [sp, #-8]
+    # Call __start_thread with the 'fn' and 'arg' we stored on the child stack.
+    pop    {r0, r1}
     b      __start_thread
 END(__bionic_clone)
 .hidden __bionic_clone
diff --git a/libc/arch-arm64/bionic/__bionic_clone.S b/libc/arch-arm64/bionic/__bionic_clone.S
index 56ac0f6..27e44e7 100644
--- a/libc/arch-arm64/bionic/__bionic_clone.S
+++ b/libc/arch-arm64/bionic/__bionic_clone.S
@@ -31,8 +31,8 @@
 // pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg);
 
 ENTRY(__bionic_clone)
-    # Copy 'fn' and 'arg' onto the child stack.
-    stp     x5, x6, [x1, #-16]
+    # Push 'fn' and 'arg' onto the child stack.
+    stp     x5, x6, [x1, #-16]!
 
     # Make the system call.
     mov     x8, __NR_clone
@@ -49,12 +49,12 @@
     ret
 
 .L_bc_child:
-    # We're in the child now. Set the end of the frame record chain...
-    mov     x29, xzr
-    # Setting x30 to 0 will make the unwinder stop at __start_thread
-    mov     x30, xzr
-    # ...and call __start_thread with the 'fn' and 'arg' we stored on the child stack.
-    ldp     x0, x1, [sp, #-16]
+    # We're in the child now. Set the end of the frame record chain.
+    mov     x29, #0
+    # Setting x30 to 0 will make the unwinder stop at __start_thread.
+    mov     x30, #0
+    # Call __start_thread with the 'fn' and 'arg' we stored on the child stack.
+    ldp     x0, x1, [sp], #16
     b       __start_thread
 END(__bionic_clone)
 .hidden __bionic_clone
diff --git a/libc/bionic/pty.cpp b/libc/bionic/pty.cpp
index 2c86180..8847147 100644
--- a/libc/bionic/pty.cpp
+++ b/libc/bionic/pty.cpp
@@ -36,6 +36,11 @@
 #include <unistd.h>
 #include <utmp.h>
 
+#include "private/ThreadLocalBuffer.h"
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(ptsname);
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(ttyname);
+
 int getpt() {
   return posix_openpt(O_RDWR|O_NOCTTY);
 }
@@ -49,8 +54,9 @@
 }
 
 char* ptsname(int fd) {
-  static char buf[32];
-  return ptsname_r(fd, buf, sizeof(buf)) == 0 ? buf : NULL;
+  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, ptsname, 32);
+  int error = ptsname_r(fd, ptsname_tls_buffer, ptsname_tls_buffer_size);
+  return (error == 0) ? ptsname_tls_buffer : NULL;
 }
 
 int ptsname_r(int fd, char* buf, size_t len) {
@@ -74,8 +80,9 @@
 }
 
 char* ttyname(int fd) {
-  static char buf[64];
-  return ttyname_r(fd, buf, sizeof(buf)) == 0 ? buf : NULL;
+  LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, ttyname, 64);
+  int error = ttyname_r(fd, ttyname_tls_buffer, ttyname_tls_buffer_size);
+  return (error == 0) ? ttyname_tls_buffer : NULL;
 }
 
 int ttyname_r(int fd, char* buf, size_t len) {
diff --git a/libc/include/machine/timespec.h b/libc/include/machine/timespec.h
new file mode 100644
index 0000000..11779ae
--- /dev/null
+++ b/libc/include/machine/timespec.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef _MACHINE_TIMESPEC_H_
+#define _MACHINE_TIMESPEC_H_
+
+#include <sys/types.h>
+
+/*
+ * This file is used to include timespec definition without introducing the whole
+ * <linux/time.h>, <sys/time.h> or <time.h>.
+ */
+#ifndef _STRUCT_TIMESPEC
+#define _STRUCT_TIMESPEC
+struct timespec {
+  time_t tv_sec;
+  long tv_nsec;
+};
+#endif
+
+#endif /* _MACHINE_TIMESPEC_H_ */
diff --git a/libc/include/sched.h b/libc/include/sched.h
index 4f9e2a6..930dd7c 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -28,10 +28,9 @@
 #ifndef _SCHED_H_
 #define _SCHED_H_
 
-#include <sys/cdefs.h>
-#include <sys/time.h>
-
 #include <linux/sched.h>
+#include <machine/timespec.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 867f497..9519f6d 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -32,8 +32,8 @@
 #include <asm/sigcontext.h>
 #include <errno.h>
 #include <limits.h>
-#include <linux/time.h>
 #include <machine/pthread_types.h>
+#include <machine/timespec.h>
 #include <string.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 3053e85..dfb788e 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -131,7 +131,7 @@
 int getpt(void);
 int grantpt(int);
 int posix_openpt(int);
-char* ptsname(int) __warnattr("ptsname is not thread-safe; use ptsname_r instead");
+char* ptsname(int);
 int ptsname_r(int, char*, size_t);
 int unlockpt(int);
 
diff --git a/libc/include/sys/endian.h b/libc/include/sys/endian.h
index c62ba7f..2fd480d 100644
--- a/libc/include/sys/endian.h
+++ b/libc/include/sys/endian.h
@@ -35,13 +35,6 @@
 #define _BYTE_ORDER _LITTLE_ENDIAN
 #define __LITTLE_ENDIAN_BITFIELD
 
-#if __BSD_VISIBLE
-#define LITTLE_ENDIAN _LITTLE_ENDIAN
-#define BIG_ENDIAN _BIG_ENDIAN
-#define PDP_ENDIAN _PDP_ENDIAN
-#define BYTE_ORDER _BYTE_ORDER
-#endif
-
 #ifndef __LITTLE_ENDIAN
 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
 #endif
@@ -54,27 +47,6 @@
 #define __swap32 __builtin_bswap32
 #define __swap64 __builtin_bswap64
 
-#if __BSD_VISIBLE
-#define swap16 __swap16
-#define swap32 __swap32
-#define swap64 __swap64
-#define swap16_multi __swap16_multi
-
-#define htobe16 __swap16
-#define htobe32 __swap32
-#define htobe64 __swap64
-#define betoh16 __swap16
-#define betoh32 __swap32
-#define betoh64 __swap64
-
-#define htole16(x) (x)
-#define htole32(x) (x)
-#define htole64(x) (x)
-#define letoh16(x) (x)
-#define letoh32(x) (x)
-#define letoh64(x) (x)
-#endif /* __BSD_VISIBLE */
-
 /* glibc compatibility. */
 __BEGIN_DECLS
 uint32_t htonl(uint32_t) __pure2;
@@ -93,13 +65,34 @@
 #define ntohq(x) __swap64(x)
 
 #if __BSD_VISIBLE
+#define LITTLE_ENDIAN _LITTLE_ENDIAN
+#define BIG_ENDIAN _BIG_ENDIAN
+#define PDP_ENDIAN _PDP_ENDIAN
+#define BYTE_ORDER _BYTE_ORDER
+
 #define	NTOHL(x) (x) = ntohl((u_int32_t)(x))
 #define	NTOHS(x) (x) = ntohs((u_int16_t)(x))
 #define	HTONL(x) (x) = htonl((u_int32_t)(x))
 #define	HTONS(x) (x) = htons((u_int16_t)(x))
-#endif
 
-#ifdef __BSD_VISIBLE
+#define swap16 __swap16
+#define swap32 __swap32
+#define swap64 __swap64
+
+#define htobe16 __swap16
+#define htobe32 __swap32
+#define htobe64 __swap64
+#define betoh16 __swap16
+#define betoh32 __swap32
+#define betoh64 __swap64
+
+#define htole16(x) (x)
+#define htole32(x) (x)
+#define htole64(x) (x)
+#define letoh16(x) (x)
+#define letoh32(x) (x)
+#define letoh64(x) (x)
+
 /*
  * glibc-compatible beXXtoh/leXXtoh synonyms for htobeXX/htoleXX.
  * The BSDs export both sets of names, bionic historically only
@@ -112,6 +105,6 @@
 #define le16toh(x) htole16(x)
 #define le32toh(x) htole32(x)
 #define le64toh(x) htole64(x)
-#endif
+#endif /* __BSD_VISIBLE */
 
 #endif /* _SYS_ENDIAN_H_ */
diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h
index 32c1206..553050b 100644
--- a/libc/include/sys/select.h
+++ b/libc/include/sys/select.h
@@ -29,11 +29,11 @@
 #ifndef _SYS_SELECT_H_
 #define _SYS_SELECT_H_
 
-#include <sys/cdefs.h>
-#include <sys/time.h>
-#include <sys/types.h>
+#include <linux/time.h>
 #include <signal.h>
 #include <string.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index 7d85dd1..e3f41a9 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -29,12 +29,11 @@
 #ifndef _SYS_STAT_H_
 #define _SYS_STAT_H_
 
+#include <endian.h>
+#include <linux/stat.h>
+#include <machine/timespec.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
-#include <sys/time.h>
-#include <linux/stat.h>
-
-#include <endian.h>
 
 __BEGIN_DECLS
 
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index e94ee66..c755715 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -195,7 +195,7 @@
 extern int optind, opterr, optopt;
 
 extern int isatty(int);
-extern char* ttyname(int) __warnattr("ttyname is not thread-safe; use ttyname_r instead");
+extern char* ttyname(int);
 extern int ttyname_r(int, char*, size_t);
 
 extern int  acct(const char*  filepath);
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 56a61be..0c6e062 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -76,7 +76,7 @@
  * pthread_key_create; grep for GLOBAL_INIT_THREAD_LOCAL_BUFFER to find those. We need to manually
  * maintain that second number, but pthread_test will fail if we forget.
  */
-#define GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT 5
+#define GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT 9
 
 #if defined(USE_JEMALLOC)
 /* jemalloc uses 5 keys for itself. */
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index 2ea01b3..8afd494 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -63,15 +63,27 @@
   }
 }
 
-static sigset_t SigSetOf(int signal, int rt_signal = 0) {
-  sigset_t ss;
-  sigemptyset(&ss);
-  sigaddset(&ss, signal);
-  if (rt_signal != 0) {
-    sigaddset(&ss, rt_signal);
+// Two distinct signal sets, pipu
+struct SigSets {
+  SigSets() : one(MakeSigSet(0)), two(MakeSigSet(1)) {
   }
-  return ss;
-}
+
+  static sigset_t MakeSigSet(int offset) {
+    sigset_t ss;
+    sigemptyset(&ss);
+    sigaddset(&ss, SIGUSR1 + offset);
+#if defined(__LP64__)
+    // For arm and x86, sigset_t was too small for the RT signals.
+    // For mips, sigset_t was large enough but jmp_buf wasn't.
+    sigaddset(&ss, SIGRTMIN + offset);
+#endif
+    return ss;
+  }
+
+  sigset_t one;
+  sigset_t two;
+  sigset_t original;
+};
 
 void AssertSigmaskEquals(const sigset_t& expected) {
   sigset_t actual;
@@ -84,76 +96,68 @@
 
 TEST(setjmp, _setjmp_signal_mask) {
   // _setjmp/_longjmp do not save/restore the signal mask.
-  sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8));
-  sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9));
-  sigset_t original_set;
-  sigprocmask(SIG_SETMASK, &ss1, &original_set);
+  SigSets ss;
+  sigprocmask(SIG_SETMASK, &ss.one, &ss.original);
   jmp_buf jb;
   if (_setjmp(jb) == 0) {
-    sigprocmask(SIG_SETMASK, &ss2, NULL);
+    sigprocmask(SIG_SETMASK, &ss.two, NULL);
     _longjmp(jb, 1);
     FAIL(); // Unreachable.
   } else {
-    AssertSigmaskEquals(ss2);
+    AssertSigmaskEquals(ss.two);
   }
-  sigprocmask(SIG_SETMASK, &original_set, NULL);
+  sigprocmask(SIG_SETMASK, &ss.original, NULL);
 }
 
 TEST(setjmp, setjmp_signal_mask) {
   // setjmp/longjmp do save/restore the signal mask on bionic, but not on glibc.
   // This is a BSD versus System V historical accident. POSIX leaves the
   // behavior unspecified, so any code that cares needs to use sigsetjmp.
-  sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8));
-  sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9));
-  sigset_t original_set;
-  sigprocmask(SIG_SETMASK, &ss1, &original_set);
+  SigSets ss;
+  sigprocmask(SIG_SETMASK, &ss.one, &ss.original);
   jmp_buf jb;
   if (setjmp(jb) == 0) {
-    sigprocmask(SIG_SETMASK, &ss2, NULL);
+    sigprocmask(SIG_SETMASK, &ss.two, NULL);
     longjmp(jb, 1);
     FAIL(); // Unreachable.
   } else {
 #if defined(__BIONIC__)
     // bionic behaves like BSD and does save/restore the signal mask.
-    AssertSigmaskEquals(ss1);
+    AssertSigmaskEquals(ss.one);
 #else
     // glibc behaves like System V and doesn't save/restore the signal mask.
-    AssertSigmaskEquals(ss2);
+    AssertSigmaskEquals(ss.two);
 #endif
   }
-  sigprocmask(SIG_SETMASK, &original_set, NULL);
+  sigprocmask(SIG_SETMASK, &ss.original, NULL);
 }
 
 TEST(setjmp, sigsetjmp_0_signal_mask) {
   // sigsetjmp(0)/siglongjmp do not save/restore the signal mask.
-  sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8));
-  sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9));
-  sigset_t original_set;
-  sigprocmask(SIG_SETMASK, &ss1, &original_set);
+  SigSets ss;
+  sigprocmask(SIG_SETMASK, &ss.one, &ss.original);
   sigjmp_buf sjb;
   if (sigsetjmp(sjb, 0) == 0) {
-    sigprocmask(SIG_SETMASK, &ss2, NULL);
+    sigprocmask(SIG_SETMASK, &ss.two, NULL);
     siglongjmp(sjb, 1);
     FAIL(); // Unreachable.
   } else {
-    AssertSigmaskEquals(ss2);
+    AssertSigmaskEquals(ss.two);
   }
-  sigprocmask(SIG_SETMASK, &original_set, NULL);
+  sigprocmask(SIG_SETMASK, &ss.original, NULL);
 }
 
 TEST(setjmp, sigsetjmp_1_signal_mask) {
   // sigsetjmp(1)/siglongjmp does save/restore the signal mask.
-  sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8));
-  sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9));
-  sigset_t original_set;
-  sigprocmask(SIG_SETMASK, &ss1, &original_set);
+  SigSets ss;
+  sigprocmask(SIG_SETMASK, &ss.one, &ss.original);
   sigjmp_buf sjb;
   if (sigsetjmp(sjb, 1) == 0) {
-    sigprocmask(SIG_SETMASK, &ss2, NULL);
+    sigprocmask(SIG_SETMASK, &ss.two, NULL);
     siglongjmp(sjb, 1);
     FAIL(); // Unreachable.
   } else {
-    AssertSigmaskEquals(ss1);
+    AssertSigmaskEquals(ss.one);
   }
-  sigprocmask(SIG_SETMASK, &original_set, NULL);
+  sigprocmask(SIG_SETMASK, &ss.original, NULL);
 }