Skip to content

Commit eab3caa

Browse files
author
Yifan Zhu
committed
address code reviews
1 parent 0580610 commit eab3caa

File tree

15 files changed

+95
-63
lines changed

15 files changed

+95
-63
lines changed

libc/config/config.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@
4444
"pthread": {
4545
"LIBC_CONF_TIMEOUT_ENSURE_MONOTONICITY": {
4646
"value": true,
47-
"doc": "Automatically adjust timeout to CLOCK_MONOTONIC."
47+
"doc": "Automatically adjust timeout to CLOCK_MONOTONIC (default to true). POSIX API may require CLOCK_REALTIME, which can be unstable and leading to unexpected behavior. This option will convert the real-time timestamp to monotonic timestamp relative to the time of call."
4848
},
4949
"LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT": {
5050
"value": 100,
51-
"doc": "Default number of spins before blocking if a mutex is in contention."
51+
"doc": "Default number of spins before blocking if a mutex is in contention (default to 100)."
5252
}
5353
}
54-
}
54+
}

libc/docs/configure.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ to learn about the defaults for your platform and target.
3535
- ``LIBC_CONF_PRINTF_DISABLE_WRITE_INT``: Disable handling of %n in printf format string.
3636
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE``: Use large table for better printf long double performance.
3737
* **"pthread" options**
38-
- ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention.
39-
- ``LIBC_CONF_TIMEOUT_ENSURE_MONOTONICITY``: Automatically adjust timeout to CLOCK_MONOTONIC.
38+
- ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention (default to 100).
39+
- ``LIBC_CONF_TIMEOUT_ENSURE_MONOTONICITY``: Automatically adjust timeout to CLOCK_MONOTONIC (default to true). POSIX API may require CLOCK_REALTIME, which can be unstable and leading to unexpected behavior. This option will convert the real-time timestamp to monotonic timestamp relative to the time of call.
4040
* **"string" options**
4141
- ``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.
4242
- ``LIBC_CONF_STRING_UNSAFE_WIDE_READ``: Read more than a byte at a time to perform byte-string operations like strlen.

libc/src/__support/File/dir.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,16 @@ class Dir {
5050
// A directory is to be opened by the static method open and closed
5151
// by the close method. So, all constructors and destructor are declared
5252
// as private. Inappropriate constructors are declared as deleted.
53-
Dir() = delete;
54-
Dir(const Dir &) = delete;
53+
LIBC_INLINE Dir() = delete;
54+
LIBC_INLINE Dir(const Dir &) = delete;
5555

56-
explicit Dir(int fdesc)
57-
: fd(fdesc), readptr(0), fillsize(0), mutex(false, false, false, false) {}
58-
~Dir() = default;
56+
LIBC_INLINE explicit Dir(int fdesc)
57+
: fd(fdesc), readptr(0), fillsize(0),
58+
mutex(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
59+
/*pshared=*/false) {}
60+
LIBC_INLINE ~Dir() = default;
5961

60-
Dir &operator=(const Dir &) = delete;
62+
LIBC_INLINE Dir &operator=(const Dir &) = delete;
6163

6264
public:
6365
static ErrorOr<Dir *> open(const char *path);
@@ -69,7 +71,7 @@ class Dir {
6971
// cleaned up.
7072
int close();
7173

72-
int getfd() { return fd; }
74+
LIBC_INLINE int getfd() { return fd; }
7375
};
7476

7577
} // namespace LIBC_NAMESPACE

libc/src/__support/File/file.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,11 @@ class File {
154154
uint8_t *buffer, size_t buffer_size, int buffer_mode,
155155
bool owned, ModeFlags modeflags)
156156
: platform_write(wf), platform_read(rf), platform_seek(sf),
157-
platform_close(cf), mutex(false, false, false, false), ungetc_buf(0),
158-
buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned),
159-
mode(modeflags), pos(0), prev_op(FileOp::NONE), read_limit(0),
160-
eof(false), err(false) {
157+
platform_close(cf), mutex(/*timed=*/false, /*recursive=*/false,
158+
/*robust=*/false, /*pshared=*/false),
159+
ungetc_buf(0), buf(buffer), bufsize(buffer_size), bufmode(buffer_mode),
160+
own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE),
161+
read_limit(0), eof(false), err(false) {
161162
adjust_buf();
162163
}
163164

