Register _cleanup function with atexit

 * Register cleanup function with atexit
   instead of calling it explicitly on
   exit()
 * abort() no longer calls _cleanup:
   Flushing stdio buffers on abort is no
   longer required by POSIX.
 * dlmalloc no longer need to reset cleanup
   (see above)
 * Upstream findfp.c makebuf.c setvbuf.cexit.c
   to openbsd versions.

Bug: 14415367
Change-Id: I277058852485a9d3dbb13e5c232db5f9948d78ac
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index b051e22..c607206 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -104,10 +104,10 @@
 {
 	struct atexit *p = __atexit;
 	struct atexit_fn *fnp;
-	int pgsize = getpagesize();
+	size_t pgsize = sysconf(_SC_PAGESIZE);
 	int ret = -1;
 
-	if (pgsize < (int)sizeof(*p))
+	if (pgsize < sizeof(*p))
 		return (-1);
 	_ATEXIT_LOCK();
 	p = __atexit;
@@ -216,3 +216,41 @@
 	}
 	_ATEXIT_UNLOCK();
 }
+
+/*
+ * Register the cleanup function
+ */
+void
+__atexit_register_cleanup(void (*func)(void))
+{
+        struct atexit *p;
+        size_t pgsize = sysconf(_SC_PAGESIZE);
+
+        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();
+}
+