/* * Sleepable Read-Copy Update mechanism for mutual exclusion * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Copyright (C) IBM Corporation, 2006 * * Author: Paul McKenney * * For detailed explanation of Read-Copy Update mechanism see - * Documentation/RCU/ *.txt * */ #ifndef _LINUX_SRCU_H #define _LINUX_SRCU_H #include #include struct srcu_struct_array { int c[2]; }; struct srcu_struct { int completed; struct srcu_struct_array __percpu *per_cpu_ref; struct mutex mutex; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif }; #ifndef CONFIG_PREEMPT #define srcu_barrier() barrier() #else #define srcu_barrier() #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC int __init_srcu_struct(struct srcu_struct *sp, const char *name, struct lock_class_key *key); #define init_srcu_struct(sp) \ ({ \ static struct lock_class_key __srcu_key; \ \ __init_srcu_struct((sp), #sp, &__srcu_key); \ }) #else int init_srcu_struct(struct srcu_struct *sp); #endif void cleanup_srcu_struct(struct srcu_struct *sp); int __srcu_read_lock(struct srcu_struct *sp) __acquires(sp); void __srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); void synchronize_srcu(struct srcu_struct *sp); void synchronize_srcu_expedited(struct srcu_struct *sp); long srcu_batches_completed(struct srcu_struct *sp); #ifdef CONFIG_DEBUG_LOCK_ALLOC static inline int srcu_read_lock_held(struct srcu_struct *sp) { if (!debug_lockdep_rcu_enabled()) return 1; if (rcu_is_cpu_idle()) return 0; if (!rcu_lockdep_current_cpu_online()) return 0; return lock_is_held(&sp->dep_map); } #else static inline int srcu_read_lock_held(struct srcu_struct *sp) { return 1; } #endif #define srcu_dereference_check(p, sp, c) \ __rcu_dereference_check((p), srcu_read_lock_held(sp) || (c), __rcu) #define srcu_dereference(p, sp) srcu_dereference_check((p), (sp), 0) static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp) { int retval = __srcu_read_lock(sp); rcu_lock_acquire(&(sp)->dep_map); rcu_lockdep_assert(!rcu_is_cpu_idle(), "srcu_read_lock() used illegally while idle"); return retval; } static inline void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp) { rcu_lockdep_assert(!rcu_is_cpu_idle(), "srcu_read_unlock() used illegally while idle"); rcu_lock_release(&(sp)->dep_map); __srcu_read_unlock(sp, idx); } static inline int srcu_read_lock_raw(struct srcu_struct *sp) { unsigned long flags; int ret; local_irq_save(flags); ret = __srcu_read_lock(sp); local_irq_restore(flags); return ret; } static inline void srcu_read_unlock_raw(struct srcu_struct *sp, int idx) { unsigned long flags; local_irq_save(flags); __srcu_read_unlock(sp, idx); local_irq_restore(flags); } #endif