10 changes: 10 additions & 0 deletions libc/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,13 @@ add_entrypoint_external(
add_entrypoint_external(
opterr
)

add_entrypoint_object(
gettid
SRCS
gettid.cpp
HDRS
gettid.h
DEPENDS
libc.src.__support.threads.tid
)
4 changes: 2 additions & 2 deletions libc/src/unistd/getpid.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
#ifndef LLVM_LIBC_SRC_UNISTD_GETPID_H
#define LLVM_LIBC_SRC_UNISTD_GETPID_H

#include "hdr/types/pid_t.h"
#include "src/__support/macros/config.h"
#include <unistd.h>

namespace LIBC_NAMESPACE_DECL {

pid_t getpid();
pid_t getpid(void);

} // namespace LIBC_NAMESPACE_DECL

Expand Down
17 changes: 17 additions & 0 deletions libc/src/unistd/gettid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//===-- Implementation file for gettid --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/unistd/gettid.h"
#include "src/__support/common.h"
#include "src/__support/threads/tid.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(pid_t, gettid, (void)) { return gettid_inline(); }

} // namespace LIBC_NAMESPACE_DECL
21 changes: 21 additions & 0 deletions libc/src/unistd/gettid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Implementation header for gettid ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_UNISTD_GETTID_H
#define LLVM_LIBC_SRC_UNISTD_GETTID_H

#include "hdr/types/pid_t.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE_DECL {

pid_t gettid(void);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_UNISTD_GETTID_H
4 changes: 2 additions & 2 deletions libc/src/unistd/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ add_entrypoint_object(
libc.include.sys_syscall
libc.src.__support.threads.fork_callbacks
libc.src.__support.OSUtil.osutil
libc.src.__support.OSUtil.pid
libc.src.__support.threads.thread
libc.src.errno.errno
)
Expand Down Expand Up @@ -204,8 +205,7 @@ add_entrypoint_object(
../getpid.h
DEPENDS
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.__support.OSUtil.pid
)

add_entrypoint_object(
Expand Down
32 changes: 22 additions & 10 deletions libc/src/unistd/linux/fork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@

#include "src/unistd/fork.h"

#include "src/__support/OSUtil/pid.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/fork_callbacks.h"
#include "src/__support/threads/thread.h" // For thread self object

#include "src/errno/libc_errno.h"

#include <signal.h> // For SIGCHLD
#include <sys/syscall.h> // For syscall numbers.

Expand All @@ -25,29 +26,40 @@ namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(pid_t, fork, (void)) {
invoke_prepare_callbacks();

// Invalidate tid/pid cache before fork to avoid post fork signal handler from
// getting wrong values. gettid() is not async-signal-safe, but let's provide
// our best efforts here.
pid_t parent_tid = self.get_tid();
self.invalidate_tid();
ProcessIdentity::start_fork();

#ifdef SYS_fork
pid_t ret = LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_fork);
#elif defined(SYS_clone)
pid_t ret = LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_clone, SIGCHLD, 0);
#else
#error "fork and clone syscalls not available."
#endif
if (ret == 0) {
// Return value is 0 in the child process.
// The child is created with a single thread whose self object will be a
// copy of parent process' thread which called fork. So, we have to fix up
// the child process' self object with the new process' tid.
self.attrib->tid = LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_gettid);
invoke_child_callbacks();
return 0;
}

if (ret < 0) {
// Error case, a child process was not created.
libc_errno = static_cast<int>(-ret);
return -1;
}

// Child process
if (ret == 0) {
self.refresh_tid();
ProcessIdentity::refresh_cache();
ProcessIdentity::end_fork();
invoke_child_callbacks();
return 0;
}

// Parent process
self.refresh_tid(parent_tid);
ProcessIdentity::end_fork();
invoke_parent_callbacks();
return ret;
}
Expand Down
11 changes: 2 additions & 9 deletions libc/src/unistd/linux/getpid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,10 @@
//===----------------------------------------------------------------------===//

#include "src/unistd/getpid.h"

#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/OSUtil/pid.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"

