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:
parent
6835b71819
commit
2411fff9f2
5 changed files with 93 additions and 6 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue