blob: 07fc216d1d1095d1695c38bc47651f624dc8ff7d [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Common definitions for the lockdep library.
//
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <type_traits>
#include <lockdep/runtime_api.h>
namespace lockdep {
// Configures the maximum number of dependencies each lock class may have. A
// system may override the default by globally defining this name to the desired
// value. This value is automatically converted to the next suitable prime.
#ifndef LOCK_DEP_MAX_DEPENDENCIES
#define LOCK_DEP_MAX_DEPENDENCIES 31
#endif
// Configures whether lock validation is enabled or not. Defaults to disabled.
// When disabled the locking utilities simply lock the underlying lock types,
// without performing any validation operations.
#ifndef LOCK_DEP_ENABLE_VALIDATION
#define LOCK_DEP_ENABLE_VALIDATION 0
#endif
// Id type used to identify each lock class.
using LockClassId = uintptr_t;
// A sentinel value indicating an empty slot in lock tracking data structures.
constexpr LockClassId kInvalidLockClassId = 0;
namespace internal {
// Returns a prime number that reasonably accommodates a hash table of the given
// number of entries. Each number is selected to be slightly less than twice the
// previous and as far as possible from the nearest two powers of two.
constexpr size_t NextPrime(size_t n) {
if (n < (1 << 4))
return 23;
else if (n < (1 << 5))
return 53;
else if (n < (1 << 6))
return 97;
else if (n < (1 << 7))
return 193;
else if (n < (1 << 8))
return 389;
else if (n < (1 << 9))
return 769;
else if (n < (1 << 10))
return 1543;
else
return 0; // The input exceeds the size of this prime table.
}
} // namespace internal
// The maximum number of dependencies each lock class may have. This is the
// maximum branching factor of the directed graph of locks managed by this
// lock dependency algorithm. The value is a prime number selected to optimize
// the hash map in LockDependencySet.
constexpr size_t kMaxLockDependencies = internal::NextPrime(LOCK_DEP_MAX_DEPENDENCIES);
// Check to make sure that the requested max does not exceed the prime table.
static_assert(kMaxLockDependencies != 0, "LOCK_DEP_MAX_DEPENDENCIES too large!");
// Whether or not lock validation is globally enabled.
constexpr bool kLockValidationEnabled = static_cast<bool>(LOCK_DEP_ENABLE_VALIDATION);
// Utility template alias to simplify selecting different types based whether
// lock validation is enabled or disabled.
template <typename EnabledType, typename DisabledType>
using IfLockValidationEnabled = typename std::conditional<kLockValidationEnabled,
EnabledType,
DisabledType>::type;
// Result type that represents whether a lock attempt was successful, or if not
// which check failed.
enum class LockResult : uint8_t {
Success,
AlreadyAcquired,
OutOfOrder,
InvalidNesting,
InvalidIrqSafety,
// Non-fatal error that indicates the dependency hash set for a particular
// lock class is full. Consider increasing the size of the lock dependency
// sets if this error is reported.
MaxLockDependencies,
// Internal error value used to differentiate between dependency set updates
// that add a new edge and those that do not. Only new edges trigger loop
// detection.
DependencyExists,
};
// Returns a string representation of the given LockResult.
static inline const char* ToString(LockResult result) {
switch (result) {
case LockResult::Success:
return "Success";
case LockResult::AlreadyAcquired:
return "Already Acquired";
case LockResult::OutOfOrder:
return "Out Of Order";
case LockResult::InvalidNesting:
return "Invalid Nesting";
case LockResult::InvalidIrqSafety:
return "Invalid Irq Safety";
case LockResult::MaxLockDependencies:
return "Max Lock Dependencies";
case LockResult::DependencyExists:
return "Dependency Exists";
default:
return "Unknown";
}
}
} // namespace lockdep