#include <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(pid_t, getpid, ()) {
return LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_getpid);
}
LLVM_LIBC_FUNCTION(pid_t, getpid, (void)) { return ProcessIdentity::get(); }

} // namespace LIBC_NAMESPACE_DECL
1 change: 1 addition & 0 deletions libc/startup/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ add_object_library(
libc.include.llvm-libc-macros.link_macros
libc.src.__support.threads.thread
libc.src.__support.OSUtil.osutil
libc.src.__support.OSUtil.pid
libc.src.stdlib.exit
libc.src.stdlib.atexit
libc.src.unistd.environ
Expand Down
5 changes: 5 additions & 0 deletions libc/startup/linux/do_start.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "startup/linux/do_start.h"
#include "include/llvm-libc-macros/link-macros.h"
#include "src/__support/OSUtil/pid.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/thread.h"
Expand Down Expand Up @@ -127,6 +128,10 @@ static ThreadAttributes main_thread_attrib;
if (tls.size != 0 && !set_thread_ptr(tls.tp))
syscall_impl<long>(SYS_exit, 1);

// Validate process identity cache (TLS needed).
ProcessIdentity::refresh_cache();
ProcessIdentity::end_fork();

self.attrib = &main_thread_attrib;
main_thread_attrib.atexit_callback_mgr =
internal::get_thread_atexit_callback_mgr();
Expand Down
4 changes: 4 additions & 0 deletions libc/test/integration/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ add_integration_test(
libc.src.sys.wait.wait4
libc.src.sys.wait.waitpid
libc.src.unistd.fork
libc.src.unistd.getpid
libc.src.unistd.gettid
libc.src.stdlib.exit
libc.include.sys_syscall
)

if((${LIBC_TARGET_OS} STREQUAL "linux") AND (${LIBC_TARGET_ARCHITECTURE_IS_X86}))
Expand Down
24 changes: 23 additions & 1 deletion libc/test/integration/src/unistd/fork_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
//
//===----------------------------------------------------------------------===//

#include "src/__support/OSUtil/syscall.h"
#include "src/pthread/pthread_atfork.h"
#include "src/signal/raise.h"
#include "src/stdlib/exit.h"
#include "src/sys/wait/wait.h"
#include "src/sys/wait/wait4.h"
#include "src/sys/wait/waitpid.h"
#include "src/unistd/fork.h"

#include "src/unistd/getpid.h"
#include "src/unistd/gettid.h"
#include "test/IntegrationTest/test.h"

#include <errno.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>

Expand Down Expand Up @@ -140,7 +144,25 @@ void fork_with_atfork_callbacks() {
ASSERT_NE(child, DONE);
}

void fork_pid_tid_test() {
pid_t pid = fork();
ASSERT_TRUE(pid >= 0);
ASSERT_EQ(LIBC_NAMESPACE::gettid(),
LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_gettid));
ASSERT_EQ(LIBC_NAMESPACE::getpid(),
LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_getpid));

if (pid == 0) {
LIBC_NAMESPACE::exit(0);
} else {
int status;
LIBC_NAMESPACE::waitpid(pid, &status, 0);
ASSERT_EQ(status, 0);
}
}

TEST_MAIN(int argc, char **argv, char **envp) {
fork_pid_tid_test();
fork_and_wait_normal_exit();
fork_and_wait4_normal_exit();
fork_and_waitpid_normal_exit();
Expand Down
10 changes: 10 additions & 0 deletions libc/test/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,16 @@ add_libc_unittest(
libc.src.unistd.getpid
)

add_libc_unittest(
gettid_test
SUITE
libc_unistd_unittests
SRCS
gettid_test.cpp
DEPENDS
libc.src.unistd.gettid
)

add_libc_unittest(
getppid_test
SUITE
Expand Down
15 changes: 15 additions & 0 deletions libc/test/src/unistd/gettid_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//===-- Unittests for gettid ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/unistd/gettid.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcGetTidTest, SmokeTest) {
// gettid always succeeds. So, we just call it as a smoke test.
ASSERT_GT(LIBC_NAMESPACE::gettid(), 0);
}