Adds quick_exit(3) and at_quick_exit(3) from freebsd
Change-Id: I4fe88abd8f7b8aa45e58aeb2529d59a8d555d338
diff --git a/libc/Android.mk b/libc/Android.mk
index c0f69fd..dffdae0 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -232,6 +232,7 @@
upstream-freebsd/lib/libc/stdlib/labs.c \
upstream-freebsd/lib/libc/stdlib/llabs.c \
upstream-freebsd/lib/libc/stdlib/qsort.c \
+ upstream-freebsd/lib/libc/stdlib/quick_exit.c \
upstream-freebsd/lib/libc/stdlib/realpath.c \
upstream-freebsd/lib/libc/string/wcpcpy.c \
upstream-freebsd/lib/libc/string/wcpncpy.c \
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 6c966f7..834dcda 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -46,6 +46,11 @@
extern __noreturn void _Exit(int);
extern int atexit(void (*)(void));
+#if __ISO_C_VISIBLE >= 2011 || __cplusplus >= 201103L
+int at_quick_exit(void (*)(void));
+void quick_exit(int) __noreturn;
+#endif
+
extern char* getenv(const char*);
extern int putenv(char*);
extern int setenv(const char*, const char*, int);
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c b/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
new file mode 100644
index 0000000..ef8cdb1
--- /dev/null
+++ b/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2011 David Chisnall
+ * 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$
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+
+/**
+ * Linked list of quick exit handlers. This is simpler than the atexit()
+ * version, because it is not required to support C++ destructors or
+ * DSO-specific cleanups.
+ */
+struct quick_exit_handler {
+ struct quick_exit_handler *next;
+ void (*cleanup)(void);
+};
+
+/**
+ * Lock protecting the handlers list.
+ */
+static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
+/**
+ * Stack of cleanup handlers. These will be invoked in reverse order when
+ */
+static struct quick_exit_handler *handlers;
+
+int
+at_quick_exit(void (*func)(void))
+{
+ struct quick_exit_handler *h;
+
+ h = malloc(sizeof(*h));
+
+ if (NULL == h)
+ return (1);
+ h->cleanup = func;
+ pthread_mutex_lock(&atexit_mutex);
+ h->next = handlers;
+ handlers = h;
+ pthread_mutex_unlock(&atexit_mutex);
+ return (0);
+}
+
+void
+quick_exit(int status)
+{
+ struct quick_exit_handler *h;
+
+ /*
+ * XXX: The C++ spec requires us to call std::terminate if there is an
+ * exception here.
+ */
+ for (h = handlers; NULL != h; h = h->next)
+ h->cleanup();
+ _Exit(status);
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index 94474ff..fccf3f1 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -40,6 +40,9 @@
test_cflags += -D__STDC_LIMIT_MACROS # For glibc.
+test_cppflags = \
+ -std=gnu++11 \
+
libBionicStandardTests_src_files := \
buffer_tests.cpp \
ctype_test.cpp \
@@ -91,6 +94,9 @@
libBionicStandardTests_cflags := \
$(test_cflags) \
+libBionicStandardTests_cppflags := \
+ $(test_cppflags) \
+
libBionicStandardTests_ldlibs_host := \
-lrt \
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index bb395f0..fc0f0e1 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -203,6 +203,52 @@
ASSERT_DOUBLE_EQ(1.23, strtold("1.23", NULL));
}
+TEST(stdlib, quick_exit) {
+ pid_t pid = fork();
+ ASSERT_NE(-1, pid) << strerror(errno);
+
+ if (pid == 0) {
+ quick_exit(99);
+ }
+
+ int status;
+ ASSERT_EQ(pid, waitpid(pid, &status, 0));
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(99, WEXITSTATUS(status));
+}
+
+static int quick_exit_status = 0;
+
+static void quick_exit_1(void) {
+ ASSERT_EQ(quick_exit_status, 0);
+ quick_exit_status = 1;
+}
+
+static void quick_exit_2(void) {
+ ASSERT_EQ(quick_exit_status, 1);
+}
+
+static void not_run(void) {
+ FAIL();
+}
+
+TEST(stdlib, at_quick_exit) {
+ pid_t pid = fork();
+ ASSERT_NE(-1, pid) << strerror(errno);
+
+ if (pid == 0) {
+ ASSERT_EQ(at_quick_exit(quick_exit_2), 0);
+ ASSERT_EQ(at_quick_exit(quick_exit_1), 0);
+ atexit(not_run);
+ quick_exit(99);
+ }
+
+ int status;
+ ASSERT_EQ(pid, waitpid(pid, &status, 0));
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(99, WEXITSTATUS(status));
+}
+
TEST(unistd, _Exit) {
int pid = fork();
ASSERT_NE(-1, pid) << strerror(errno);