// SPDX-License-Identifier: GPL-2.0 #include <linux/percpu.h> #include <linux/sched.h> #include <linux/osq_lock.h> /* * An MCS like lock especially tailored for optimistic spinning for sleeping * lock implementations (mutex, rwsem, etc). * * Using a single mcs node per CPU is safe because sleeping locks should not be * called from interrupt context and we have preemption disabled while * spinning. */ struct optimistic_spin_node { … }; static DEFINE_PER_CPU_SHARED_ALIGNED(struct optimistic_spin_node, osq_node); /* * We use the value 0 to represent "no CPU", thus the encoded value * will be the CPU number incremented by 1. */ static inline int encode_cpu(int cpu_nr) { … } static inline int node_cpu(struct optimistic_spin_node *node) { … } static inline struct optimistic_spin_node *decode_cpu(int encoded_cpu_val) { … } /* * Get a stable @node->next pointer, either for unlock() or unqueue() purposes. * Can return NULL in case we were the last queued and we updated @lock instead. * * If osq_lock() is being cancelled there must be a previous node * and 'old_cpu' is its CPU #. * For osq_unlock() there is never a previous node and old_cpu is * set to OSQ_UNLOCKED_VAL. */ static inline struct optimistic_spin_node * osq_wait_next(struct optimistic_spin_queue *lock, struct optimistic_spin_node *node, int old_cpu) { … } bool osq_lock(struct optimistic_spin_queue *lock) { … } void osq_unlock(struct optimistic_spin_queue *lock) { … }