Commit 3cd4ca47 authored by Paul E. McKenney's avatar Paul E. McKenney
Browse files

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: default avatarPaul E. McKenney <paulmck@linux.ibm.com>
parent 142d106d
Loading
Loading
Loading
Loading
+49 −56
Original line number Diff line number Diff line
@@ -643,6 +643,33 @@ static void _synchronize_rcu_expedited(void)
	mutex_unlock(&rcu_state.exp_mutex);
}

/*
 * During early boot, any blocking grace-period wait automatically
 * implies a grace period.  Later on, this is never the case for PREEMPT.
 *
 * Howevr, because a context switch is a grace period for !PREEMPT, any
 * blocking grace-period wait automatically implies a grace period if
 * there is only one CPU online at any point time during execution of
 * either synchronize_rcu() or synchronize_rcu_expedited().  It is OK to
 * occasionally incorrectly indicate that there are multiple CPUs online
 * when there was in fact only one the whole time, as this just adds some
 * overhead: RCU still operates correctly.
 */
static int rcu_blocking_is_gp(void)
{
	int ret;

	if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
		return true;
	if (IS_ENABLED(CONFIG_PREEMPT))
		return false;
	might_sleep();  /* Check for RCU read-side critical section. */
	preempt_disable();
	ret = num_online_cpus() <= 1;
	preempt_enable();
	return ret;
}

#ifdef CONFIG_PREEMPT_RCU

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

/**
 * synchronize_rcu_expedited - Brute-force RCU grace period
 *
 * Wait for an RCU-preempt grace period, but expedite it.  The basic
 * idea is to IPI all non-idle non-nohz online CPUs.  The IPI handler
 * checks whether the CPU is in an RCU-preempt critical section, and
 * if so, it sets a flag that causes the outermost rcu_read_unlock()
 * to report the quiescent state.  On the other hand, if the CPU is
 * not in an RCU read-side critical section, the IPI handler reports
 * the quiescent state immediately.
 *
 * Although this is a greate improvement over previous expedited
 * implementations, it is still unfriendly to real-time workloads, so is
 * thus not recommended for any sort of common-case code.  In fact, if
 * you are using synchronize_rcu_expedited() in a loop, please restructure
 * your code to batch your updates, and then Use a single synchronize_rcu()
 * instead.
 *
 * This has the same semantics as (but is more brutal than) synchronize_rcu().
 */
void synchronize_rcu_expedited(void)
{
	RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) ||
			 lock_is_held(&rcu_lock_map) ||
			 lock_is_held(&rcu_sched_lock_map),
			 "Illegal synchronize_rcu_expedited() in RCU read-side critical section");

	if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
		return;
	_synchronize_rcu_expedited();
}
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);

#else /* #ifdef CONFIG_PREEMPT_RCU */

/* Invoked on each online non-idle CPU for expedited quiescent state. */
@@ -801,27 +795,28 @@ static void sync_sched_exp_online_cleanup(int cpu)
	WARN_ON_ONCE(ret);
}

/*
 * Because a context switch is a grace period for !PREEMPT, any
 * blocking grace-period wait automatically implies a grace period if
 * there is only one CPU online at any point time during execution of
 * either synchronize_rcu() or synchronize_rcu_expedited().  It is OK to
 * occasionally incorrectly indicate that there are multiple CPUs online
 * when there was in fact only one the whole time, as this just adds some
 * overhead: RCU still operates correctly.
 */
static int rcu_blocking_is_gp(void)
{
	int ret;

	might_sleep();  /* Check for RCU read-side critical section. */
	preempt_disable();
	ret = num_online_cpus() <= 1;
	preempt_enable();
	return ret;
}
#endif /* #else #ifdef CONFIG_PREEMPT_RCU */

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

	/* If only one CPU, this is automatically a grace period. */
	/* Is the state is such that the call is a grace period? */
	if (rcu_blocking_is_gp())
		return;

	_synchronize_rcu_expedited();
}
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);

#endif /* #else #ifdef CONFIG_PREEMPT_RCU */