libc/src/__support/threads/CndVar.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
namespace LIBC_NAMESPACE {
1919

20-
struct CndVar {
20+
class CndVar {
2121
enum CndWaiterStatus : uint32_t {
2222
WS_Waiting = 0xE,
2323
WS_Signalled = 0x5,
@@ -30,15 +30,16 @@ struct CndVar {
3030

3131
CndWaiter *waitq_front;
3232
CndWaiter *waitq_back;
33-
internal::RawMutex qmtx;
33+
RawMutex qmtx;
3434

35-
static int init(CndVar *cv) {
35+
public:
36+
LIBC_INLINE static int init(CndVar *cv) {
3637
cv->waitq_front = cv->waitq_back = nullptr;
37-
internal::RawMutex::init(&cv->qmtx);
38+
RawMutex::init(&cv->qmtx);
3839
return 0;
3940
}
4041

41-
static void destroy(CndVar *cv) {
42+
LIBC_INLINE static void destroy(CndVar *cv) {
4243
cv->waitq_front = cv->waitq_back = nullptr;
4344
}
4445

libc/src/__support/threads/fork_callbacks.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ class AtForkCallbackManager {
3434

3535
public:
3636
constexpr AtForkCallbackManager()
37-
: mtx(false, false, false, false), next_index(0) {}
37+
: mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
38+
/*pshared=*/false),
39+
next_index(0) {}
3840

3941
bool register_triple(const ForkCallbackTriple &triple) {
4042
cpp::lock_guard lock(mtx);

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ add_header_library(
2424

2525
set(raw_mutex_additional_flags)
2626
if (LIBC_CONF_TIMEOUT_ENSURE_MONOTONICITY)
27-
set(raw_mutex_additional_flags -DLIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY)
27+
set(raw_mutex_additional_flags -DLIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY=1)
28+
else()
29+
set(raw_mutex_additional_flags -DLIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY=0)
2830
endif()
2931

3032
add_header_library(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void CndVar::notify_one() {
7575
if (waitq_front == nullptr)
7676
waitq_back = nullptr;
7777

78-
qmtx.futex = internal::RawMutex::UNLOCKED;
78+
qmtx.futex = RawMutex::UNLOCKED;
7979

8080
// this is a special WAKE_OP, so we use syscall directly
8181
LIBC_NAMESPACE::syscall_impl<long>(

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111

1212
#include "hdr/types/pid_t.h"
1313
#include "src/__support/CPP/optional.h"
14+
#include "src/__support/libc_assert.h"
1415
#include "src/__support/threads/linux/futex_utils.h"
1516
#include "src/__support/threads/linux/raw_mutex.h"
1617
#include "src/__support/threads/mutex_common.h"
1718

1819
namespace LIBC_NAMESPACE {
1920

2021
// TODO: support shared/recursive/robust mutexes.
21-
class Mutex final : private internal::RawMutex {
22+
class Mutex final : private RawMutex {
2223
// reserved timed, may be useful when combined with other flags.
2324
unsigned char timed;
2425
unsigned char recursive;
@@ -32,12 +33,12 @@ class Mutex final : private internal::RawMutex {
3233
public:
3334
LIBC_INLINE constexpr Mutex(bool is_timed, bool is_recursive, bool is_robust,
3435
bool is_pshared)
35-
: internal::RawMutex(), timed(is_timed), recursive(is_recursive),
36-
robust(is_robust), pshared(is_pshared), owner(0), lock_count(0) {}
36+
: RawMutex(), timed(is_timed), recursive(is_recursive), robust(is_robust),
37+
pshared(is_pshared), owner(0), lock_count(0) {}
3738

3839
LIBC_INLINE static MutexError init(Mutex *mutex, bool is_timed, bool isrecur,
3940
bool isrobust, bool is_pshared) {
40-
internal::RawMutex::init(mutex);
41+
RawMutex::init(mutex);
4142
mutex->timed = is_timed;
4243
mutex->recursive = isrecur;
4344
mutex->robust = isrobust;
@@ -47,31 +48,37 @@ class Mutex final : private internal::RawMutex {
4748
return MutexError::NONE;
4849
}
4950

50-
LIBC_INLINE static MutexError destroy(Mutex *) { return MutexError::NONE; }
51+
LIBC_INLINE static MutexError destroy(Mutex *lock) {
52+
LIBC_ASSERT(lock->owner == 0 && lock->lock_count == 0 &&
53+
"Mutex destroyed while being locked.");
54+
RawMutex::destroy(lock);
55+
return MutexError::NONE;
56+
}
5157

5258
// TODO: record owner and lock count.
5359
LIBC_INLINE MutexError lock() {
54-
this->internal::RawMutex::lock(
55-
/* timeout */ cpp::nullopt, this->pshared);
60+
// Since timeout is not specified, we do not need to check the return value.
61+
this->RawMutex::lock(
62+
/* timeout=*/cpp::nullopt, this->pshared);
5663
return MutexError::NONE;
5764
}
5865

5966
// TODO: record owner and lock count.
6067
LIBC_INLINE MutexError timed_lock(internal::AbsTimeout abs_time) {
61-
if (this->internal::RawMutex::lock(abs_time, this->pshared))
68+
if (this->RawMutex::lock(abs_time, this->pshared))
6269
return MutexError::NONE;
6370
return MutexError::TIMEOUT;
6471
}
6572

6673
LIBC_INLINE MutexError unlock() {
67-
if (this->internal::RawMutex::unlock(this->pshared))
74+
if (this->RawMutex::unlock(this->pshared))
6875
return MutexError::NONE;
6976
return MutexError::UNLOCK_WITHOUT_LOCK;
7077
}
7178

7279
// TODO: record owner and lock count.
7380
LIBC_INLINE MutexError try_lock() {
74-
if (this->internal::RawMutex::try_lock())
81+
if (this->RawMutex::try_lock())
7582
return MutexError::NONE;
7683
return MutexError::BUSY;
7784
}

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

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,31 @@
88
#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RAW_MUTEX_H
99
#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RAW_MUTEX_H
1010

11-
#include "futex_word.h"
1211
#include "src/__support/CPP/optional.h"
1312
#include "src/__support/common.h"
13+
#include "src/__support/libc_assert.h"
1414
#include "src/__support/macros/attributes.h"
1515
#include "src/__support/threads/linux/futex_utils.h"
16+
#include "src/__support/threads/linux/futex_word.h"
1617
#include "src/__support/threads/sleep.h"
1718
#include "src/__support/time/linux/abs_timeout.h"
18-
#ifdef LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
19+
20+
#ifndef LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
21+
#define LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY 1
22+
#warning "LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY is not defined, defaulting to 1"
23+
#endif
24+
25+
#if LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
1926
#include "src/__support/time/linux/monotonicity.h"
2027
#endif
2128

2229
#ifndef LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT
2330
#define LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT 100
31+
#warning \
32+
"LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT is not defined, defaulting to 100"
2433
#endif
2534

2635
namespace LIBC_NAMESPACE {
27-
struct CndVar;
28-
namespace internal {
2936
// Lock is a simple timable lock for internal usage.
3037
// This is separated from Mutex because this one does not need to consider
3138
// robustness and reentrancy. Also, this one has spin optimization for shorter
@@ -37,7 +44,8 @@ class RawMutex {
3744
LIBC_INLINE_VAR static constexpr FutexWordType LOCKED = 0b01;
3845
LIBC_INLINE_VAR static constexpr FutexWordType IN_CONTENTION = 0b10;
3946

40-
LIBC_INLINE FutexWordType spin(uint_fast32_t spin_count) {
47+
private:
48+
LIBC_INLINE FutexWordType spin(int spin_count) {
4149
FutexWordType result;
4250
for (;;) {
4351
result = futex.load(cpp::MemoryOrder::RELAXED);
@@ -56,16 +64,16 @@ class RawMutex {
5664

5765
// Return true if the lock is acquired. Return false if timeout happens before
5866
// the lock is acquired.
59-
[[gnu::cold]] LIBC_INLINE bool
60-
lock_slow(cpp::optional<Futex::Timeout> timeout, bool is_pshared,
61-
uint_fast32_t spin_count) {
67+
LIBC_INLINE bool lock_slow(cpp::optional<Futex::Timeout> timeout,
68+
bool is_pshared, int spin_count) {
6269
FutexWordType state = spin(spin_count);
6370
// Before go into contention state, try to grab the lock.
6471
if (state == UNLOCKED &&
6572
futex.compare_exchange_strong(state, LOCKED, cpp::MemoryOrder::ACQUIRE,
6673
cpp::MemoryOrder::RELAXED))
6774
return true;
68-
#ifdef LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
75+
#if LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
76+
/* ADL should kick in */
6977
if (timeout)
7078
ensure_monotonicity(*timeout);
7179
#endif
@@ -83,14 +91,12 @@ class RawMutex {
8391
}
8492
}
8593

86-
[[gnu::cold]] LIBC_INLINE void wake(bool is_pshared) {
87-
futex.notify_one(is_pshared);
88-
}
94+
LIBC_INLINE void wake(bool is_pshared) { futex.notify_one(is_pshared); }
8995

9096
public:
9197
LIBC_INLINE static void init(RawMutex *mutex) { mutex->futex = UNLOCKED; }
9298
LIBC_INLINE constexpr RawMutex() : futex(UNLOCKED) {}
93-
LIBC_INLINE bool try_lock() {
99+
[[nodiscard]] LIBC_INLINE bool try_lock() {
94100
FutexWordType expected = UNLOCKED;
95101
// Use strong version since this is a one-time operation.
96102
return futex.compare_exchange_strong(
@@ -99,23 +105,25 @@ class RawMutex {
99105
LIBC_INLINE bool
100106
lock(cpp::optional<Futex::Timeout> timeout = cpp::nullopt,
101107
bool is_shared = false,
102-
uint_fast32_t spin_count = LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT) {
108+
int spin_count = LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT) {
103109
// Timeout will not be checked if immediate lock is possible.
104-
if (try_lock())
110+
if (LIBC_LIKELY(try_lock()))
105111
return true;
106112
return lock_slow(timeout, is_shared, spin_count);
107113
}
108114
LIBC_INLINE bool unlock(bool is_pshared = false) {
109115
FutexWordType prev = futex.exchange(UNLOCKED, cpp::MemoryOrder::RELEASE);
110116
// if there is someone waiting, wake them up
111-
if (prev == IN_CONTENTION)
117+
if (LIBC_UNLIKELY(prev == IN_CONTENTION))
112118
wake(is_pshared);
113119
// Detect invalid unlock operation.
114120
return prev != UNLOCKED;
115121
}
116-
friend struct ::LIBC_NAMESPACE::CndVar;
122+
LIBC_INLINE void static destroy([[maybe_unused]] RawMutex *lock) {
123+
LIBC_ASSERT(lock->futex == UNLOCKED && "Mutex destroyed while used.");
124+
}
125+
friend class CndVar;
117126
};
118-
} // namespace internal
119127
} // namespace LIBC_NAMESPACE
120128

121129
#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RAW_MUTEX_H

libc/src/__support/threads/thread.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ class TSSKeyMgr {
5454
cpp::array<TSSKeyUnit, TSS_KEY_COUNT> units;
5555

5656
public:
57-
constexpr TSSKeyMgr() : mtx(false, false, false, false) {}
57+
constexpr TSSKeyMgr()
58+
: mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
59+
/*pshared=*/false) {}
5860

5961
cpp::optional<unsigned int> new_key(TSSDtor *dtor) {
6062
cpp::lock_guard lock(mtx);
@@ -111,7 +113,9 @@ class ThreadAtExitCallbackMgr {
111113
FixedVector<AtExitUnit, 1024> callback_list;
112114

113115
public:
114-
constexpr ThreadAtExitCallbackMgr() : mtx(false, false, false, false) {}
116+
constexpr ThreadAtExitCallbackMgr()
117+
: mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
118+
/*pshared=*/false) {}
115119

116120
int add_callback(AtExitCallback *callback, void *obj) {
117121
cpp::lock_guard lock(mtx);

libc/src/pthread/pthread_mutex_init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ LLVM_LIBC_FUNCTION(int, pthread_mutex_init,
2626
const pthread_mutexattr_t *__restrict attr)) {
2727
auto mutexattr = attr == nullptr ? DEFAULT_MUTEXATTR : *attr;
2828
auto err =
29-
Mutex::init(reinterpret_cast<Mutex *>(m), /* timeout is supported */ true,
29+
Mutex::init(reinterpret_cast<Mutex *>(m), /*is_timed=*/true,
3030
get_mutexattr_type(mutexattr) & PTHREAD_MUTEX_RECURSIVE,
3131
get_mutexattr_robust(mutexattr) & PTHREAD_MUTEX_ROBUST,
3232
get_mutexattr_pshared(mutexattr) & PTHREAD_PROCESS_SHARED);

libc/src/stdlib/atexit.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ namespace LIBC_NAMESPACE {
1717

1818
namespace {
1919

20-
Mutex handler_list_mtx(false, false, false, false);
20+
Mutex handler_list_mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
21+
/*pshared=*/false);
2122

2223
using AtExitCallback = void(void *);
2324
using StdCAtExitCallback = void(void);

libc/test/integration/src/__support/threads/thread_detach_test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
#include "src/__support/threads/thread.h"
1111
#include "test/IntegrationTest/test.h"
1212

13-
LIBC_NAMESPACE::Mutex mutex(false, false, false, false);
13+
LIBC_NAMESPACE::Mutex mutex(/*timed=*/false, /*recursive=*/false,
14+
/*robust=*/false, /*pshared=*/false);
1415

1516
int func(void *) {
1617
mutex.lock();

0 commit comments

Comments
 (0)