Author: Schrodinger ZHU Yifan Date: 2024-07-20T08:04:24-07:00 New Revision: 9130500ce71f5ec38182ac8b397d8e6ab846782e
URL: https://github.com/llvm/llvm-project/commit/9130500ce71f5ec38182ac8b397d8e6ab846782e DIFF: https://github.com/llvm/llvm-project/commit/9130500ce71f5ec38182ac8b397d8e6ab846782e.diff LOG: Revert "Revert "[libc] implement cached process/thread identity" (#99559)" This reverts commit 415ca24f8e392bca6f6295e667be2f02211fc303. Added: libc/src/__support/OSUtil/linux/pid.cpp libc/src/__support/OSUtil/pid.h libc/src/__support/threads/tid.h libc/src/unistd/gettid.cpp libc/src/unistd/gettid.h libc/test/src/unistd/gettid_test.cpp Modified: libc/config/config.json libc/config/linux/aarch64/entrypoints.txt libc/config/linux/riscv/entrypoints.txt libc/config/linux/x86_64/entrypoints.txt libc/docs/configure.rst libc/docs/dev/undefined_behavior.rst libc/spec/posix.td libc/src/__support/OSUtil/CMakeLists.txt libc/src/__support/OSUtil/linux/CMakeLists.txt libc/src/__support/threads/CMakeLists.txt libc/src/__support/threads/linux/CMakeLists.txt libc/src/__support/threads/linux/rwlock.h libc/src/__support/threads/linux/thread.cpp libc/src/__support/threads/thread.h libc/src/unistd/CMakeLists.txt libc/src/unistd/getpid.h libc/src/unistd/linux/CMakeLists.txt libc/src/unistd/linux/fork.cpp libc/src/unistd/linux/getpid.cpp libc/startup/linux/CMakeLists.txt libc/startup/linux/do_start.cpp libc/test/integration/src/unistd/CMakeLists.txt libc/test/integration/src/unistd/fork_test.cpp libc/test/src/unistd/CMakeLists.txt Removed: ################################################################################ diff --git a/libc/config/config.json b/libc/config/config.json index 94bfed894c173..0fc88e2b8dbd5 100644 --- a/libc/config/config.json +++ b/libc/config/config.json @@ -75,6 +75,16 @@ "LIBC_CONF_FREELIST_MALLOC_BUFFER_SIZE": { "value": 1073741824, "doc": "Default size for the constinit freelist buffer used for the freelist malloc implementation (default 1o 1GB)." + }, + }, + "unistd": { + "LIBC_CONF_ENABLE_TID_CACHE": { + "value": true, + "doc": "Enable caching mechanism for gettid to avoid syscall (only effective in fullbuild mode, default to true). Please refer to Undefined Behavior documentation for implications." + }, + "LIBC_CONF_ENABLE_PID_CACHE": { + "value": true, + "doc": "Enable caching mechanism for getpid to avoid syscall (default to true). Please refer to Undefined Behavior documentation for implications." } }, "math": { diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index e2f6bd74bb694..8afd3fb67197e 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -297,6 +297,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.geteuid libc.src.unistd.getpid libc.src.unistd.getppid + libc.src.unistd.gettid libc.src.unistd.getuid libc.src.unistd.isatty libc.src.unistd.link diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 33dd8d06173b2..f61936b758bd9 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -296,6 +296,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.geteuid libc.src.unistd.getpid libc.src.unistd.getppid + libc.src.unistd.gettid libc.src.unistd.getuid libc.src.unistd.isatty libc.src.unistd.link diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 7309e95644c74..f2029da83ee71 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -315,6 +315,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.geteuid libc.src.unistd.getpid libc.src.unistd.getppid + libc.src.unistd.gettid libc.src.unistd.getuid libc.src.unistd.isatty libc.src.unistd.link diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst index dfb35f6a6611a..5c55e4ab0f181 100644 --- a/libc/docs/configure.rst +++ b/libc/docs/configure.rst @@ -52,3 +52,6 @@ to learn about the defaults for your platform and target. * **"string" options** - ``LIBC_CONF_MEMSET_X86_USE_SOFTWARE_PREFETCHING``: Inserts prefetch for write instructions (PREFETCHW) for memset on x86 to recover performance when hardware prefetcher is disabled. - ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen. +* **"unistd" options** + - ``LIBC_CONF_ENABLE_PID_CACHE``: Enable caching mechanism for getpid to avoid syscall (default to true). Please refer to Undefined Behavior documentation for implications. + - ``LIBC_CONF_ENABLE_TID_CACHE``: Enable caching mechanism for gettid to avoid syscall (only effective in fullbuild mode, default to true). Please refer to Undefined Behavior documentation for implications. diff --git a/libc/docs/dev/undefined_behavior.rst b/libc/docs/dev/undefined_behavior.rst index 3faae3134ce2a..b712780222aa3 100644 --- a/libc/docs/dev/undefined_behavior.rst +++ b/libc/docs/dev/undefined_behavior.rst @@ -93,3 +93,26 @@ direction in this case. Non-const Constant Return Values -------------------------------- Some libc functions, like ``dlerror()``, return ``char *`` instead of ``const char *`` and then tell the caller they promise not to to modify this value. Any modification of this value is undefined behavior. + +Cached ``getpid/gettid`` +------------------------ +Since version ``2.25``, glibc removes its cache mechanism for ``getpid/gettid`` +(See the history section in https://man7.org/linux/man-pages/man2/getpid.2.html). +LLVM's libc still implements the cache as it is useful for fast deadlock detection. +The cache mechanism is also implemented in MUSL and bionic. The tid/pid cache can +be disabled by setting ``LIBC_CONF_ENABLE_TID_CACHE`` and ``LIBC_CONF_ENABLE_PID_CACHE`` +to ``false`` respectively. + +Unwrapped ``SYS_clone/SYS_fork/SYS_vfork`` +------------------------------------------ +It is highly discouraged to use unwrapped ``SYS_clone/SYS_fork/SYS_vfork``. +First, calling such syscalls without provided libc wrappers ignores +all the ``pthread_atfork`` entries as libc can no longer detect the ``fork``. +Second, libc relies on the ``fork/clone`` wrappers to correctly maintain cache for +process id and thread id, and other important process-specific states such as the list +of robust mutexes. Third, even if the user is to call ``exec*`` functions immediately, +there can still be other unexpected issues. For instance, there can be signal handlers +inherited from parent process triggered inside the instruction window between ``fork`` +and ``exec*``. As libc failed to maintain its internal states correctly, even though the +functions used inside the signal handlers are marked as ``async-signal-safe`` (such as +``getpid``), they will still return wrong values or lead to other even worse situations. diff --git a/libc/spec/posix.td b/libc/spec/posix.td index 1878b1ee2ae41..48f743dff4e6f 100644 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -546,6 +546,11 @@ def POSIX : StandardSpec<"POSIX"> { RetValSpec<PidT>, [ArgSpec<VoidType>] >, + FunctionSpec< + "gettid", + RetValSpec<PidT>, + [ArgSpec<VoidType>] + >, FunctionSpec< "getuid", RetValSpec<UidT>, @@ -601,16 +606,6 @@ def POSIX : StandardSpec<"POSIX"> { RetValSpec<IntType>, [ArgSpec<ConstCharPtr>] >, - FunctionSpec< - "getpid", - RetValSpec<IntType>, - [ArgSpec<VoidType>] - >, - FunctionSpec< - "getppid", - RetValSpec<IntType>, - [ArgSpec<VoidType>] - >, FunctionSpec< "link", RetValSpec<IntType>, diff --git a/libc/src/__support/OSUtil/CMakeLists.txt b/libc/src/__support/OSUtil/CMakeLists.txt index 94d1042ccbb4a..517f888178718 100644 --- a/libc/src/__support/OSUtil/CMakeLists.txt +++ b/libc/src/__support/OSUtil/CMakeLists.txt @@ -15,3 +15,20 @@ add_object_library( DEPENDS ${target_os_util} ) + +if (LIBC_CONF_ENABLE_PID_CACHE) + set(libc_copt_enable_pid_cache 1) +else() + set(libc_copt_enable_pid_cache 0) +endif() + +if(TARGET libc.src.__support.OSUtil.${LIBC_TARGET_OS}.pid) + add_object_library( + pid + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.pid + COMPILE_OPTIONS + -DLIBC_COPT_ENABLE_PID_CACHE=${libc_copt_enable_pid_cache} + ) +endif() diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt index 089cad454d534..95a83d77d0257 100644 --- a/libc/src/__support/OSUtil/linux/CMakeLists.txt +++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt @@ -23,3 +23,16 @@ add_object_library( libc.hdr.types.struct_f_owner_ex libc.hdr.types.off_t ) + +add_object_library( + pid + SRCS + pid.cpp + HDRS + ../pid.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.hdr.types.pid_t + libc.include.sys_syscall +) diff --git a/libc/src/__support/OSUtil/linux/pid.cpp b/libc/src/__support/OSUtil/linux/pid.cpp new file mode 100644 index 0000000000000..a8499af596229 --- /dev/null +++ b/libc/src/__support/OSUtil/linux/pid.cpp @@ -0,0 +1,20 @@ +//===------------ pid_t utilities implementation ----------------*- 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/__support/OSUtil/pid.h" +#include "src/__support/OSUtil/syscall.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { + +pid_t ProcessIdentity::cache = -1; +pid_t ProcessIdentity::get_uncached() { + return syscall_impl<pid_t>(SYS_getpid); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/OSUtil/pid.h b/libc/src/__support/OSUtil/pid.h new file mode 100644 index 0000000000000..d723abe728569 --- /dev/null +++ b/libc/src/__support/OSUtil/pid.h @@ -0,0 +1,41 @@ +//===------------ pid_t utilities -------------------------------*- 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___SUPPORT_OSUTIL_PID_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_PID_H +#include "hdr/types/pid_t.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/optimization.h" + +#ifndef LIBC_COPT_ENABLE_PID_CACHE +#define LIBC_COPT_ENABLE_PID_CACHE 1 +#endif + +namespace LIBC_NAMESPACE_DECL { + +class ProcessIdentity { + static LIBC_INLINE_VAR thread_local bool fork_inflight = true; + static pid_t cache; + static pid_t get_uncached(); + +public: + LIBC_INLINE static void start_fork() { fork_inflight = true; } + LIBC_INLINE static void end_fork() { fork_inflight = false; } + LIBC_INLINE static void refresh_cache() { cache = get_uncached(); } + LIBC_INLINE static pid_t get() { +#if LIBC_COPT_ENABLE_PID_CACHE + if (LIBC_LIKELY(!fork_inflight)) + return cache; +#endif + return get_uncached(); + } +}; + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_PID_H diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt index d2e46b8e2574e..f1a2f162acfc2 100644 --- a/libc/src/__support/threads/CMakeLists.txt +++ b/libc/src/__support/threads/CMakeLists.txt @@ -44,6 +44,12 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.mutex) ) endif() +if (LIBC_CONF_ENABLE_TID_CACHE) + set(libc_copt_enable_tid_cache 1) +else() + set(libc_copt_enable_tid_cache 0) +endif() + add_header_library( thread_common HDRS @@ -54,6 +60,9 @@ add_header_library( libc.src.__support.CPP.optional libc.src.__support.CPP.string_view libc.src.__support.CPP.stringstream + libc.hdr.types.pid_t + COMPILE_OPTIONS + -DLIBC_COPT_ENABLE_TID_CACHE=${libc_copt_enable_tid_cache} ) if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.thread) @@ -89,3 +98,21 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.CndVar) .${LIBC_TARGET_OS}.CndVar ) endif() + +set(tid_dep) +if (LLVM_LIBC_FULL_BUILD) + list(APPEND tid_dep libc.src.__support.thread) +else() + list(APPEND tid_dep libc.src.__support.OSUtil.osutil) + list(APPEND tid_dep libc.include.sys_syscall) +endif() + +add_header_library( + tid + HDRS + tid.h + DEPENDS + libc.src.__support.common + libc.hdr.types.pid_t + ${tid_dep} +) diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt index 8b7971584e77e..d86441dd67cd7 100644 --- a/libc/src/__support/threads/linux/CMakeLists.txt +++ b/libc/src/__support/threads/linux/CMakeLists.txt @@ -55,6 +55,7 @@ add_header_library( libc.src.__support.common libc.src.__support.OSUtil.osutil libc.src.__support.CPP.limits + libc.src.__support.threads.tid COMPILE_OPTIONS -DLIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT=${LIBC_CONF_RWLOCK_DEFAULT_SPIN_COUNT} ${monotonicity_flags} diff --git a/libc/src/__support/threads/linux/rwlock.h b/libc/src/__support/threads/linux/rwlock.h index d2fb0ce1a3c08..cae8aa6410686 100644 --- a/libc/src/__support/threads/linux/rwlock.h +++ b/libc/src/__support/threads/linux/rwlock.h @@ -23,6 +23,7 @@ #include "src/__support/threads/linux/futex_word.h" #include "src/__support/threads/linux/raw_mutex.h" #include "src/__support/threads/sleep.h" +#include "src/__support/threads/tid.h" #ifndef LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT #define LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT 100 @@ -336,8 +337,6 @@ class RwLock { LIBC_INLINE Role get_preference() const { return static_cast<Role>(preference); } - // TODO: use cached thread id once implemented. - LIBC_INLINE static pid_t gettid() { return syscall_impl<pid_t>(SYS_gettid); } template <Role role> LIBC_INLINE LockResult try_lock(RwState &old) { if constexpr (role == Role::Reader) { @@ -359,7 +358,7 @@ class RwLock { if (LIBC_LIKELY(old.compare_exchange_weak_with( state, old.set_writer_bit(), cpp::MemoryOrder::ACQUIRE, cpp::MemoryOrder::RELAXED))) { - writer_tid.store(gettid(), cpp::MemoryOrder::RELAXED); + writer_tid.store(gettid_inline(), cpp::MemoryOrder::RELAXED); return LockResult::Success; } // Notice that old is updated by the compare_exchange_weak_with @@ -394,7 +393,7 @@ class RwLock { unsigned spin_count = LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT) { // Phase 1: deadlock detection. // A deadlock happens if this is a RAW/WAW lock in the same thread. - if (writer_tid.load(cpp::MemoryOrder::RELAXED) == gettid()) + if (writer_tid.load(cpp::MemoryOrder::RELAXED) == gettid_inline()) return LockResult::Deadlock; #if LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY @@ -520,7 +519,7 @@ class RwLock { if (old.has_active_writer()) { // The lock is held by a writer. // Check if we are the owner of the lock. - if (writer_tid.load(cpp::MemoryOrder::RELAXED) != gettid()) + if (writer_tid.load(cpp::MemoryOrder::RELAXED) != gettid_inline()) return LockResult::PermissionDenied; // clear writer tid. writer_tid.store(0, cpp::MemoryOrder::RELAXED); diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp index 36b4a88eba9b4..c8ad086f3d1cb 100644 --- a/libc/src/__support/threads/linux/thread.cpp +++ b/libc/src/__support/threads/linux/thread.cpp @@ -518,4 +518,6 @@ void thread_exit(ThreadReturnValue retval, ThreadStyle style) { __builtin_unreachable(); } +pid_t Thread::get_uncached_tid() { return syscall_impl<pid_t>(SYS_gettid); } + } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h index ce23a880e048a..1805b6fd6182a 100644 --- a/libc/src/__support/threads/thread.h +++ b/libc/src/__support/threads/thread.h @@ -9,6 +9,11 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H #define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H +#ifndef LIBC_COPT_ENABLE_TID_CACHE +#define LIBC_COPT_ENABLE_TID_CACHE 1 +#endif + +#include "hdr/types/pid_t.h" #include "src/__support/CPP/atomic.h" #include "src/__support/CPP/optional.h" #include "src/__support/CPP/string_view.h" @@ -103,7 +108,7 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes { uintptr_t tls; // Address to the thread TLS memory uintptr_t tls_size; // The size of area pointed to by |tls|. unsigned char owned_stack; // Indicates if the thread owns this stack memory - int tid; + pid_t tid; ThreadStyle style; ThreadReturnValue retval; ThreadAtExitCallbackMgr *atexit_callback_mgr; @@ -228,6 +233,26 @@ struct Thread { // Return the name of the thread in |name|. Return the error number of error. int get_name(cpp::StringStream &name) const; + + static pid_t get_uncached_tid(); + + LIBC_INLINE void refresh_tid(pid_t cached = -1) { + if (cached >= 0) + this->attrib->tid = cached; + else + this->attrib->tid = get_uncached_tid(); + } + LIBC_INLINE void invalidate_tid() { this->attrib->tid = -1; } + + LIBC_INLINE pid_t get_tid() { +#if LIBC_COPT_ENABLE_TID_CACHE + if (LIBC_UNLIKELY(this->attrib->tid < 0)) + return get_uncached_tid(); + return this->attrib->tid; +#else + return get_uncached_tid(); +#endif + } }; extern LIBC_THREAD_LOCAL Thread self; diff --git a/libc/src/__support/threads/tid.h b/libc/src/__support/threads/tid.h new file mode 100644 index 0000000000000..a575cff508a0f --- /dev/null +++ b/libc/src/__support/threads/tid.h @@ -0,0 +1,34 @@ +//===--- Tid wrapper --------------------------------------------*- 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___SUPPORT_THREADS_TID_H +#define LLVM_LIBC_SRC___SUPPORT_THREADS_TID_H + +// This header is for internal usage which automatically dispatches full build +// and overlay build behaviors. + +#include "hdr/types/pid_t.h" +#include "src/__support/common.h" +#ifdef LIBC_FULL_BUILD +#include "src/__support/threads/thread.h" +#else +#include "src/__support/OSUtil/syscall.h" +#include <sys/syscall.h> +#endif // LIBC_FULL_BUILD + +namespace LIBC_NAMESPACE_DECL { +LIBC_INLINE pid_t gettid_inline() { +#ifdef LIBC_FULL_BUILD + return self.get_tid(); +#else + return syscall_impl<pid_t>(SYS_gettid); +#endif +} +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_TID_H diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt index ddafcd7c92f21..ec767128588f6 100644 --- a/libc/src/unistd/CMakeLists.txt +++ b/libc/src/unistd/CMakeLists.txt @@ -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 +) diff --git a/libc/src/unistd/getpid.h b/libc/src/unistd/getpid.h index c3c55b0c06b10..5812df0dfecd6 100644 --- a/libc/src/unistd/getpid.h +++ b/libc/src/unistd/getpid.h @@ -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 diff --git a/libc/src/unistd/gettid.cpp b/libc/src/unistd/gettid.cpp new file mode 100644 index 0000000000000..6d8ed65fb753d --- /dev/null +++ b/libc/src/unistd/gettid.cpp @@ -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 diff --git a/libc/src/unistd/gettid.h b/libc/src/unistd/gettid.h new file mode 100644 index 0000000000000..42283191be49b --- /dev/null +++ b/libc/src/unistd/gettid.h @@ -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 diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt index 7e733d7f002c3..651ea60d07a30 100644 --- a/libc/src/unistd/linux/CMakeLists.txt +++ b/libc/src/unistd/linux/CMakeLists.txt @@ -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 ) @@ -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( diff --git a/libc/src/unistd/linux/fork.cpp b/libc/src/unistd/linux/fork.cpp index 7d47665b16d3f..8fe1881733f34 100644 --- a/libc/src/unistd/linux/fork.cpp +++ b/libc/src/unistd/linux/fork.cpp @@ -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. @@ -25,6 +26,14 @@ 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) @@ -32,15 +41,6 @@ LLVM_LIBC_FUNCTION(pid_t, fork, (void)) { #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. @@ -48,6 +48,18 @@ LLVM_LIBC_FUNCTION(pid_t, fork, (void)) { 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; } diff --git a/libc/src/unistd/linux/getpid.cpp b/libc/src/unistd/linux/getpid.cpp index b24c86a15990f..65d6c8a3bea95 100644 --- a/libc/src/unistd/linux/getpid.cpp +++ b/libc/src/unistd/linux/getpid.cpp @@ -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 diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt index 336c5d0f6bfa2..585edf20f65be 100644 --- a/libc/startup/linux/CMakeLists.txt +++ b/libc/startup/linux/CMakeLists.txt @@ -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 diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp index 824c0e1cf8f26..4047c06ff25c1 100644 --- a/libc/startup/linux/do_start.cpp +++ b/libc/startup/linux/do_start.cpp @@ -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" @@ -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(); diff --git a/libc/test/integration/src/unistd/CMakeLists.txt b/libc/test/integration/src/unistd/CMakeLists.txt index 3f18231209512..f50405d0925e2 100644 --- a/libc/test/integration/src/unistd/CMakeLists.txt +++ b/libc/test/integration/src/unistd/CMakeLists.txt @@ -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})) diff --git a/libc/test/integration/src/unistd/fork_test.cpp b/libc/test/integration/src/unistd/fork_test.cpp index 9c9213ed46316..4b82d5f195627 100644 --- a/libc/test/integration/src/unistd/fork_test.cpp +++ b/libc/test/integration/src/unistd/fork_test.cpp @@ -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> @@ -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(); diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt index 332455b791aee..f8292653081f1 100644 --- a/libc/test/src/unistd/CMakeLists.txt +++ b/libc/test/src/unistd/CMakeLists.txt @@ -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 diff --git a/libc/test/src/unistd/gettid_test.cpp b/libc/test/src/unistd/gettid_test.cpp new file mode 100644 index 0000000000000..c2330f4002279 --- /dev/null +++ b/libc/test/src/unistd/gettid_test.cpp @@ -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); +} _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits