Skip to content

Commit bdf5f91

Browse files
Yifan ZhuSchrodingerZhu
authored andcommitted
[libc] implement cached process/thread identity
1 parent 8598bcb commit bdf5f91

File tree

24 files changed

+272
-38
lines changed

24 files changed

+272
-38
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ set(TARGET_LIBC_ENTRYPOINTS
290290
libc.src.unistd.geteuid
291291
libc.src.unistd.getpid
292292
libc.src.unistd.getppid
293+
libc.src.unistd.gettid
293294
libc.src.unistd.getuid
294295
libc.src.unistd.isatty
295296
libc.src.unistd.link

libc/config/linux/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ set(TARGET_LIBC_ENTRYPOINTS
295295
libc.src.unistd.geteuid
296296
libc.src.unistd.getpid
297297
libc.src.unistd.getppid
298+
libc.src.unistd.gettid
298299
libc.src.unistd.getuid
299300
libc.src.unistd.isatty
300301
libc.src.unistd.link

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ set(TARGET_LIBC_ENTRYPOINTS
308308
libc.src.unistd.geteuid
309309
libc.src.unistd.getpid
310310
libc.src.unistd.getppid
311+
libc.src.unistd.gettid
311312
libc.src.unistd.getuid
312313
libc.src.unistd.isatty
313314
libc.src.unistd.link

libc/docs/dev/undefined_behavior.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,24 @@ The C23 standard states that if the value of the ``rnd`` argument of the
8989
the value of a math rounding direction macro, the direction of rounding is
9090
unspecified. LLVM's libc chooses to use the ``FP_INT_TONEAREST`` rounding
9191
direction in this case.
92+
93+
Cached ``getpid/gettid``
94+
------------------------
95+
Since version ``2.25``, glibc removes its cache mechanism for ``getpid/gettid``
96+
(See the history section in https://man7.org/linux/man-pages/man2/getpid.2.html).
97+
LLVM's libc still implements the cache as it is useful for fast deadlock detection.
98+
The cache mechanism is also implemented in MUSL and bionic.
99+
100+
Unwrapped ``SYS_clone/SYS_fork/SYS_vfork``
101+
------------------------------------------
102+
It is highly discouraged to use unwrapped ``SYS_clone/SYS_fork/SYS_vfork``.
103+
First, calling such syscalls without provided libc wrappers ignores
104+
all the ``pthread_atfork`` entries as libc can no longer detect the ``fork``.
105+
Second, libc relies on the ``fork/clone`` wrappers to correctly maintain cache for
106+
process id and thread id, and other important process-specific states such as the list
107+
of robust mutexes. Third, even if the user is to call ``exec*`` functions immediately,
108+
there can still be other unexpected issues. For instance, there can be signal handlers
109+
inherited from parent process triggered inside the instruction window between ``fork``
110+
and ``exec*``. As libc failed to maintain its internal states correctly, even though the
111+
functions used inside the signal handlers are marked as ``async-signal-safe`` (such as
112+
``getpid``), they will still return wrong values or lead to other even worse situations.

libc/spec/posix.td

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,11 @@ def POSIX : StandardSpec<"POSIX"> {
512512
RetValSpec<PidT>,
513513
[ArgSpec<VoidType>]
514514
>,
515+
FunctionSpec<
516+
"gettid",
517+
RetValSpec<PidT>,
518+
[ArgSpec<VoidType>]
519+
>,
515520
FunctionSpec<
516521
"getuid",
517522
RetValSpec<UidT>,
@@ -567,16 +572,6 @@ def POSIX : StandardSpec<"POSIX"> {
567572
RetValSpec<IntType>,
568573
[ArgSpec<ConstCharPtr>]
569574
>,
570-
FunctionSpec<
571-
"getpid",
572-
RetValSpec<IntType>,
573-
[ArgSpec<VoidType>]
574-
>,
575-
FunctionSpec<
576-
"getppid",
577-
RetValSpec<IntType>,
578-
[ArgSpec<VoidType>]
579-
>,
580575
FunctionSpec<
581576
"link",
582577
RetValSpec<IntType>,

libc/src/__support/OSUtil/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,12 @@ add_object_library(
1515
DEPENDS
1616
${target_os_util}
1717
)
18+
19+
if(TARGET libc.src.__support.OSUtil.${LIBC_TARGET_OS}.pid)
20+
add_object_library(
21+
pid
22+
ALIAS
23+
DEPENDS
24+
.${LIBC_TARGET_OS}.pid
25+
)
26+
endif()

libc/src/__support/OSUtil/linux/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,16 @@ add_object_library(
2222
libc.hdr.types.struct_flock64
2323
libc.hdr.types.struct_f_owner_ex
2424
)
25+
26+
add_object_library(
27+
pid
28+
SRCS
29+
pid.cpp
30+
HDRS
31+
../pid.h
32+
DEPENDS
33+
libc.src.__support.OSUtil.osutil
34+
libc.src.__support.common
35+
libc.hdr.types.pid_t
36+
libc.include.sys_syscall
37+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===------------ pid_t utilities implementation ----------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/__support/OSUtil/pid.h"
10+
#include "src/__support/OSUtil/syscall.h"
11+
#include <sys/syscall.h>
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
pid_t ProcessIdentity::cache = -1;
16+
pid_t ProcessIdentity::get_uncached() {
17+
return syscall_impl<pid_t>(SYS_getpid);
18+
}
19+
20+
} // namespace LIBC_NAMESPACE

libc/src/__support/OSUtil/pid.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===------------ pid_t utilities -------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_PID_H
10+
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_PID_H
11+
#include "hdr/types/pid_t.h"
12+
#include "src/__support/macros/attributes.h"
13+
#include "src/__support/macros/optimization.h"
14+
namespace LIBC_NAMESPACE {
15+
16+
class ProcessIdentity {
17+
static pid_t cache;
18+
static pid_t get_uncached();
19+
20+
public:
21+
LIBC_INLINE static void invalidate_cache() { cache = -1; }
22+
LIBC_INLINE static void refresh_cache() { cache = get_uncached(); }
23+
LIBC_INLINE static pid_t get() {
24+
if (LIBC_UNLIKELY(cache < 0))
25+
return get_uncached();
26+
return cache;
27+
}
28+
};
29+
30+
} // namespace LIBC_NAMESPACE
31+
32+
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_PID_H

libc/src/__support/threads/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ add_header_library(
4545
libc.src.__support.CPP.optional
4646
libc.src.__support.CPP.string_view
4747
libc.src.__support.CPP.stringstream
48+
libc.hdr.types.pid_t
4849
)
4950

5051
if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.thread)
@@ -80,3 +81,21 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.CndVar)
8081
.${LIBC_TARGET_OS}.CndVar
8182
)
8283
endif()
84+
85+
set(tid_dep)
86+
if (LLVM_LIBC_FULL_BUILD)
87+
list(APPEND tid_dep libc.src.__support.thread)
88+
else()
89+
list(APPEND tid_dep libc.src.__support.OSUtil.osutil)
90+
list(APPEND tid_dep libc.include.sys_syscall)
91+
endif()
92+
93+
add_header_library(
94+
tid
95+
HDRS
96+
tid.h
97+
DEPENDS
98+
libc.src.__support.common
99+
libc.hdr.types.pid_t
100+
${tid_dep}
101+
)

libc/src/__support/threads/linux/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ add_header_library(
5555
libc.src.__support.common
5656
libc.src.__support.OSUtil.osutil
5757
libc.src.__support.CPP.limits
58+
libc.src.__support.threads.tid
5859
COMPILE_OPTIONS
5960
-DLIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT=${LIBC_CONF_RWLOCK_DEFAULT_SPIN_COUNT}
6061
${monotonicity_flags}

libc/src/__support/threads/linux/rwlock.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "src/__support/threads/linux/futex_word.h"
2323
#include "src/__support/threads/linux/raw_mutex.h"
2424
#include "src/__support/threads/sleep.h"
25+
#include "src/__support/threads/tid.h"
2526

2627
#ifndef LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT
2728
#define LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT 100
@@ -335,8 +336,6 @@ class RwLock {
335336
LIBC_INLINE Role get_preference() const {
336337
return static_cast<Role>(preference);
337338
}
338-
// TODO: use cached thread id once implemented.
339-
LIBC_INLINE static pid_t gettid() { return syscall_impl<pid_t>(SYS_gettid); }
340339

341340
template <Role role> LIBC_INLINE LockResult try_lock(RwState &old) {
342341
if constexpr (role == Role::Reader) {
@@ -358,7 +357,7 @@ class RwLock {
358357
if (LIBC_LIKELY(old.compare_exchange_weak_with(
359358
state, old.set_writer_bit(), cpp::MemoryOrder::ACQUIRE,
360359
cpp::MemoryOrder::RELAXED))) {
361-
writer_tid.store(gettid(), cpp::MemoryOrder::RELAXED);
360+
writer_tid.store(gettid_inline(), cpp::MemoryOrder::RELAXED);
362361
return LockResult::Success;
363362
}
364363
// Notice that old is updated by the compare_exchange_weak_with
@@ -393,7 +392,7 @@ class RwLock {
393392
unsigned spin_count = LIBC_COPT_RWLOCK_DEFAULT_SPIN_COUNT) {
394393
// Phase 1: deadlock detection.
395394
// A deadlock happens if this is a RAW/WAW lock in the same thread.
396-
if (writer_tid.load(cpp::MemoryOrder::RELAXED) == gettid())
395+
if (writer_tid.load(cpp::MemoryOrder::RELAXED) == gettid_inline())
397396
return LockResult::Deadlock;
398397

399398
#if LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
@@ -519,7 +518,7 @@ class RwLock {
519518
if (old.has_active_writer()) {
520519
// The lock is held by a writer.
521520
// Check if we are the owner of the lock.
522-
if (writer_tid.load(cpp::MemoryOrder::RELAXED) != gettid())
521+
if (writer_tid.load(cpp::MemoryOrder::RELAXED) != gettid_inline())
523522
return LockResult::PermissionDenied;
524523
// clear writer tid.
525524
writer_tid.store(0, cpp::MemoryOrder::RELAXED);

libc/src/__support/threads/linux/thread.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,4 +517,6 @@ void thread_exit(ThreadReturnValue retval, ThreadStyle style) {
517517
__builtin_unreachable();
518518
}
519519

520+
pid_t Thread::get_uncached_tid() { return syscall_impl<pid_t>(SYS_gettid); }
521+
520522
} // namespace LIBC_NAMESPACE

libc/src/__support/threads/thread.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H
1010
#define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H
1111

12+
#include "hdr/types/pid_t.h"
1213
#include "src/__support/CPP/atomic.h"
1314
#include "src/__support/CPP/optional.h"
1415
#include "src/__support/CPP/string_view.h"
@@ -102,7 +103,7 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes {
102103
uintptr_t tls; // Address to the thread TLS memory
103104
uintptr_t tls_size; // The size of area pointed to by |tls|.
104105
unsigned char owned_stack; // Indicates if the thread owns this stack memory
105-
int tid;
106+
pid_t tid;
106107
ThreadStyle style;
107108
ThreadReturnValue retval;
108109
ThreadAtExitCallbackMgr *atexit_callback_mgr;
@@ -227,6 +228,16 @@ struct Thread {
227228

228229
// Return the name of the thread in |name|. Return the error number of error.
229230
int get_name(cpp::StringStream &name) const;
231+
232+
static pid_t get_uncached_tid();
233+
234+
LIBC_INLINE void refresh_tid() { this->attrib->tid = get_uncached_tid(); }
235+
LIBC_INLINE void invalidate_tid() { this->attrib->tid = -1; }
236+
LIBC_INLINE pid_t get_tid() {
237+
if (LIBC_UNLIKELY(this->attrib->tid < 0))
238+
return get_uncached_tid();
239+
return this->attrib->tid;
240+
}
230241
};
231242

232243
extern LIBC_THREAD_LOCAL Thread self;

libc/src/__support/threads/tid.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===--- Tid wrapper --------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_TID_H
10+
#define LLVM_LIBC_SRC___SUPPORT_THREADS_TID_H
11+
12+
// This header is for internal usage which automatically dispatches full build
13+
// and overlay build behaviors.
14+
15+
#include "hdr/types/pid_t.h"
16+
#include "src/__support/common.h"
17+
#ifdef LIBC_FULL_BUILD
18+
#include "src/__support/threads/thread.h"
19+
#else
20+
#include "src/__support/OSUtil/syscall.h"
21+
#include <sys/syscall.h>
22+
#endif // LIBC_FULL_BUILD
23+
24+
namespace LIBC_NAMESPACE {
25+
LIBC_INLINE pid_t gettid_inline() {
26+
#ifdef LIBC_FULL_BUILD
27+
return self.get_tid();
28+
#else
29+
return syscall_impl<pid_t>(SYS_gettid);
30+
#endif
31+
}
32+
} // namespace LIBC_NAMESPACE
33+
34+
#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_TID_H

libc/src/unistd/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,13 @@ add_entrypoint_external(
318318
add_entrypoint_external(
319319
opterr
320320
)
321+
322+
add_entrypoint_object(
323+
gettid
324+
SRCS
325+
gettid.cpp
326+
HDRS
327+
gettid.h
328+
DEPENDS
329+
libc.src.__support.threads.tid
330+
)

libc/src/unistd/getpid.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
#ifndef LLVM_LIBC_SRC_UNISTD_GETPID_H
1010
#define LLVM_LIBC_SRC_UNISTD_GETPID_H
1111

12-
#include <unistd.h>
12+
#include "hdr/types/pid_t.h"
1313

1414
namespace LIBC_NAMESPACE {
1515

16-
pid_t getpid();
16+
pid_t getpid(void);
1717

1818
} // namespace LIBC_NAMESPACE
1919

libc/src/unistd/gettid.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===-- Implementation file for gettid --------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/unistd/gettid.h"
10+
#include "src/__support/common.h"
11+
#include "src/__support/threads/tid.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(pid_t, gettid, (void)) { return gettid_inline(); }
16+
17+
} // namespace LIBC_NAMESPACE

libc/src/unistd/gettid.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for gettid ------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_UNISTD_GETTID_H
10+
#define LLVM_LIBC_SRC_UNISTD_GETTID_H
11+
12+
#include "hdr/types/pid_t.h"
13+
#include "src/__support/common.h"
14+
15+
namespace LIBC_NAMESPACE {
16+
17+
pid_t gettid(void);
18+
19+
} // namespace LIBC_NAMESPACE
20+
21+
#endif // LLVM_LIBC_SRC_UNISTD_GETTID_H

0 commit comments

Comments
 (0)