Make strerror(3) and strsignal(3) thread-safe, and add psignal(3) and psiginfo(3).
Change-Id: I426109db25e907980d6cb3a7a695796e45783b78
diff --git a/libc/Android.mk b/libc/Android.mk
index 65a738a..2604404 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -61,7 +61,6 @@
unistd/sigwait.c \
unistd/sleep.c \
unistd/statfs.c \
- unistd/strsignal.c \
unistd/syslog.c \
unistd/system.c \
unistd/tcgetpgrp.c \
@@ -191,8 +190,6 @@
string/strcoll.c \
string/strcspn.c \
string/strdup.c \
- string/strerror.c \
- string/strerror_r.c \
string/strlcat.c \
string/strlcpy.c \
string/strncat.c \
@@ -291,6 +288,9 @@
bionic/sched_cpucount.c \
bionic/semaphore.c \
bionic/sha1.c \
+ bionic/strerror.cpp \
+ bionic/strerror_r.cpp \
+ bionic/strsignal.cpp \
bionic/stubs.cpp \
bionic/system_properties.c \
bionic/tdestroy.c \
@@ -332,6 +332,7 @@
libc_upstream_netbsd_src_files := \
upstream-netbsd/libc/compat-43/creat.c \
upstream-netbsd/libc/gen/nice.c \
+ upstream-netbsd/libc/gen/psignal.c \
upstream-netbsd/libc/regex/regcomp.c \
upstream-netbsd/libc/regex/regerror.c \
upstream-netbsd/libc/regex/regexec.c \
diff --git a/libc/bionic/ThreadLocalBuffer.h b/libc/bionic/ThreadLocalBuffer.h
new file mode 100644
index 0000000..99acdba
--- /dev/null
+++ b/libc/bionic/ThreadLocalBuffer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 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 _BIONIC_THREAD_LOCAL_BUFFER_H_included
+#define _BIONIC_THREAD_LOCAL_BUFFER_H_included
+
+#include <malloc.h>
+#include <pthread.h>
+
+// libstdc++ currently contains __cxa_guard_acquire and __cxa_guard_release,
+// so we make do with macros instead of a C++ class.
+// TODO: move __cxa_guard_acquire and __cxa_guard_release into libc.
+
+#define GLOBAL_INIT_THREAD_LOCAL_BUFFER(name) \
+ static pthread_once_t name ## _once; \
+ static pthread_key_t name ## _key; \
+ static void name ## _key_destroy(void* buffer) { \
+ free(buffer); \
+ } \
+ static void name ## _key_init() { \
+ pthread_key_create(&name ## _key, name ## _key_destroy); \
+ }
+
+// Leaves "name_buffer" and "name_byte_count" defined and initialized.
+#define LOCAL_INIT_THREAD_LOCAL_BUFFER(type, name, byte_count) \
+ pthread_once(&name ## _once, name ## _key_init); \
+ type name ## _buffer = reinterpret_cast<type>(pthread_getspecific(name ## _key)); \
+ if (name ## _buffer == NULL) { \
+ name ## _buffer = reinterpret_cast<type>(malloc(byte_count)); \
+ pthread_setspecific(name ## _key, name ## _buffer); \
+ } \
+ const size_t name ## _buffer_size = byte_count
+
+#endif // _BIONIC_THREAD_LOCAL_BUFFER_H_included
diff --git a/libc/unistd/strsignal.c b/libc/bionic/strerror.cpp
similarity index 80%
rename from libc/unistd/strsignal.c
rename to libc/bionic/strerror.cpp
index 171de3d..036ec8d 100644
--- a/libc/unistd/strsignal.c
+++ b/libc/bionic/strerror.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,14 +25,14 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <signal.h>
-#include <string.h>
-char*
-strsignal(int sig)
-{
- if ((unsigned)sig < NSIG)
- return (char*) sys_siglist[sig];
- else
- return "Invalid signal number";
+#include <string.h>
+#include "ThreadLocalBuffer.h"
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(strerror);
+
+char* strerror(int error_number) {
+ LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strerror, NL_TEXTMAX);
+ strerror_r(error_number, strerror_buffer, strerror_buffer_size);
+ return strerror_buffer;
}
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;
+}
diff --git a/libc/unistd/strsignal.c b/libc/bionic/strsignal.cpp
similarity index 77%
copy from libc/unistd/strsignal.c
copy to libc/bionic/strsignal.cpp
index 171de3d..1cbec9b 100644
--- a/libc/unistd/strsignal.c
+++ b/libc/bionic/strsignal.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,14 +25,15 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <signal.h>
-#include <string.h>
-char*
-strsignal(int sig)
-{
- if ((unsigned)sig < NSIG)
- return (char*) sys_siglist[sig];
- else
- return "Invalid signal number";
+#include <string.h>
+#include "ThreadLocalBuffer.h"
+
+extern "C" const char* __strsignal(int, char*, size_t);
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(strsignal);
+
+char* strsignal(int signal_number) {
+ LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strsignal, NL_TEXTMAX);
+ return const_cast<char*>(__strsignal(signal_number, strsignal_buffer, strsignal_buffer_size));
}
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 91c3b00..6432c18 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -125,6 +125,8 @@
extern int killpg(int pgrp, int sig);
extern int sigaltstack(const stack_t *ss, stack_t *oss);
+extern void psiginfo(const siginfo_t* si, const char* message);
+extern void psignal(int signal_number, const char* message);
__END_DECLS
diff --git a/libc/string/strerror.c b/libc/string/strerror.c
deleted file mode 100644
index b2ae001..0000000
--- a/libc/string/strerror.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* $OpenBSD: strerror.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */
-/*
- * Copyright (c) 1988 Regents of the University of California.
- * 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.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-#include <string.h>
-#include <limits.h>
-
-char *
-strerror(int num)
-{
- static char buf[256];
-
- (void)strerror_r(num, buf, sizeof(buf));
- return (buf);
-}
diff --git a/libc/string/strerror_r.c b/libc/string/strerror_r.c
deleted file mode 100644
index 30841f3..0000000
--- a/libc/string/strerror_r.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
-/* Public Domain <marc@snafu.org> */
-
-#define sys_siglist _sys_siglist
-
-#include <errno.h>
-#include <limits.h>
-#include <signal.h>
-#include <string.h>
-
-typedef struct {
- int code;
- const char* msg;
-} CodeString;
-
-static const char*
-__code_string_lookup( const CodeString* strings,
- int code )
-{
- int nn = 0;
-
- for (;;)
- {
- if (strings[nn].msg == NULL)
- break;
-
- if (strings[nn].code == code)
- return strings[nn].msg;
-
- nn++;
- }
- return NULL;
-}
-
-
-static const CodeString _sys_error_strings[] =
-{
-#define __BIONIC_ERRDEF(x,y,z) { x, z },
-#include <sys/_errdefs.h>
- { 0, NULL }
-};
-
-static size_t
-__digits10(unsigned int num)
-{
- size_t i = 0;
-
- do {
- num /= 10;
- i++;
- } while (num != 0);
-
- return i;
-}
-
-static int
-__itoa(int num, int sign, char *buffer, size_t start, size_t end)
-{
- size_t pos;
- unsigned int a;
- int neg;
-
- if (sign && num < 0) {
- a = -num;
- neg = 1;
- }
- else {
- a = num;
- neg = 0;
- }
-
- pos = start + __digits10(a);
- if (neg)
- pos++;
-
- if (pos < end)
- buffer[pos] = '\0';
- else
- return ERANGE;
- pos--;
- do {
- buffer[pos] = (a % 10) + '0';
- pos--;
- a /= 10;
- } while (a != 0);
- if (neg)
- buffer[pos] = '-';
- return 0;
-}
-
-
-int
-strerror_r(int errnum, char *strerrbuf, size_t buflen)
-{
- int save_errno;
- int len, ret = 0;
- const char* msg;
-
- save_errno = errno;
- msg = __code_string_lookup( _sys_error_strings, errnum );
- if (msg != NULL) {
- len = strlcpy(strerrbuf, msg, buflen);
- if ((size_t)len >= buflen)
- ret = ERANGE;
- } else {
- len = strlcpy(strerrbuf, "Unknown error: ", buflen);
- if ((size_t)len >= buflen)
- ret = ERANGE;
- else {
- int ret = __itoa(errnum, 1, strerrbuf, len, buflen);
-
- if (ret == 0)
- ret = EINVAL;
- }
- }
- return ret;
-}
-
-#if 0
-static const CodeString _sys_signal_strings[] =
-{
-#define SIGDEF(x,y,z) { y, z },
-#include <sys/_sigdefs.h>
-};
-
-
-static int
-__num2string(int num, int sign, int setid, char *buf, size_t buflen,
- char * list[], size_t max, const char *def)
-{
- int ret = 0;
- size_t len;
-
- if (0 <= num && num < max) {
- len = strlcpy(buf, def, buflen);
- if (len >= buflen)
- ret = ERANGE;
- } else {
- len = strlcpy(buf, def, buflen);
- if (len >= buflen)
- ret = ERANGE;
- else {
- ret = __itoa(num, sign, buf, len, buflen);
- if (ret == 0)
- ret = EINVAL;
- }
- }
-
- return ret;
-}
-
-
-
-#define USIGPREFIX "Unknown signal: "
-
-char *
-__strsignal(int num, char *buf)
-{
- __num2string(num, 0, 2, buf, NL_TEXTMAX, (char **)sys_siglist, NSIG,
- USIGPREFIX);
- return buf;
-}
-#endif
diff --git a/libc/upstream-netbsd/extern.h b/libc/upstream-netbsd/extern.h
new file mode 100644
index 0000000..942e237
--- /dev/null
+++ b/libc/upstream-netbsd/extern.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BIONIC_NETBSD_EXTERN_H_included
+#define _BIONIC_NETBSD_EXTERN_H_included
+
+// Placeholder.
+
+#endif
diff --git a/libc/upstream-netbsd/libc/gen/psignal.c b/libc/upstream-netbsd/libc/gen/psignal.c
new file mode 100644
index 0000000..4472be6
--- /dev/null
+++ b/libc/upstream-netbsd/libc/gen/psignal.c
@@ -0,0 +1,85 @@
+/* $NetBSD: psignal.c,v 1.23 2012/03/13 21:13:36 christos Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)psignal.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: psignal.c,v 1.23 2012/03/13 21:13:36 christos Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#ifdef __weak_alias
+__weak_alias(psignal,_psignal)
+#endif
+
+void
+psignal(int sig, const char *s)
+{
+ struct iovec *v;
+ struct iovec iov[4];
+ char buf[NL_TEXTMAX];
+
+ v = iov;
+ if (s && *s) {
+ v->iov_base = __UNCONST(s);
+ v->iov_len = strlen(s);
+ v++;
+ v->iov_base = __UNCONST(": ");
+ v->iov_len = 2;
+ v++;
+ }
+ v->iov_base = __UNCONST(__strsignal((int)sig, buf, sizeof(buf)));
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ v->iov_base = __UNCONST("\n");
+ v->iov_len = 1;
+ (void)writev(STDERR_FILENO, iov, (int)((v - iov) + 1));
+}
+
+void
+psiginfo(const siginfo_t *si, const char *s)
+{
+ psignal(si->si_signo, s);
+}