/* * Wound/Wait Mutexes: blocking mutual exclusion locks with deadlock avoidance * * Original mutex implementation started by Ingo Molnar: * * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar * * Wound/wait implementation: * Copyright (C) 2013 Canonical Ltd. * * Wound/ wait drop-in, actual wound-wait semantics and batching: * Copyright (C) 2016-2018 VMWare Inc. * * This file contains the main data structure and API definitions. */ #ifndef _WW_MUTEX_H_ #define _WW_MUTEX_H_ #include "ww_mutex_test.h" #include #include #include #include #include struct ww_class { spinlock_t lock; atomic_long_t stamp; struct lock_class_key acquire_key; struct lock_class_key mutex_key; const char *acquire_name; const char *mutex_name; bool is_wait_die; }; struct ww_acquire_ctx { struct ww_class *my_class; unsigned long stamp; unsigned long acquired; u32 batched : 1; u32 wounded : 1; u32 done_acquire : 1; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; struct lockdep_map batch_map; #endif #ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH unsigned deadlock_inject_interval; unsigned deadlock_inject_countdown; #endif }; struct ww_mutex { struct mutex base; struct ww_class *my_class; wait_queue_head_t queue; struct ww_acquire_ctx *ctx; }; #define __WW_CLASS_INITIALIZER(ww_class) { \ .lock = __SPIN_LOCK_UNLOCKED(ww_class.lock), \ .stamp = ATOMIC_LONG_INIT(0), \ .acquire_name = #ww_class "_acquire", \ .mutex_name = #ww_class "_mutex", \ .is_wait_die = WW_WAITDIE, \ } #define DEFINE_WW_CLASS(classname) \ struct ww_class classname = __WW_CLASS_INITIALIZER(classname) #ifdef WW_BATCHING void ww_acquire_batch_begin(struct ww_acquire_ctx *ctx); void ww_acquire_batch_end(struct ww_acquire_ctx *ctx); #else #define ww_acquire_batch_begin(_a) #define ww_acquire_batch_end(_a) #endif static inline void ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class) { ctx->my_class = ww_class; ctx->stamp = atomic_long_inc_return(&ww_class->stamp); ctx->acquired = 0L; ctx->batched = false; ctx->wounded = false; ctx->done_acquire = 0; #ifdef CONFIG_DEBUG_LOCK_ALLOC lockdep_init_map(&ctx->dep_map, ww_class->acquire_name, &ww_class->acquire_key, 0); lockdep_init_map(&ctx->batch_map, ww_class->mutex_name, &ww_class->mutex_key, 0); lock_acquire(&ctx->dep_map, 0, 0, 0, 1, NULL, _RET_IP_); lock_acquired(&ctx->dep_map, _RET_IP_); #endif #ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH ctx->deadlock_inject_interval = 1L; ctx->deadlock_inject_countdown = ctx->stamp & 0x0f; #endif } /** * ww_acquire_done - marks the end of the acquire phase * @ctx: the acquire context * * Marks the end of the acquire phase, any further w/w mutex lock calls using * this context are forbidden. * * Calling this function is optional, it is just useful to document w/w mutex * code and clearly designated the acquire phase from actually using the locked * data structures. */ static inline void ww_acquire_done(struct ww_acquire_ctx *ctx) { #ifdef CONFIG_DEBUG_MUTEXES lockdep_assert_held(ctx); WARN_ON(ctx->batched); DEBUG_LOCKS_WARN_ON(ctx->done_acquire); #endif ctx->done_acquire = 1; } /** * ww_acquire_fini - releases a w/w acquire context * @ctx: the acquire context to free * * Releases a w/w acquire context. This must be called _after_ all acquired w/w * mutexes have been released with ww_mutex_unlock. */ static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx) { #ifdef CONFIG_DEBUG_LOCK_ALLOC lock_release(&ctx->dep_map, 0, _THIS_IP_); #endif #ifdef CONFIG_DEBUG_MUTEXES DEBUG_LOCKS_WARN_ON(ctx->acquired); if (!IS_ENABLED(CONFIG_PROVE_LOCKING)) /* * lockdep will normally handle this, * but fail without anyway */ ctx->done_acquire = 1; if (!IS_ENABLED(CONFIG_DEBUG_LOCK_ALLOC)) /* ensure ww_acquire_fini will still fail if called twice */ ctx->acquired = ~0U; #endif } static inline void ww_mutex_init(struct ww_mutex *ww, struct ww_class *ww_class) { ww->my_class = ww_class; ww->ctx = NULL; init_waitqueue_head(&ww->queue); mutex_init(&ww->base); } static inline bool ww_mutex_is_locked(struct ww_mutex *ww) { return mutex_is_locked(&ww->base); } int ww_mutex_trylock(struct ww_mutex *lock); int ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx); #define ww_mutex_lock_slow_interruptible ww_mutex_lock_interruptible int ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx); #define ww_mutex_lock_slow ww_mutex_lock void ww_mutex_unlock(struct ww_mutex *lock); static inline void ww_mutex_destroy(struct ww_mutex *lock) { mutex_destroy(&lock->base); } #endif