blob: 204438ae0705a082a5da40f9220d093fac7d1a1e [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_INCLUDE_KERNEL_SPIN_TRACING_STORAGE_H_
#define ZIRCON_KERNEL_INCLUDE_KERNEL_SPIN_TRACING_STORAGE_H_
#include <lib/fxt/interned_string.h>
#include <kernel/lockdep.h>
#include <kernel/spin_tracing_config.h>
#include <ktl/atomic.h>
namespace spin_tracing {
class LockIdGenerator {
protected:
LockIdGenerator() = default;
~LockIdGenerator() = default;
static uint64_t CreateId() { return generator_.fetch_add(1, ktl::memory_order_relaxed); }
private:
static inline ktl::atomic<uint64_t> generator_{1};
};
template <LockType kLockType, bool Enabled = false>
class LockNameStorage {
public:
constexpr void SetLockClassId(lockdep::LockClassId lcid) {}
protected:
constexpr LockNameStorage() = default;
explicit constexpr LockNameStorage(uint16_t) {}
constexpr EncodedLockId encoded_lock_id() const { return EncodedLockId::Invalid(); }
};
template <LockType kLockType>
class LockNameStorage<kLockType, true> : public LockIdGenerator {
public:
void SetLockClassId(lockdep::LockClassId lcid) {
if ((lcid != lockdep::kInvalidLockClassId) &&
(encoded_lock_id_.class_name() == fxt::InternedString::kInvalidId)) {
lockdep::MetadataLockClassState* state = lockdep::MetadataLockClassState::Get(lcid);
const fxt::InternedString* name = &state->interned_name();
// Note: in a perfect world it should be absolutely impossible for the
// reference returned by `interned_name()` to be invalid. Unfortunately,
// because of _technically_ possible global ctor races, it is possible to
// be accessing a LockStateClass which has not fully been constructed yet,
// meaning that its reference to its name might be null (something which
// _should_ be impossible). Until we get to C++20 and can use
// consteval/constinit, there is always a small chance that this could
// happen in an instrumented build.
//
// If/when it does happen, it can be a pretty unpleasant experience as the
// kernel will panic before there is even serial enabled, making things
// extremely difficult to debug. Adding this check (and hoping that the
// compiler does not elide it) makes for a better experience in the worst
// case scenario. It is possible for a lock to go unnamed, but at least
// we won't crash during early boot.
if (name != nullptr) {
encoded_lock_id_.SetLockClassId(name->GetId());
}
}
}
protected:
constexpr LockNameStorage()
: encoded_lock_id_{kLockType, CreateId(), fxt::InternedString::kInvalidId} {}
explicit LockNameStorage(uint16_t class_name_id)
: encoded_lock_id_{kLockType, CreateId(), class_name_id} {}
EncodedLockId encoded_lock_id() const { return encoded_lock_id_; }
private:
EncodedLockId encoded_lock_id_;
};
} // namespace spin_tracing
#endif // ZIRCON_KERNEL_INCLUDE_KERNEL_SPIN_TRACING_STORAGE_H_