Skip to content

Commit 3cd4ca4

Browse files
author
Paul E. McKenney
committed
rcu: Consolidate PREEMPT and !PREEMPT synchronize_rcu_expedited()
The CONFIG_PREEMPT=n and CONFIG_PREEMPT=y implementations of synchronize_rcu_expedited() are quite similar, and with small modifications to rcu_blocking_is_gp() can be made identical. This commit therefore makes this change in order to save a few lines of code and to reduce the amount of duplicate code. Signed-off-by: Paul E. McKenney <[email protected]>
1 parent 142d106 commit 3cd4ca4

File tree

1 file changed

+49
-56
lines changed

1 file changed

+49
-56
lines changed

kernel/rcu/tree_exp.h

Lines changed: 49 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,33 @@ static void _synchronize_rcu_expedited(void)
643643
mutex_unlock(&rcu_state.exp_mutex);
644644
}
645645

646+
/*
647+
* During early boot, any blocking grace-period wait automatically
648+
* implies a grace period. Later on, this is never the case for PREEMPT.
649+
*
650+
* Howevr, because a context switch is a grace period for !PREEMPT, any
651+
* blocking grace-period wait automatically implies a grace period if
652+
* there is only one CPU online at any point time during execution of
653+
* either synchronize_rcu() or synchronize_rcu_expedited(). It is OK to
654+
* occasionally incorrectly indicate that there are multiple CPUs online
655+
* when there was in fact only one the whole time, as this just adds some
656+
* overhead: RCU still operates correctly.
657+
*/
658+
static int rcu_blocking_is_gp(void)
659+
{
660+
int ret;
661+
662+
if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
663+
return true;
664+
if (IS_ENABLED(CONFIG_PREEMPT))
665+
return false;
666+
might_sleep(); /* Check for RCU read-side critical section. */
667+
preempt_disable();
668+
ret = num_online_cpus() <= 1;
669+
preempt_enable();
670+
return ret;
671+
}
672+
646673
#ifdef CONFIG_PREEMPT_RCU
647674

648675
/*
@@ -729,39 +756,6 @@ static void sync_sched_exp_online_cleanup(int cpu)
729756
{
730757
}
731758

732-
/**
733-
* synchronize_rcu_expedited - Brute-force RCU grace period
734-
*
735-
* Wait for an RCU-preempt grace period, but expedite it. The basic
736-
* idea is to IPI all non-idle non-nohz online CPUs. The IPI handler
737-
* checks whether the CPU is in an RCU-preempt critical section, and
738-
* if so, it sets a flag that causes the outermost rcu_read_unlock()
739-
* to report the quiescent state. On the other hand, if the CPU is
740-
* not in an RCU read-side critical section, the IPI handler reports
741-
* the quiescent state immediately.
742-
*
743-
* Although this is a greate improvement over previous expedited
744-
* implementations, it is still unfriendly to real-time workloads, so is
745-
* thus not recommended for any sort of common-case code. In fact, if
746-
* you are using synchronize_rcu_expedited() in a loop, please restructure
747-
* your code to batch your updates, and then Use a single synchronize_rcu()
748-
* instead.
749-
*
750-
* This has the same semantics as (but is more brutal than) synchronize_rcu().
751-
*/
752-
void synchronize_rcu_expedited(void)
753-
{
754-
RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) ||
755-
lock_is_held(&rcu_lock_map) ||
756-
lock_is_held(&rcu_sched_lock_map),
757-
"Illegal synchronize_rcu_expedited() in RCU read-side critical section");
758-
759-
if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
760-
return;
761-
_synchronize_rcu_expedited();
762-
}
763-
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
764-
765759
#else /* #ifdef CONFIG_PREEMPT_RCU */
766760

767761
/* Invoked on each online non-idle CPU for expedited quiescent state. */
@@ -801,40 +795,39 @@ static void sync_sched_exp_online_cleanup(int cpu)
801795
WARN_ON_ONCE(ret);
802796
}
803797

804-
/*
805-
* Because a context switch is a grace period for !PREEMPT, any
806-
* blocking grace-period wait automatically implies a grace period if
807-
* there is only one CPU online at any point time during execution of
808-
* either synchronize_rcu() or synchronize_rcu_expedited(). It is OK to
809-
* occasionally incorrectly indicate that there are multiple CPUs online
810-
* when there was in fact only one the whole time, as this just adds some
811-
* overhead: RCU still operates correctly.
812-
*/
813-
static int rcu_blocking_is_gp(void)
814-
{
815-
int ret;
816-
817-
might_sleep(); /* Check for RCU read-side critical section. */
818-
preempt_disable();
819-
ret = num_online_cpus() <= 1;
820-
preempt_enable();
821-
return ret;
822-
}
798+
#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
823799

824-
/* PREEMPT=n implementation of synchronize_rcu_expedited(). */
800+
/**
801+
* synchronize_rcu_expedited - Brute-force RCU grace period
802+
*
803+
* Wait for an RCU grace period, but expedite it. The basic idea is to
804+
* IPI all non-idle non-nohz online CPUs. The IPI handler checks whether
805+
* the CPU is in an RCU critical section, and if so, it sets a flag that
806+
* causes the outermost rcu_read_unlock() to report the quiescent state
807+
* for RCU-preempt or asks the scheduler for help for RCU-sched. On the
808+
* other hand, if the CPU is not in an RCU read-side critical section,
809+
* the IPI handler reports the quiescent state immediately.
810+
*
811+
* Although this is a greate improvement over previous expedited
812+
* implementations, it is still unfriendly to real-time workloads, so is
813+
* thus not recommended for any sort of common-case code. In fact, if
814+
* you are using synchronize_rcu_expedited() in a loop, please restructure
815+
* your code to batch your updates, and then Use a single synchronize_rcu()
816+
* instead.
817+
*
818+
* This has the same semantics as (but is more brutal than) synchronize_rcu().
819+
*/
825820
void synchronize_rcu_expedited(void)
826821
{
827822
RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) ||
828823
lock_is_held(&rcu_lock_map) ||
829824
lock_is_held(&rcu_sched_lock_map),
830825
"Illegal synchronize_rcu_expedited() in RCU read-side critical section");
831826

832-
/* If only one CPU, this is automatically a grace period. */
827+
/* Is the state is such that the call is a grace period? */
833828
if (rcu_blocking_is_gp())
834829
return;
835830

836831
_synchronize_rcu_expedited();
837832
}
838833
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
839-
840-
#endif /* #else #ifdef CONFIG_PREEMPT_RCU */

0 commit comments

Comments
 (0)