Make strerror(3) and strsignal(3) thread-safe, and add psignal(3) and psiginfo(3).

Change-Id: I426109db25e907980d6cb3a7a695796e45783b78
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
new file mode 100644
index 0000000..92235a5
--- /dev/null
+++ b/libc/bionic/strerror_r.cpp
@@ -0,0 +1,71 @@
+/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
+/* Public Domain <marc@snafu.org> */
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+struct Pair {
+  int code;
+  const char* msg;
+};
+
+static const char* __code_string_lookup(const Pair* strings, int code) {
+  for (size_t i = 0; strings[i].msg != NULL; ++i) {
+    if (strings[i].code == code) {
+      return strings[i].msg;
+    }
+  }
+  return NULL;
+}
+
+static const Pair _sys_error_strings[] = {
+#define  __BIONIC_ERRDEF(x,y,z)  { x, z },
+#include <sys/_errdefs.h>
+  { 0, NULL }
+};
+
+int strerror_r(int error_number, char* buf, size_t buf_len) {
+  int saved_errno = errno;
+  size_t length;
+
+  const char* error_name = __code_string_lookup(_sys_error_strings, error_number);
+  if (error_name != NULL) {
+    length = snprintf(buf, buf_len, "%s", error_name);
+  } else {
+    length = snprintf(buf, buf_len, "Unknown error %u", error_number);
+  }
+  if (length >= buf_len) {
+    errno = ERANGE;
+    return -1;
+  }
+
+  errno = saved_errno;
+  return 0;
+}
+
+static const Pair _sys_signal_strings[] = {
+#define  __BIONIC_SIGDEF(x,y,z)  { y, z },
+#include <sys/_sigdefs.h>
+  { 0, NULL }
+};
+
+extern "C" const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
+  const char* signal_name = __code_string_lookup(_sys_signal_strings, signal_number);
+  if (signal_name != NULL) {
+    return signal_name;
+  }
+
+  const char* prefix = "Unknown";
+  if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
+    prefix = "Real-time";
+    signal_number -= SIGRTMIN;
+  }
+  size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number);
+  if (length >= buf_len) {
+    return NULL;
+  }
+  return buf;
+}