void* new_tls = NULL;
int* child_tid = NULL;
- if (!child_stack) {
+ if (fn != nullptr && child_stack == nullptr) {
errno = EINVAL;
return -1;
}
pid_t parent_pid = self->invalidate_cached_pid();
// Actually do the clone.
- int clone_result = __bionic_clone(flags, child_stack, parent_tid, new_tls, child_tid, fn, arg);
+ int clone_result;
+ if (fn != nullptr) {
+ clone_result = __bionic_clone(flags, child_stack, parent_tid, new_tls, child_tid, fn, arg);
+ } else {
+#if defined(__x86_64__) // sys_clone's last two arguments are flipped on x86-64.
+ clone_result = syscall(__NR_clone, flags, child_stack, parent_tid, child_tid, new_tls);
+#else
+ clone_result = syscall(__NR_clone, flags, child_stack, parent_tid, new_tls, child_tid);
+#endif
+ }
// We're the parent, so put our known pid back in place.
// We leave the child without a cached pid, but:
#include "pthread_internal.h"
-#define FORK_FLAGS (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD)
-
int fork() {
__bionic_atfork_run_prepare();
// Remember the parent pid and invalidate the cached value while we fork.
pid_t parent_pid = self->invalidate_cached_pid();
-#if defined(__x86_64__) // sys_clone's last two arguments are flipped on x86-64.
- int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, &(self->tid), NULL);
-#else
- int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, NULL, &(self->tid));
-#endif
+ int result = clone(nullptr,
+ nullptr,
+ (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD),
+ nullptr,
+ nullptr,
+ nullptr,
+ &(self->tid));
if (result == 0) {
self->set_cached_pid(gettid());
__bionic_atfork_run_child();
// Check that our hand-written clone assembler sets errno correctly on failure.
uintptr_t fake_child_stack[16];
errno = 0;
- ASSERT_EQ(-1, clone(NULL, &fake_child_stack[16], CLONE_THREAD, NULL));
+ // If CLONE_THREAD is set, CLONE_SIGHAND must be set too.
+ ASSERT_EQ(-1, clone(child_fn, &fake_child_stack[16], CLONE_THREAD, NULL));
ASSERT_EQ(EINVAL, errno);
}