Upstream atexit

Change-Id: Ia454a2181b5058ed9783dc02b6b1805d0e4d2715
diff --git a/libc/Android.mk b/libc/Android.mk
index 765f4d2..59cc3b8 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -67,7 +67,6 @@
     bionic/unlockpt.c \
     stdio/snprintf.c\
     stdio/sprintf.c \
-    stdlib/atexit.c \
     unistd/syslog.c \
 
 # Fortify implementations of libc functions.
@@ -463,6 +462,7 @@
     upstream-openbsd/lib/libc/stdio/wprintf.c \
     upstream-openbsd/lib/libc/stdio/wscanf.c \
     upstream-openbsd/lib/libc/stdio/wsetup.c \
+    upstream-openbsd/lib/libc/stdlib/atexit.c \
     upstream-openbsd/lib/libc/stdlib/atoi.c \
     upstream-openbsd/lib/libc/stdlib/atol.c \
     upstream-openbsd/lib/libc/stdlib/atoll.c \
@@ -549,7 +549,6 @@
 # Define some common includes
 # ========================================================
 libc_common_c_includes += \
-    $(LOCAL_PATH)/stdlib  \
     $(LOCAL_PATH)/stdio   \
 
 # ========================================================
@@ -735,6 +734,7 @@
 LOCAL_CFLAGS := \
     $(libc_common_cflags) \
     -Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter \
+    -I$(LOCAL_PATH)/private \
     -I$(LOCAL_PATH)/upstream-openbsd/android/include \
     -I$(LOCAL_PATH)/upstream-openbsd/lib/libc/include \
     -I$(LOCAL_PATH)/upstream-openbsd/lib/libc/gdtoa/ \
@@ -767,6 +767,7 @@
     $(libc_common_cflags) \
     -Wno-sign-compare -Wno-uninitialized \
     -fvisibility=hidden \
+    -I$(LOCAL_PATH)/private \
     -I$(LOCAL_PATH)/upstream-openbsd/android/include \
     -I$(LOCAL_PATH)/upstream-openbsd/lib/libc/include \
     -include openbsd-compat.h \
diff --git a/libc/bionic/abort.cpp b/libc/bionic/abort.cpp
index 69ac0e5..75413c6 100644
--- a/libc/bionic/abort.cpp
+++ b/libc/bionic/abort.cpp
@@ -30,7 +30,6 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include "atexit.h"
 
 #ifdef __arm__
 extern "C" __LIBC_HIDDEN__ void __libc_android_abort()
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index fa61c3c..aa76650 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -39,7 +39,6 @@
 #include <sys/resource.h>
 #include <unistd.h>
 
-#include "atexit.h"
 #include "private/bionic_auxv.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_tls.h"
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 7c46364..78125f9 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -48,7 +48,6 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <elf.h>
-#include "atexit.h"
 #include "libc_init_common.h"
 
 #include "private/bionic_tls.h"
@@ -58,6 +57,7 @@
   extern void malloc_debug_init(void);
   extern void malloc_debug_fini(void);
   extern void netdClientInit(void);
+  extern int __cxa_atexit(void (*)(void *), void *, void *);
 };
 
 // We flag the __libc_preinit function as a constructor to ensure
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index ab0b3a6..bc11f3d 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -46,7 +46,6 @@
 #include <sys/auxv.h>
 #include <sys/mman.h>
 
-#include "atexit.h"
 #include "libc_init_common.h"
 #include "pthread_internal.h"
 
@@ -60,6 +59,8 @@
 // itself at the start of a page.
 #define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
 
+extern "C" int __cxa_atexit(void (*)(void *), void *, void *);
+
 static void call_array(void(**list)()) {
   // First element is -1, list is null-terminated
   while (*++list) {
diff --git a/libc/private/thread_private.h b/libc/private/thread_private.h
index 724808a..b8b1a81 100644
--- a/libc/private/thread_private.h
+++ b/libc/private/thread_private.h
@@ -33,8 +33,12 @@
 #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
 	pthread_mutex_unlock( &__THREAD_NAME(name)._private_lock )
 
-__LIBC_HIDDEN__ void	_thread_atexit_lock(void);
-__LIBC_HIDDEN__ void	_thread_atexit_unlock(void);
+/* Note that these aren't compatible with the usual OpenBSD ones which lazy-initialize! */
+#define _MUTEX_LOCK(l) pthread_mutex_lock((pthread_mutex_t*) l)
+#define _MUTEX_UNLOCK(l) pthread_mutex_unlock((pthread_mutex_t*) l)
+
+__LIBC_HIDDEN__ void  _thread_atexit_lock(void);
+__LIBC_HIDDEN__ void  _thread_atexit_unlock(void);
 
 #define _ATEXIT_LOCK() _thread_atexit_lock()
 #define _ATEXIT_UNLOCK() _thread_atexit_unlock()
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
deleted file mode 100644
index e10238b..0000000
--- a/libc/stdlib/atexit.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*	$OpenBSD: atexit.c,v 1.14 2007/09/05 20:47:47 chl Exp $ */
-/*
- * Copyright (c) 2002 Daniel Hartmeier
- * 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 HOLDERS 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/types.h>
-#include <sys/mman.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "atexit.h"
-#include "private/thread_private.h"
-
-struct atexit *__atexit;
-
-/*
- * TODO: Read this before upstreaming:
- *
- * As of Apr 2014 there is a bug regaring function type detection logic in
- * Free/Open/NetBSD implementations of __cxa_finalize().
- *
- * What it is about:
- * First of all there are two kind of atexit handlers:
- *  1) void handler(void) - this is the regular type
- *     available for to user via atexit(.) function call.
- *
- *  2) void internal_handler(void*) - this is the type
- *     __cxa_atexit() function expects. This handler is used
- *     by C++ compiler to register static destructor calls.
- *     Note that calling this function as the handler of type (1)
- *     results in incorrect this pointer in static d-tors.
- *
- * What is wrong with BSD implementations:
- *
- *  They use dso argument to identify the handler type. The problem
- *  with it is dso is also used to identify the handlers associated
- *  with particular dynamic library and allow __cxa_finalize to call correct
- *  set of functions on dlclose(). And it cannot identify both.
- *
- * What is correct way to identify function type?
- *
- *  Consider this:
- *  1. __cxa_finalize and __cxa_atexit are part of libc and do not have access to hidden
- *     &__dso_handle.
- *  2. __cxa_atexit has only 3 arguments: function pointer, function argument, dso.
- *     none of them can be reliably used to pass information about handler type.
- *  3. following http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor (3.3.5.3 - B)
- *     translation of user atexit -> __cxa_atexit(f, NULL, NULL) results in crashes
- *     on exit() after dlclose() of a library with an atexit() call.
- *
- *  One way to resolve this is to always call second form of handler, which will
- *  result in storing unused argument in register/stack depending on architecture
- *  and should not present any problems.
- *
- *  Another way is to make them dso-local in one way or the other.
- */
-
-/*
- * Function pointers are stored in a linked list of pages. The list
- * is initially empty, and pages are allocated on demand. The first
- * function pointer in the first allocated page (the last one in
- * the linked list) was reserved for the cleanup function.
- *
- * Outside the following functions, all pages are mprotect()'ed
- * to prevent unintentional/malicious corruption.
- */
-
-/*
- * Register a function to be performed at exit or when a shared object
- * with the given dso handle is unloaded dynamically.  Also used as
- * the backend for atexit().  For more info on this API, see:
- *
- *	http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor
- */
-int
-__cxa_atexit(void (*func)(void *), void *arg, void *dso)
-{
-	struct atexit *p = __atexit;
-	struct atexit_fn *fnp;
-	size_t pgsize = getpagesize();
-	int ret = -1;
-
-	if (pgsize < sizeof(*p))
-		return (-1);
-	_ATEXIT_LOCK();
-	p = __atexit;
-	if (p != NULL) {
-		if (p->ind + 1 >= p->max)
-			p = NULL;
-		else if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
-			goto unlock;
-	}
-	if (p == NULL) {
-		p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
-		    MAP_ANON | MAP_PRIVATE, -1, 0);
-		if (p == MAP_FAILED)
-			goto unlock;
-		if (__atexit == NULL) {
-			memset(&p->fns[0], 0, sizeof(p->fns[0]));
-			p->ind = 1;
-		} else
-			p->ind = 0;
-		p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
-		    sizeof(p->fns[0]);
-		p->next = __atexit;
-		__atexit = p;
-	}
-	fnp = &p->fns[p->ind++];
-	fnp->cxa_func = func;
-	fnp->fn_arg = arg;
-	fnp->fn_dso = dso;
-	if (mprotect(p, pgsize, PROT_READ))
-		goto unlock;
-	ret = 0;
-unlock:
-	_ATEXIT_UNLOCK();
-	return (ret);
-}
-
-/*
- * Call all handlers registered with __cxa_atexit() for the shared
- * object owning 'dso'.
- * Note: if 'dso' is NULL, then all remaining handlers are called.
- */
-void
-__cxa_finalize(void *dso)
-{
-	struct atexit *p, *q, *original_atexit;
-	struct atexit_fn fn;
-	int n, pgsize = getpagesize(), original_ind;
-	static int call_depth;
-
-	_ATEXIT_LOCK();
-	call_depth++;
-
-	p = original_atexit = __atexit;
-	n = original_ind = p != NULL ? p->ind : 0;
-	while (p != NULL) {
-		if (p->fns[n].cxa_func != NULL /* not called */
-				&& (dso == NULL || dso == p->fns[n].fn_dso)) { /* correct DSO */
-			/*
-			 * Mark handler as having been already called to avoid
-			 * dupes and loops, then call the appropriate function.
-			 */
-			fn = p->fns[n];
-			if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) {
-				p->fns[n].cxa_func = NULL;
-				mprotect(p, pgsize, PROT_READ);
-			}
-
-			_ATEXIT_UNLOCK();
-			(*fn.cxa_func)(fn.fn_arg);
-			_ATEXIT_LOCK();
-			// check for new atexit handlers
-			if ((__atexit->ind != original_ind) || (__atexit != original_atexit)) {
-				// need to restart now to preserve correct
-				// call order - LIFO
-				p = original_atexit = __atexit;
-				n = original_ind = p->ind;
-				continue;
-			}
-		}
-		if (n == 0) {
-			p = p->next;
-			n = p != NULL ? p->ind : 0;
-		} else {
-			--n;
-		}
-	}
-
-	--call_depth;
-
-	/*
-	 * If called via exit(), unmap the pages since we have now run
-	 * all the handlers.  We defer this until calldepth == 0 so that
-	 * we don't unmap things prematurely if called recursively.
-	 */
-	if (dso == NULL && call_depth == 0) {
-		for (p = __atexit; p != NULL; ) {
-			q = p;
-			p = p->next;
-			munmap(q, pgsize);
-		}
-		__atexit = NULL;
-	}
-	_ATEXIT_UNLOCK();
-}
-
-/*
- * Register the cleanup function
- */
-void
-__atexit_register_cleanup(void (*func)(void))
-{
-        struct atexit *p;
-        size_t pgsize = getpagesize();
-
-        if (pgsize < sizeof(*p))
-                return;
-        _ATEXIT_LOCK();
-        p = __atexit;
-        while (p != NULL && p->next != NULL)
-                p = p->next;
-        if (p == NULL) {
-                p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
-                    MAP_ANON | MAP_PRIVATE, -1, 0);
-                if (p == MAP_FAILED)
-                        goto unlock;
-                p->ind = 1;
-                p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
-                    sizeof(p->fns[0]);
-                p->next = NULL;
-                __atexit = p;
-        } else {
-                if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
-                        goto unlock;
-        }
-        p->fns[0].cxa_func = (void (*)(void*))func;
-        p->fns[0].fn_arg = NULL;
-        p->fns[0].fn_dso = NULL;
-        mprotect(p, pgsize, PROT_READ);
-unlock:
-        _ATEXIT_UNLOCK();
-}
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index f00d91a..cf63907 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -40,4 +40,6 @@
 __LIBC64_HIDDEN__ extern const short *_tolower_tab_;
 __LIBC64_HIDDEN__ extern const short *_toupper_tab_;
 
