Skip to content

[libc] rework mutex #92168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions libc/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,15 @@
"value": true,
"doc": "Enable -fstack-protector-strong to defend against stack smashing attack."
}
},
"pthread": {
"LIBC_CONF_TIMEOUT_ENSURE_MONOTONICITY": {
"value": true,
"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."
},
"LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT": {
"value": 100,
"doc": "Default number of spins before blocking if a mutex is in contention (default to 100)."
}
}
}
3 changes: 3 additions & 0 deletions libc/docs/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ to learn about the defaults for your platform and target.
- ``LIBC_CONF_PRINTF_DISABLE_INDEX_MODE``: Disable index mode in the printf format string.
- ``LIBC_CONF_PRINTF_DISABLE_WRITE_INT``: Disable handling of %n in printf format string.
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE``: Use large table for better printf long double performance.
* **"pthread" options**
- ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention (default to 100).
- ``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.
* **"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.
9 changes: 9 additions & 0 deletions libc/hdr/types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,12 @@ add_proxy_header_library(
libc.include.llvm-libc-types.struct_timeval
libc.include.sys_time
)

add_proxy_header_library(
pid_t
HDRS
pid_t.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.pid_t
libc.include.sys_types
)
22 changes: 22 additions & 0 deletions libc/hdr/types/pid_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Proxy for pid_t ---------------------------------------------------===//
//
// 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_HDR_TYPES_PID_T_H
#define LLVM_LIBC_HDR_TYPES_PID_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/pid_t.h"

#else // Overlay mode

#include <sys/types.h>

#endif // LLVM_LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_TYPES_PID_T_H
6 changes: 3 additions & 3 deletions libc/include/llvm-libc-types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ add_header(__call_once_func_t HDR __call_once_func_t.h)
add_header(__exec_argv_t HDR __exec_argv_t.h)
add_header(__exec_envp_t HDR __exec_envp_t.h)
add_header(__futex_word HDR __futex_word.h)
add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word)
add_header(pid_t HDR pid_t.h)
add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word .pid_t)
add_header(__pthread_once_func_t HDR __pthread_once_func_t.h)
add_header(__pthread_start_t HDR __pthread_start_t.h)
add_header(__pthread_tss_dtor_t HDR __pthread_tss_dtor_t.h)
Expand All @@ -20,7 +21,7 @@ add_header(blksize_t HDR blksize_t.h)
add_header(cc_t HDR cc_t.h)
add_header(clock_t HDR clock_t.h)
add_header(clockid_t HDR clockid_t.h)
add_header(cnd_t HDR cnd_t.h)
add_header(cnd_t HDR cnd_t.h DEPENDS .__futex_word)
add_header(cookie_io_functions_t HDR cookie_io_functions_t.h DEPENDS .off64_t .ssize_t)
add_header(cpu_set_t HDR cpu_set_t.h)
add_header(double_t HDR double_t.h)
Expand All @@ -45,7 +46,6 @@ add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type)
add_header(nlink_t HDR nlink_t.h)
add_header(off_t HDR off_t.h)
add_header(once_flag HDR once_flag.h DEPENDS .__futex_word)
add_header(pid_t HDR pid_t.h)
add_header(posix_spawn_file_actions_t HDR posix_spawn_file_actions_t.h)
add_header(posix_spawnattr_t HDR posix_spawnattr_t.h)
add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t)
Expand Down
4 changes: 2 additions & 2 deletions libc/include/llvm-libc-types/cnd_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
#ifndef LLVM_LIBC_TYPES_CND_T_H
#define LLVM_LIBC_TYPES_CND_T_H

#include "mtx_t.h"
#include "llvm-libc-types/__futex_word.h"

typedef struct {
void *__qfront;
void *__qback;
mtx_t __qmtx;
__futex_word __qmtx;
} cnd_t;

#endif // LLVM_LIBC_TYPES_CND_T_H
16 changes: 9 additions & 7 deletions libc/src/__support/File/dir.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@ class Dir {
// A directory is to be opened by the static method open and closed
// by the close method. So, all constructors and destructor are declared
// as private. Inappropriate constructors are declared as deleted.
Dir() = delete;
Dir(const Dir &) = delete;
LIBC_INLINE Dir() = delete;
LIBC_INLINE Dir(const Dir &) = delete;

explicit Dir(int fdesc)
: fd(fdesc), readptr(0), fillsize(0), mutex(false, false, false) {}
~Dir() = default;
LIBC_INLINE explicit Dir(int fdesc)
: fd(fdesc), readptr(0), fillsize(0),
mutex(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
/*pshared=*/false) {}
LIBC_INLINE ~Dir() = default;

Dir &operator=(const Dir &) = delete;
LIBC_INLINE Dir &operator=(const Dir &) = delete;

public:
static ErrorOr<Dir *> open(const char *path);
Expand All @@ -69,7 +71,7 @@ class Dir {
// cleaned up.
int close();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all of the functions in this header should be marked LIBC_INLINE

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm: including declarations with separate definitions in another TU?


int getfd() { return fd; }
LIBC_INLINE int getfd() { return fd; }
};

} // namespace LIBC_NAMESPACE
Expand Down
9 changes: 5 additions & 4 deletions libc/src/__support/File/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,11 @@ class File {
uint8_t *buffer, size_t buffer_size, int buffer_mode,
bool owned, ModeFlags modeflags)
: platform_write(wf), platform_read(rf), platform_seek(sf),
platform_close(cf), mutex(false, false, false), ungetc_buf(0),
buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned),
mode(modeflags), pos(0), prev_op(FileOp::NONE), read_limit(0),
eof(false), err(false) {
platform_close(cf), mutex(/*timed=*/false, /*recursive=*/false,
/*robust=*/false, /*pshared=*/false),
ungetc_buf(0), buf(buffer), bufsize(buffer_size), bufmode(buffer_mode),
own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE),
read_limit(0), eof(false), err(false) {
adjust_buf();
}

