Add _Fork().

POSIX issue 8 function, already in musl/glibc (but not iOS/macOS).

Bug: https://austingroupbugs.net/view.php?id=62
Test: treehugger
Change-Id: Id51611afdab92dff36a540b7d8737fc0e31f3d36
diff --git a/libc/bionic/fork.cpp b/libc/bionic/fork.cpp
index d432c6d..615e81f 100644
--- a/libc/bionic/fork.cpp
+++ b/libc/bionic/fork.cpp
@@ -50,11 +50,13 @@
   return result;
 }
 
+int _Fork() {
+  return __clone_for_fork();
+}
+
 int fork() {
   __bionic_atfork_run_prepare();
-
-  int result = __clone_for_fork();
-
+  int result = _Fork();
   if (result == 0) {
     // Disable fdsan and fdtrack post-fork, so we don't falsely trigger on processes that
     // fork, close all of their fds, and then exec.
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index c8cceb2..b94197e 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -78,8 +78,37 @@
 
 __noreturn void _exit(int __status);
 
-pid_t  fork(void);
-pid_t  vfork(void) __returns_twice;
+/**
+ * [fork(2)](http://man7.org/linux/man-pages/man2/fork.2.html) creates a new
+ * process. fork() runs any handlers set by pthread_atfork().
+ *
+ * Returns 0 in the child, the pid of the child in the parent,
+ * and returns -1 and sets `errno` on failure.
+ */
+pid_t fork(void);
+
+/**
+ * _Fork() creates a new process. _Fork() differs from fork() in that it does
+ * not run any handlers set by pthread_atfork().
+ *
+ * Returns 0 in the child, the pid of the child in the parent,
+ * and returns -1 and sets `errno` on failure.
+ *
+ * Available since API level 35.
+ */
+pid_t _Fork(void) __INTRODUCED_IN(35);
+
+/**
+ * [vfork(2)](http://man7.org/linux/man-pages/man2/vfork.2.html) creates a new
+ * process. vfork() differs from fork() in that it does not run any handlers
+ * set by pthread_atfork(), and the parent is suspended until the child calls
+ * exec() or exits.
+ *
+ * Returns 0 in the child, the pid of the child in the parent,
+ * and returns -1 and sets `errno` on failure.
+ */
+pid_t vfork(void) __returns_twice;
+
 pid_t  getpid(void);
 pid_t  gettid(void) __attribute_const__;
 pid_t  getpgid(pid_t __pid);
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 5e9763b..2c8ec07 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1592,6 +1592,7 @@
     android_crash_detail_replace_data;
     epoll_pwait2;
     epoll_pwait2_64;
+    _Fork;
     localtime_rz;
     mbsrtowcs_l;
     mktime_z;
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 1a882be..2bf755b 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -1423,10 +1423,11 @@
 static void AtForkChild1() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 1; }
 static void AtForkChild2() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 2; }
 
-TEST(pthread, pthread_atfork_smoke) {
+TEST(pthread, pthread_atfork_smoke_fork) {
   ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
   ASSERT_EQ(0, pthread_atfork(AtForkPrepare2, AtForkParent2, AtForkChild2));
 
+  g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
   pid_t pid = fork();
   ASSERT_NE(-1, pid) << strerror(errno);
 
@@ -1442,6 +1443,44 @@
   AssertChildExited(pid, 0);
 }
 
+TEST(pthread, pthread_atfork_smoke_vfork) {
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare2, AtForkParent2, AtForkChild2));
+
+  g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
+  pid_t pid = vfork();
+  ASSERT_NE(-1, pid) << strerror(errno);
+
+  // atfork handlers are not called.
+  if (pid == 0) {
+    ASSERT_EQ(0, g_atfork_child_calls);
+    _exit(0);
+  }
+  ASSERT_EQ(0, g_atfork_parent_calls);
+  ASSERT_EQ(0, g_atfork_prepare_calls);
+  AssertChildExited(pid, 0);
+}
+
+TEST(pthread, pthread_atfork_smoke__Fork) {
+#if defined(__BIONIC__)
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
+  ASSERT_EQ(0, pthread_atfork(AtForkPrepare2, AtForkParent2, AtForkChild2));
+
+  g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
+  pid_t pid = _Fork();
+  ASSERT_NE(-1, pid) << strerror(errno);
+
+  // atfork handlers are not called.
+  if (pid == 0) {
+    ASSERT_EQ(0, g_atfork_child_calls);
+    _exit(0);
+  }
+  ASSERT_EQ(0, g_atfork_parent_calls);
+  ASSERT_EQ(0, g_atfork_prepare_calls);
+  AssertChildExited(pid, 0);
+#endif
+}
+
 TEST(pthread, pthread_attr_getscope) {
   pthread_attr_t attr;
   ASSERT_EQ(0, pthread_attr_init(&attr));
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 6c08972..78b55c1 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -440,6 +440,22 @@
   TestSyncFunction(syncfs);
 }
 
+TEST(UNISTD_TEST, _Fork) {
+#if defined(__BIONIC__)
+  pid_t rc = _Fork();
+  ASSERT_NE(-1, rc);
+  if (rc == 0) {
+    _exit(66);
+  }
+
+  int status;
+  pid_t wait_result = waitpid(rc, &status, 0);
+  ASSERT_EQ(wait_result, rc);
+  ASSERT_TRUE(WIFEXITED(status));
+  ASSERT_EQ(66, WEXITSTATUS(status));
+#endif
+}
+
 TEST(UNISTD_TEST, vfork) {
 #if defined(__BIONIC__)
   pthread_internal_t* self = __get_thread();