blob: 8007a095e6054f8bfb1795049c0c254386dfad14 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2014 Travis Geiselbrecht
//
// 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
#pragma once
#include <arch/arch_ops.h>
#include <arch/spinlock.h>
#include <zircon/compiler.h>
#include <zircon/thread_annotations.h>
__BEGIN_CDECLS
/* returns true if |lock| is held by the current CPU;
* interrupts should be disabled before calling */
static inline bool spin_lock_held(spin_lock_t* lock) {
return arch_spin_lock_held(lock);
}
// interrupts should already be disabled
static inline void spin_lock(spin_lock_t* lock) TA_ACQ(lock) {
DEBUG_ASSERT(arch_ints_disabled());
DEBUG_ASSERT(!spin_lock_held(lock));
arch_spin_lock(lock);
}
// Returns 0 on success, non-0 on failure
static inline int spin_trylock(spin_lock_t* lock) TA_TRY_ACQ(false, lock) {
return arch_spin_trylock(lock);
}
// interrupts should already be disabled
static inline void spin_unlock(spin_lock_t* lock) TA_REL(lock) {
arch_spin_unlock(lock);
}
static inline void spin_lock_init(spin_lock_t* lock) {
*lock = SPIN_LOCK_INITIAL_VALUE;
}
// which cpu currently holds the spin lock
// returns UINT_MAX if not held
static inline uint spin_lock_holder_cpu(spin_lock_t* lock) {
return arch_spin_lock_holder_cpu(lock);
}
// spin lock irq save flags:
// Possible future flags:
// SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff
// SPIN_LOCK_FLAG_PREEMPTION = 0x00000100
// SPIN_LOCK_FLAG_SET_PMR = 0x00000200
// Generic flags
#define SPIN_LOCK_FLAG_INTERRUPTS ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS
// same as spin lock, but save disable and save interrupt state first
static inline void spin_lock_save(spin_lock_t* lock, spin_lock_saved_state_t* statep,
spin_lock_save_flags_t flags) TA_ACQ(lock) {
arch_interrupt_save(statep, flags);
spin_lock(lock);
}
// restore interrupt state before unlocking
static inline void spin_unlock_restore(spin_lock_t* lock, spin_lock_saved_state_t old_state,
spin_lock_save_flags_t flags) TA_REL(lock) {
spin_unlock(lock);
arch_interrupt_restore(old_state, flags);
}
// hand(ier) routines
#define spin_lock_irqsave(lock, statep) spin_lock_save(lock, &(statep), SPIN_LOCK_FLAG_INTERRUPTS)
#define spin_unlock_irqrestore(lock, statep) spin_unlock_restore(lock, statep, SPIN_LOCK_FLAG_INTERRUPTS)
__END_CDECLS
#ifdef __cplusplus
#include <lockdep/lock_policy.h>
#include <lockdep/lock_traits.h>
class TA_CAP("mutex") SpinLock {
public:
constexpr SpinLock() = default;
void Acquire() TA_ACQ() { spin_lock(&spinlock_); }
bool TryAcquire() TA_TRY_ACQ(false) { return spin_trylock(&spinlock_); }
void Release() TA_REL() { spin_unlock(&spinlock_); }
bool IsHeld() { return spin_lock_held(&spinlock_); }
void AcquireIrqSave(spin_lock_saved_state_t& state,
spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
TA_ACQ() {
spin_lock_save(&spinlock_, &state, flags);
}
void ReleaseIrqRestore(spin_lock_saved_state_t state,
spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
TA_REL() {
spin_unlock_restore(&spinlock_, state, flags);
}
spin_lock_t* GetInternal() TA_RET_CAP(spinlock_) { return &spinlock_; }
// suppress default constructors
SpinLock(const SpinLock& am) = delete;
SpinLock& operator=(const SpinLock& am) = delete;
SpinLock(SpinLock&& c) = delete;
SpinLock& operator=(SpinLock&& c) = delete;
private:
spin_lock_t spinlock_ = SPIN_LOCK_INITIAL_VALUE;
};
// Declares a SpinLock member of the struct or class |containing_type|
// with instrumentation for runtime lock validation.
//
// Example usage:
//
// struct MyType {
// DECLARE_SPINLOCK(MyType) lock;
// };
//
#define DECLARE_SPINLOCK(containing_type) \
LOCK_DEP_INSTRUMENT(containing_type, SpinLock)
// Declares a singleton SpinLock with the name |name|.
//
// Example usage:
//
// DECLARE_SINGLETON_SPINLOCK(MyGlobalLock [, LockFlags]);
//
#define DECLARE_SINGLETON_SPINLOCK(name, ...) \
LOCK_DEP_SINGLETON_LOCK(name, SpinLock, ##__VA_ARGS__)
//
// Configure lockdep flags and wrappers for SpinLock.
//
// Configure lockdep to check irq-safety rules for SpinLock.
LOCK_DEP_TRAITS(SpinLock, lockdep::LockFlagsIrqSafe);
// Configure lockdep to check irq-safety rules for spin_lock_t.
LOCK_DEP_TRAITS(spin_lock_t, lockdep::LockFlagsIrqSafe);
// Option tag for acquiring a SpinLock WITHOUT saving irq state.
struct NoIrqSave {};
// Option tag for acquiring a SpinLock WITH saving irq state.
struct IrqSave {};
// Option tag for try-acquiring a SpinLock WITHOUT saving irq state.
struct TryLockNoIrqSave {};
// Base type for spinlock policies that do not save irq state.
template <typename LockType>
struct NoIrqSavePolicy;
// Lock policy for acquiring a SpinLock WITHOUT saving irq state.
template <>
struct NoIrqSavePolicy<SpinLock> {
// No extra state required when not saving irq state.
struct State {};
static bool Acquire(SpinLock* lock, State*) TA_ACQ(lock) {
lock->Acquire();
return true;
}
static void Release(SpinLock* lock, State*) TA_REL(lock) {
lock->Release();
}
};
// Configure Guard<SpinLock, NoIrqSave> to use the above policy to acquire and
// release a SpinLock.
LOCK_DEP_POLICY_OPTION(SpinLock, NoIrqSave, NoIrqSavePolicy<SpinLock>);
// Lock policy for acquiring a SpinLock WITHOUT saving irq state.
template <>
struct NoIrqSavePolicy<spin_lock_t> {
// No extra state required when not saving irq state.
struct State {};
static bool Acquire(spin_lock_t* lock, State*) TA_ACQ(lock) {
spin_lock(lock);
return true;
}
static void Release(spin_lock_t* lock, State*) TA_REL(lock) {
spin_unlock(lock);
}
};
// Configure Guard<spin_lock_t, NoIrqSave> to use the above policy to acquire and
// release a spin_lock_t.
LOCK_DEP_POLICY_OPTION(spin_lock_t, NoIrqSave, NoIrqSavePolicy<spin_lock_t>);
// Base type for spinlock policies that save irq state.
template <typename LockType>
struct IrqSavePolicy;
// Lock policy for acquiring a SpinLock WITH saving irq state.
template <>
struct IrqSavePolicy<SpinLock> {
// State and flags required to save irq state.
struct State {
// This constructor receives the extra arguments passed to Guard when
// locking an instrumented SpinLock like this:
//
// Guard<SpinLock, IrqSave> guard{&a_spin_lock, |flags|};
//
// The extra argument to Guard is optional because this constructor has
// a default value.
State(spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
: flags{flags} {}
spin_lock_save_flags_t flags;
spin_lock_saved_state_t state;
};
static bool Acquire(SpinLock* lock, State* state) TA_ACQ(lock) {
lock->AcquireIrqSave(state->state, state->flags);
return true;
}
static void Release(SpinLock* lock, State* state) TA_REL(lock) {
lock->ReleaseIrqRestore(state->state, state->flags);
}
};
// Configure Guard<SpinLock, IrqSave> to use the above policy to acquire and
// release a SpinLock.
LOCK_DEP_POLICY_OPTION(SpinLock, IrqSave, IrqSavePolicy<SpinLock>);
// Lock policy for acquiring a spin_lock_t WITH saving irq state.
template <>
struct IrqSavePolicy<spin_lock_t> {
// State and flags required to save irq state.
struct State {
// This constructor receives the extra arguments passed to Guard when
// locking an instrumented spin_lock_t like this:
//
// Guard<spin_lock_t, IrqSave> guard{&a_spin_lock, |flags|};
//
// The extra argument to Guard is optional because this constructor has
// a default value.
State(spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
: flags{flags} {}
spin_lock_save_flags_t flags;
spin_lock_saved_state_t state;
};
static bool Acquire(spin_lock_t* lock, State* state) TA_ACQ(lock) {
spin_lock_save(lock, &state->state, state->flags);
return true;
}
static void Release(spin_lock_t* lock, State* state) TA_REL(lock) {
spin_unlock_restore(lock, state->state, state->flags);
}
};
// Configure Guard<SpinLock, IrqSave> to use the above policy to acquire and
// release a SpinLock.
LOCK_DEP_POLICY_OPTION(spin_lock_t, IrqSave, IrqSavePolicy<spin_lock_t>);
// Base type for spinlock policies that try-acquire without saving irq state.
template <typename LockType>
struct TryLockNoIrqSavePolicy;
// Lock policy for try-acquiring a SpinLock WITHOUT saving irq state.
template <>
struct TryLockNoIrqSavePolicy<SpinLock> {
// No extra state required when not saving irq state.
struct State {};
static bool Acquire(SpinLock* lock, State*) TA_TRY_ACQ(true, lock) {
const bool failed = lock->TryAcquire();
return !failed; // Guard uses true to indicate success.
}
static void Release(SpinLock* lock, State*) TA_REL(lock) {
lock->Release();
}
};
// Configure Guard<SpinLock, TryLockNoIrqSave> to use the above policy to
// acquire and release a SpinLock.
LOCK_DEP_POLICY_OPTION(SpinLock, TryLockNoIrqSave,
TryLockNoIrqSavePolicy<SpinLock>);
// Lock policy for try-acquiring a spin_lock_t WITHOUT saving irq state.
template <>
struct TryLockNoIrqSavePolicy<spin_lock_t> {
// No extra state required when not saving irq state.
struct State {};
static bool Acquire(spin_lock_t* lock, State*) TA_TRY_ACQ(true, lock) {
const bool failed = spin_trylock(lock);
return !failed; // Guard uses true to indicate success.
}
static void Release(spin_lock_t* lock, State*) TA_REL(lock) {
spin_unlock(lock);
}
};
// Configure Guard<spin_lock_t, TryLockNoIrqSave> to use the above policy to
// acquire and release a spin_lock_t.
LOCK_DEP_POLICY_OPTION(spin_lock_t, TryLockNoIrqSave,
TryLockNoIrqSavePolicy<spin_lock_t>);
#endif // ifdef __cplusplus