Expand Down
14 changes: 8 additions & 6 deletions libc/src/__support/threads/CndVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
#define LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_CNDVAR_H

#include "src/__support/threads/linux/futex_utils.h" // Futex
#include "src/__support/threads/linux/raw_mutex.h" // RawMutex
#include "src/__support/threads/mutex.h" // Mutex

#include <stdint.h> // uint32_t

namespace LIBC_NAMESPACE {

struct CndVar {
class CndVar {
enum CndWaiterStatus : uint32_t {
WS_Waiting = 0xE,
WS_Signalled = 0x5,
Expand All @@ -29,15 +30,16 @@ struct CndVar {

CndWaiter *waitq_front;
CndWaiter *waitq_back;
Mutex qmtx;
RawMutex qmtx;

static int init(CndVar *cv) {
public:
LIBC_INLINE static int init(CndVar *cv) {
cv->waitq_front = cv->waitq_back = nullptr;
auto err = Mutex::init(&cv->qmtx, false, false, false);
return err == MutexError::NONE ? 0 : -1;
RawMutex::init(&cv->qmtx);
return 0;
}

static void destroy(CndVar *cv) {
LIBC_INLINE static void destroy(CndVar *cv) {
cv->waitq_front = cv->waitq_back = nullptr;
}

Expand Down
5 changes: 4 additions & 1 deletion libc/src/__support/threads/fork_callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ class AtForkCallbackManager {
size_t next_index;

public:
constexpr AtForkCallbackManager() : mtx(false, false, false), next_index(0) {}
constexpr AtForkCallbackManager()
: mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
/*pshared=*/false),
next_index(0) {}

bool register_triple(const ForkCallbackTriple &triple) {
cpp::lock_guard lock(mtx);
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/threads/gpu/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace LIBC_NAMESPACE {
/// define the Mutex interface and require that only a single thread executes
/// code requiring a mutex lock.
struct Mutex {
LIBC_INLINE constexpr Mutex(bool, bool, bool) {}
LIBC_INLINE constexpr Mutex(bool, bool, bool, bool) {}

LIBC_INLINE MutexError lock() { return MutexError::NONE; }
LIBC_INLINE MutexError unlock() { return MutexError::NONE; }
Expand Down
26 changes: 26 additions & 0 deletions libc/src/__support/threads/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,37 @@ add_header_library(
libc.src.__support.time.linux.abs_timeout
)

set(raw_mutex_additional_flags)
if (LIBC_CONF_TIMEOUT_ENSURE_MONOTONICITY)
set(raw_mutex_additional_flags -DLIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY=1)
else()
set(raw_mutex_additional_flags -DLIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY=0)
endif()

add_header_library(
raw_mutex
HDRS
mutex.h
DEPENDS
.futex_utils
libc.src.__support.threads.sleep
libc.src.__support.time.linux.abs_timeout
libc.src.__support.time.linux.monotonicity
libc.src.__support.CPP.optional
libc.hdr.types.pid_t
COMPILE_OPTIONS
-DLIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT=${LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT}
${raw_mutex_additional_flags}

)

add_header_library(
mutex
HDRS
mutex.h
DEPENDS
.futex_utils
.raw_mutex
libc.src.__support.threads.mutex_common
)

Expand Down Expand Up @@ -75,5 +100,6 @@ add_object_library(
libc.src.__support.OSUtil.osutil
libc.src.__support.threads.linux.futex_word_type
libc.src.__support.threads.mutex
libc.src.__support.threads.linux.raw_mutex
libc.src.__support.CPP.mutex
)
5 changes: 3 additions & 2 deletions libc/src/__support/threads/linux/CndVar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "src/__support/CPP/mutex.h"
#include "src/__support/OSUtil/syscall.h" // syscall_impl
#include "src/__support/threads/linux/futex_word.h" // FutexWordType
#include "src/__support/threads/linux/raw_mutex.h" // RawMutex
#include "src/__support/threads/mutex.h" // Mutex

#include <sys/syscall.h> // For syscall numbers.
Expand Down Expand Up @@ -74,11 +75,11 @@ void CndVar::notify_one() {
if (waitq_front == nullptr)
waitq_back = nullptr;

qmtx.futex_word = FutexWordType(Mutex::LockState::Free);
qmtx.reset();

// this is a special WAKE_OP, so we use syscall directly
LIBC_NAMESPACE::syscall_impl<long>(
FUTEX_SYSCALL_ID, &qmtx.futex_word.val, FUTEX_WAKE_OP, 1, 1,
FUTEX_SYSCALL_ID, &qmtx.get_raw_futex(), FUTEX_WAKE_OP, 1, 1,
&first->futex_word.val,
FUTEX_OP(FUTEX_OP_SET, WS_Signalled, FUTEX_OP_CMP_EQ, WS_Waiting));
}
Expand Down
Loading
Loading