Skip to content

[scudo] Add ConditionVariable in SizeClassAllocator64 #69031

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 3 commits into from
Oct 19, 2023
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
4 changes: 4 additions & 0 deletions compiler-rt/lib/scudo/standalone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ set(SCUDO_HEADERS
bytemap.h
checksum.h
chunk.h
condition_variable.h
condition_variable_base.h
condition_variable_linux.h
combined.h
common.h
flags_parser.h
Expand Down Expand Up @@ -104,6 +107,7 @@ set(SCUDO_HEADERS
set(SCUDO_SOURCES
checksum.cpp
common.cpp
condition_variable_linux.cpp
crc32_hw.cpp
flags_parser.cpp
flags.cpp
Expand Down
9 changes: 9 additions & 0 deletions compiler-rt/lib/scudo/standalone/allocator_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "combined.h"
#include "common.h"
#include "condition_variable.h"
#include "flags.h"
#include "primary32.h"
#include "primary64.h"
Expand Down Expand Up @@ -82,6 +83,14 @@ namespace scudo {
// // Defines the minimal & maximal release interval that can be set.
// static const s32 MinReleaseToOsIntervalMs = INT32_MIN;
// static const s32 MaxReleaseToOsIntervalMs = INT32_MAX;
//
// // Use condition variable to shorten the waiting time of refillment of
// // freelist. Note that this depends on the implementation of condition
// // variable on each platform and the performance may vary so that it
// // doesn't guarantee a performance benefit.
// // Note that both variables have to be defined to enable it.
// static const bool UseConditionVariable = true;
// using ConditionVariableT = ConditionVariableLinux;
// };
// // Defines the type of Primary allocator to use.
// template <typename Config> using PrimaryT = SizeClassAllocator64<Config>;
Expand Down
60 changes: 60 additions & 0 deletions compiler-rt/lib/scudo/standalone/condition_variable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===-- condition_variable.h ------------------------------------*- 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 SCUDO_CONDITION_VARIABLE_H_
#define SCUDO_CONDITION_VARIABLE_H_

#include "condition_variable_base.h"

#include "common.h"
#include "platform.h"

#include "condition_variable_linux.h"

namespace scudo {

// A default implementation of default condition variable. It doesn't do a real
// `wait`, instead it spins a short amount of time only.
class ConditionVariableDummy
: public ConditionVariableBase<ConditionVariableDummy> {
public:
void notifyAllImpl(UNUSED HybridMutex &M) REQUIRES(M) {}

void waitImpl(UNUSED HybridMutex &M) REQUIRES(M) {
M.unlock();

constexpr u32 SpinTimes = 64;
volatile u32 V = 0;
for (u32 I = 0; I < SpinTimes; ++I) {
u32 Tmp = V + 1;
V = Tmp;
}

M.lock();
}
};

template <typename Config, typename = const bool>
struct ConditionVariableState {
static constexpr bool enabled() { return false; }
// This is only used for compilation purpose so that we won't end up having
// many conditional compilations. If you want to use `ConditionVariableDummy`,
// define `ConditionVariableT` in your allocator configuration. See
// allocator_config.h for more details.
using ConditionVariableT = ConditionVariableDummy;
};

template <typename Config>
struct ConditionVariableState<Config, decltype(Config::UseConditionVariable)> {
static constexpr bool enabled() { return true; }
using ConditionVariableT = typename Config::ConditionVariableT;
};

} // namespace scudo

#endif // SCUDO_CONDITION_VARIABLE_H_
56 changes: 56 additions & 0 deletions compiler-rt/lib/scudo/standalone/condition_variable_base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===-- condition_variable_base.h -------------------------------*- 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 SCUDO_CONDITION_VARIABLE_BASE_H_
#define SCUDO_CONDITION_VARIABLE_BASE_H_

#include "mutex.h"
#include "thread_annotations.h"

namespace scudo {

template <typename Derived> class ConditionVariableBase {
public:
constexpr ConditionVariableBase() = default;

void bindTestOnly(HybridMutex &Mutex) {
#if SCUDO_DEBUG
boundMutex = &Mutex;
#else
(void)Mutex;
#endif
}

void notifyAll(HybridMutex &M) REQUIRES(M) {
#if SCUDO_DEBUG
CHECK_EQ(&M, boundMutex);
#endif
getDerived()->notifyAllImpl(M);
}

void wait(HybridMutex &M) REQUIRES(M) {
#if SCUDO_DEBUG
CHECK_EQ(&M, boundMutex);
#endif
getDerived()->waitImpl(M);
}

protected:
Derived *getDerived() { return static_cast<Derived *>(this); }

#if SCUDO_DEBUG
// Because thread-safety analysis doesn't support pointer aliasing, we are not
// able to mark the proper annotations without false positive. Instead, we
// pass the lock and do the same-lock check separately.
HybridMutex *boundMutex = nullptr;
#endif
};

} // namespace scudo

#endif // SCUDO_CONDITION_VARIABLE_BASE_H_
52 changes: 52 additions & 0 deletions compiler-rt/lib/scudo/standalone/condition_variable_linux.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===-- condition_variable_linux.cpp ----------------------------*- 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 "platform.h"

#if SCUDO_LINUX

#include "condition_variable_linux.h"

#include "atomic_helpers.h"

#include <limits.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>

namespace scudo {

void ConditionVariableLinux::notifyAllImpl(UNUSED HybridMutex &M) {
const u32 V = atomic_load_relaxed(&Counter);
atomic_store_relaxed(&Counter, V + 1);

// TODO(chiahungduan): Move the waiters from the futex waiting queue
// `Counter` to futex waiting queue `M` so that the awoken threads won't be
// blocked again due to locked `M` by current thread.
if (LastNotifyAll != V) {
syscall(SYS_futex, reinterpret_cast<uptr>(&Counter), FUTEX_WAKE_PRIVATE,
INT_MAX, nullptr, nullptr, 0);
}

LastNotifyAll = V + 1;
}

void ConditionVariableLinux::waitImpl(HybridMutex &M) {
const u32 V = atomic_load_relaxed(&Counter) + 1;
atomic_store_relaxed(&Counter, V);

// TODO: Use ScopedUnlock when it's supported.
M.unlock();
syscall(SYS_futex, reinterpret_cast<uptr>(&Counter), FUTEX_WAIT_PRIVATE, V,
nullptr, nullptr, 0);
M.lock();
}

} // namespace scudo

#endif // SCUDO_LINUX
38 changes: 38 additions & 0 deletions compiler-rt/lib/scudo/standalone/condition_variable_linux.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===-- condition_variable_linux.h ------------------------------*- 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 SCUDO_CONDITION_VARIABLE_LINUX_H_
#define SCUDO_CONDITION_VARIABLE_LINUX_H_

#include "platform.h"

#if SCUDO_LINUX

#include "atomic_helpers.h"
#include "condition_variable_base.h"
#include "thread_annotations.h"

namespace scudo {

class ConditionVariableLinux
: public ConditionVariableBase<ConditionVariableLinux> {
public:
void notifyAllImpl(HybridMutex &M) REQUIRES(M);

void waitImpl(HybridMutex &M) REQUIRES(M);

private:
u32 LastNotifyAll = 0;
atomic_u32 Counter = {};
};

} // namespace scudo

#endif // SCUDO_LINUX

#endif // SCUDO_CONDITION_VARIABLE_LINUX_H_
Loading