
This CL adds the proper thread-safety annotations for most of the functions and variables. However, given the restriction of the current architecture, in some cases, we may not be able to use the annotations easily. The followings are two exceptions, 1. enable()/disable(): Many structures in scudo are enabled/disabled by acquiring the lock in each instance. This makes those structure act like a `lock`. We can't mark those functions with ACQUIRE()/RELEASE() because that makes the entire allocator become another `lock`. In the end, that implies we need to *acquire* the `allocator` before each malloc et al. request. Therefore, adding a variable to tell the status of those structures may be a better way to cooperate with thread-safety annotation. 2. TSD/TSD shared/TSD exclusive: These three have simiar restrictions as mentioned above. In addition, they don't always need to be released if it's a thread local instance. However, thread-safety analysis doesn't support conditional branch. Which means we can't mark the proper annotations around the uses of TSDs. We may consider to make it consistent and which makes the code structure simpler. This CL is supposed to introduce the annotations with the least code refactoring. So only trivial thread safety issues will be addressed here. For example, lacking of acquiring certain lock before accessing certain variables will have the ScopedLock inserted. Other than that, they are supposed to be done in the later changes. Reviewed By: cferris Differential Revision: https://reviews.llvm.org/D140706
103 lines
2.9 KiB
C++
103 lines
2.9 KiB
C++
//===-- stats.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_STATS_H_
|
|
#define SCUDO_STATS_H_
|
|
|
|
#include "atomic_helpers.h"
|
|
#include "list.h"
|
|
#include "mutex.h"
|
|
#include "thread_annotations.h"
|
|
|
|
#include <string.h>
|
|
|
|
namespace scudo {
|
|
|
|
// Memory allocator statistics
|
|
enum StatType { StatAllocated, StatFree, StatMapped, StatCount };
|
|
|
|
typedef uptr StatCounters[StatCount];
|
|
|
|
// Per-thread stats, live in per-thread cache. We use atomics so that the
|
|
// numbers themselves are consistent. But we don't use atomic_{add|sub} or a
|
|
// lock, because those are expensive operations , and we only care for the stats
|
|
// to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is
|
|
// LocalStats::add'ing, this is OK, we will still get a meaningful number.
|
|
class LocalStats {
|
|
public:
|
|
void init() {
|
|
for (uptr I = 0; I < StatCount; I++)
|
|
DCHECK_EQ(get(static_cast<StatType>(I)), 0U);
|
|
}
|
|
|
|
void add(StatType I, uptr V) {
|
|
V += atomic_load_relaxed(&StatsArray[I]);
|
|
atomic_store_relaxed(&StatsArray[I], V);
|
|
}
|
|
|
|
void sub(StatType I, uptr V) {
|
|
V = atomic_load_relaxed(&StatsArray[I]) - V;
|
|
atomic_store_relaxed(&StatsArray[I], V);
|
|
}
|
|
|
|
void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
|
|
|
|
uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
|
|
|
|
LocalStats *Next = nullptr;
|
|
LocalStats *Prev = nullptr;
|
|
|
|
private:
|
|
atomic_uptr StatsArray[StatCount] = {};
|
|
};
|
|
|
|
// Global stats, used for aggregation and querying.
|
|
class GlobalStats : public LocalStats {
|
|
public:
|
|
void init() { LocalStats::init(); }
|
|
|
|
void link(LocalStats *S) EXCLUDES(Mutex) {
|
|
ScopedLock L(Mutex);
|
|
StatsList.push_back(S);
|
|
}
|
|
|
|
void unlink(LocalStats *S) EXCLUDES(Mutex) {
|
|
ScopedLock L(Mutex);
|
|
StatsList.remove(S);
|
|
for (uptr I = 0; I < StatCount; I++)
|
|
add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
|
|
}
|
|
|
|
void get(uptr *S) const EXCLUDES(Mutex) {
|
|
ScopedLock L(Mutex);
|
|
for (uptr I = 0; I < StatCount; I++)
|
|
S[I] = LocalStats::get(static_cast<StatType>(I));
|
|
for (const auto &Stats : StatsList) {
|
|
for (uptr I = 0; I < StatCount; I++)
|
|
S[I] += Stats.get(static_cast<StatType>(I));
|
|
}
|
|
// All stats must be non-negative.
|
|
for (uptr I = 0; I < StatCount; I++)
|
|
S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
|
|
}
|
|
|
|
void lock() ACQUIRE(Mutex) { Mutex.lock(); }
|
|
void unlock() RELEASE(Mutex) { Mutex.unlock(); }
|
|
|
|
void disable() ACQUIRE(Mutex) { lock(); }
|
|
void enable() RELEASE(Mutex) { unlock(); }
|
|
|
|
private:
|
|
mutable HybridMutex Mutex;
|
|
DoublyLinkedList<LocalStats> StatsList GUARDED_BY(Mutex);
|
|
};
|
|
|
|
} // namespace scudo
|
|
|
|
#endif // SCUDO_STATS_H_
|