Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
[safe/jmp/linux-2.6] / include / linux / rcupreempt.h
index 8a05c7e..fce5227 100644 (file)
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 #include <linux/threads.h>
-#include <linux/percpu.h>
+#include <linux/smp.h>
 #include <linux/cpumask.h>
 #include <linux/seqlock.h>
 
-#define rcu_qsctr_inc(cpu)
-#define rcu_bh_qsctr_inc(cpu)
-#define call_rcu_bh(head, rcu) call_rcu(head, rcu)
+extern void rcu_qsctr_inc(int cpu);
+static inline void rcu_bh_qsctr_inc(int cpu) { }
+
+/*
+ * Someone might want to pass call_rcu_bh as a function pointer.
+ * So this needs to just be a rename and not a macro function.
+ *  (no parentheses)
+ */
+#define call_rcu_bh            call_rcu
+
+/**
+ * call_rcu_sched - Queue RCU callback for invocation after sched grace period.
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual update function to be invoked after the grace period
+ *
+ * The update function will be invoked some time after a full
+ * synchronize_sched()-style grace period elapses, in other words after
+ * all currently executing preempt-disabled sections of code (including
+ * hardirq handlers, NMI handlers, and local_irq_save() blocks) have
+ * completed.
+ */
+extern void call_rcu_sched(struct rcu_head *head,
+                          void (*func)(struct rcu_head *head));
 
 extern void __rcu_read_lock(void)      __acquires(RCU);
 extern void __rcu_read_unlock(void)    __releases(RCU);
@@ -55,6 +75,7 @@ extern int rcu_needs_cpu(int cpu);
 extern void __synchronize_sched(void);
 
 extern void __rcu_init(void);
+extern void rcu_init_sched(void);
 extern void rcu_check_callbacks(int cpu, int user);
 extern void rcu_restart_cpu(int cpu);
 extern long rcu_batches_completed(void);
@@ -81,25 +102,26 @@ extern struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu);
 struct softirq_action;
 
 #ifdef CONFIG_NO_HZ
-DECLARE_PER_CPU(long, dynticks_progress_counter);
-
-static inline void rcu_enter_nohz(void)
-{
-       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
-       __get_cpu_var(dynticks_progress_counter)++;
-       WARN_ON(__get_cpu_var(dynticks_progress_counter) & 0x1);
-}
+extern void rcu_enter_nohz(void);
+extern void rcu_exit_nohz(void);
+#else
+# define rcu_enter_nohz()      do { } while (0)
+# define rcu_exit_nohz()       do { } while (0)
+#endif
 
-static inline void rcu_exit_nohz(void)
+/*
+ * A context switch is a grace period for rcupreempt synchronize_rcu()
+ * only during early boot, before the scheduler has been initialized.
+ * So, how the heck do we get a context switch?  Well, if the caller
+ * invokes synchronize_rcu(), they are willing to accept a context
+ * switch, so we simply pretend that one happened.
+ *
+ * After boot, there might be a blocked or preempted task in an RCU
+ * read-side critical section, so we cannot then take the fastpath.
+ */
+static inline int rcu_blocking_is_gp(void)
 {
-       __get_cpu_var(dynticks_progress_counter)++;
-       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
-       WARN_ON(!(__get_cpu_var(dynticks_progress_counter) & 0x1));
+       return num_online_cpus() == 1 && !rcu_scheduler_active;
 }
 
-#else /* CONFIG_NO_HZ */
-#define rcu_enter_nohz()       do { } while (0)
-#define rcu_exit_nohz()                do { } while (0)
-#endif /* CONFIG_NO_HZ */
-
 #endif /* __LINUX_RCUPREEMPT_H */