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
This commit is contained in:
Elliott Hughes 2024-02-24 23:55:58 +00:00
parent 6835b71819
commit 2411fff9f2
5 changed files with 93 additions and 6 deletions

View file

@ -50,11 +50,13 @@ int __clone_for_fork() {
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.

View file

@ -78,8 +78,37 @@ extern char* _Nullable * _Nullable environ;
__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);

View file

@ -1592,6 +1592,7 @@ LIBC_V { # introduced=VanillaIceCream
android_crash_detail_replace_data;
epoll_pwait2;
epoll_pwait2_64;
_Fork;
localtime_rz;
mbsrtowcs_l;
mktime_z;

View file

@ -1423,10 +1423,11 @@ static int g_atfork_child_calls = 0;
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 @@ TEST(pthread, pthread_atfork_smoke) {
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));

View file

@ -440,6 +440,22 @@ TEST(UNISTD_TEST, syncfs) {
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();