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);