+__LIBC_HIDDEN__ extern struct atexit *__atexit;
+
 #endif
diff --git a/libc/upstream-openbsd/android/include/thread_private.h b/libc/upstream-openbsd/android/include/thread_private.h
deleted file mode 100644
index 10421e2..0000000
--- a/libc/upstream-openbsd/android/include/thread_private.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2014 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 _THREAD_PRIVATE_H_
-#define _THREAD_PRIVATE_H_
-
-#include <pthread.h>
-
-/* Note that these aren't compatible with the usual OpenBSD ones which lazy-initialize! */
-#define _MUTEX_LOCK(l) pthread_mutex_lock((pthread_mutex_t*) l)
-#define _MUTEX_UNLOCK(l) pthread_mutex_unlock((pthread_mutex_t*) l)
-
-#endif /* _THREAD_PRIVATE_H_ */
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/atexit.c b/libc/upstream-openbsd/lib/libc/stdlib/atexit.c
new file mode 100644
index 0000000..6532b38
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdlib/atexit.c
@@ -0,0 +1,202 @@
+/*	$OpenBSD: atexit.c,v 1.20 2014/07/11 09:51:37 kettenis Exp $ */
+/*
+ * Copyright (c) 2002 Daniel Hartmeier
+ * 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 HOLDERS 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/types.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "atexit.h"
+#include "thread_private.h"
+
+struct atexit *__atexit;
+static int restartloop;
+
+/*
+ * Function pointers are stored in a linked list of pages. The list
+ * is initially empty, and pages are allocated on demand. The first
+ * function pointer in the first allocated page (the last one in
+ * the linked list) is reserved for the cleanup function.
+ *
+ * Outside the following functions, all pages are mprotect()'ed
+ * to prevent unintentional/malicious corruption.
+ */
+
+/*
+ * Register a function to be performed at exit or when a shared object
+ * with the given dso handle is unloaded dynamically.  Also used as
+ * the backend for atexit().  For more info on this API, see:
+ *
+ *	http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor
+ */
+int
+__cxa_atexit(void (*func)(void *), void *arg, void *dso)
+{
+	struct atexit *p = __atexit;
+	struct atexit_fn *fnp;
+	int pgsize = getpagesize();
+	int ret = -1;
+
+	if (pgsize < sizeof(*p))
+		return (-1);
+	_ATEXIT_LOCK();
+	p = __atexit;
+	if (p != NULL) {
+		if (p->ind + 1 >= p->max)
+			p = NULL;
+		else if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
+			goto unlock;
+	}
+	if (p == NULL) {
+		p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
+		    MAP_ANON | MAP_PRIVATE, -1, 0);
+		if (p == MAP_FAILED)
+			goto unlock;
+		if (__atexit == NULL) {
+			memset(&p->fns[0], 0, sizeof(p->fns[0]));
+			p->ind = 1;
+		} else
+			p->ind = 0;
+		p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
+		    sizeof(p->fns[0]);
+		p->next = __atexit;
+		__atexit = p;
+	}
+	fnp = &p->fns[p->ind++];
+	fnp->fn_ptr = func;
+	fnp->fn_arg = arg;
+	fnp->fn_dso = dso;
+	if (mprotect(p, pgsize, PROT_READ))
+		goto unlock;
+	restartloop = 1;
+	ret = 0;
+unlock:
+	_ATEXIT_UNLOCK();
+	return (ret);
+}
+
+/*
+ * Call all handlers registered with __cxa_atexit() for the shared
+ * object owning 'dso'.
+ * Note: if 'dso' is NULL, then all remaining handlers are called.
+ */
+void
+__cxa_finalize(void *dso)
+{
+	struct atexit *p, *q;
+	struct atexit_fn fn;
+	int n, pgsize = getpagesize();
+	static int call_depth;
+
+	_ATEXIT_LOCK();
+	call_depth++;
+
+restart:
+	restartloop = 0;
+	for (p = __atexit; p != NULL; p = p->next) {
+		for (n = p->ind; --n >= 0;) {
+			if (p->fns[n].fn_ptr == NULL)
+				continue;	/* already called */
+			if (dso != NULL && dso != p->fns[n].fn_dso)
+				continue;	/* wrong DSO */
+
+			/*
+			 * Mark handler as having been already called to avoid
+			 * dupes and loops, then call the appropriate function.
+			 */
+			fn = p->fns[n];
+			if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) {
+				p->fns[n].fn_ptr = NULL;
+				mprotect(p, pgsize, PROT_READ);
+			}
+			_ATEXIT_UNLOCK();
+			(*fn.fn_ptr)(fn.fn_arg);
+			_ATEXIT_LOCK();
+			if (restartloop)
+				goto restart;
+		}
+	}
+
+	call_depth--;
+
+	/*
+	 * If called via exit(), unmap the pages since we have now run
+	 * all the handlers.  We defer this until calldepth == 0 so that
+	 * we don't unmap things prematurely if called recursively.
+	 */
+	if (dso == NULL && call_depth == 0) {
+		for (p = __atexit; p != NULL; ) {
+			q = p;
+			p = p->next;
+			munmap(q, pgsize);
+		}
+		__atexit = NULL;
+	}
+	_ATEXIT_UNLOCK();
+}
+
+/*
+ * Register the cleanup function
+ */
+void
+__atexit_register_cleanup(void (*func)(void))
+{
+	struct atexit *p;
+	int pgsize = getpagesize();
+
+	if (pgsize < sizeof(*p))
+		return;
+	_ATEXIT_LOCK();
+	p = __atexit;
+	while (p != NULL && p->next != NULL)
+		p = p->next;
+	if (p == NULL) {
+		p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
+		    MAP_ANON | MAP_PRIVATE, -1, 0);
+		if (p == MAP_FAILED)
+			goto unlock;
+		p->ind = 1;
+		p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
+		    sizeof(p->fns[0]);
+		p->next = NULL;
+		__atexit = p;
+	} else {
+		if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
+			goto unlock;
+	}
+	p->fns[0].fn_ptr = (void (*)(void *))func;
+	p->fns[0].fn_arg = NULL;
+	p->fns[0].fn_dso = NULL;
+	mprotect(p, pgsize, PROT_READ);
+	restartloop = 1;
+unlock:
+	_ATEXIT_UNLOCK();
+}
diff --git a/libc/stdlib/atexit.h b/libc/upstream-openbsd/lib/libc/stdlib/atexit.h
similarity index 88%
rename from libc/stdlib/atexit.h
rename to libc/upstream-openbsd/lib/libc/stdlib/atexit.h
index b530ade..3de2aa3 100644
--- a/libc/stdlib/atexit.h
+++ b/libc/upstream-openbsd/lib/libc/stdlib/atexit.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: atexit.h,v 1.7 2007/09/03 14:40:16 millert Exp $ */
+/*	$OpenBSD: atexit.h,v 1.9 2014/06/18 19:01:10 kettenis Exp $ */
 
 /*
  * Copyright (c) 2002 Daniel Hartmeier
@@ -30,24 +30,18 @@
  *
  */
 
-#include <sys/cdefs.h>
-
 struct atexit {
 	struct atexit *next;		/* next in list */
 	int ind;			/* next index in this table */
 	int max;			/* max entries >= ATEXIT_SIZE */
 	struct atexit_fn {
-		void (*cxa_func)(void *);
+		void (*fn_ptr)(void *);
 		void *fn_arg;		/* argument for CXA callback */
 		void *fn_dso;		/* shared module handle */
 	} fns[1];			/* the table itself */
 };
 
-__BEGIN_DECLS
-
-__LIBC_HIDDEN__ extern struct atexit *__atexit;		/* points to head of LIFO stack */
+extern struct atexit *__atexit;		/* points to head of LIFO stack */
 
 int	__cxa_atexit(void (*)(void *), void *, void *);
 void	__cxa_finalize(void *);
-
-__END_DECLS