Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

rcu: Create a synchronize_rcu_mult()



There have been several requests for a primitive that waits for
grace periods for several RCU flavors concurrently, so this
commit creates it.  This is a variadic macro, and you pass in
the call_rcu() functions of the flavors of RCU that you wish to
wait for.

Note that you cannot pass in call_srcu() for two reasons: (1) This
would result in a type mismatch and (2) You need to specify which
srcu_struct you want to use.  Handle this by creating a wrapper
function for your SRCU domain, for example:

	void call_srcu_mine(struct rcu_head *head, rcu_callback_t func)
	{
		call_srcu(&ss_mine, head, func);
	}

You can then do something like this:

	synchronize_rcu_mult(call_srcu_mine, call_rcu, call_rcu_sched);

Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent bc17ea10
Loading
Loading
Loading
Loading
+31 −4
Original line number Original line Diff line number Diff line
@@ -226,6 +226,37 @@ struct rcu_synchronize {
};
};
void wakeme_after_rcu(struct rcu_head *head);
void wakeme_after_rcu(struct rcu_head *head);


void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array,
		   struct rcu_synchronize *rs_array);

#define _wait_rcu_gp(checktiny, ...) \
do { \
	call_rcu_func_t __crcu_array[] = { __VA_ARGS__ }; \
	const int __n = ARRAY_SIZE(__crcu_array); \
	struct rcu_synchronize __rs_array[__n]; \
	\
	__wait_rcu_gp(checktiny, __n, __crcu_array, __rs_array); \
} while (0)

#define wait_rcu_gp(...) _wait_rcu_gp(false, __VA_ARGS__)

/**
 * synchronize_rcu_mult - Wait concurrently for multiple grace periods
 * @...: List of call_rcu() functions for the flavors to wait on.
 *
 * This macro waits concurrently for multiple flavors of RCU grace periods.
 * For example, synchronize_rcu_mult(call_rcu, call_rcu_bh) would wait
 * on concurrent RCU and RCU-bh grace periods.  Waiting on a give SRCU
 * domain requires you to write a wrapper function for that SRCU domain's
 * call_srcu() function, supplying the corresponding srcu_struct.
 *
 * If Tiny RCU, tell _wait_rcu_gp() not to bother waiting for RCU
 * or RCU-bh, given that anywhere synchronize_rcu_mult() can be called
 * is automatically a grace period.
 */
#define synchronize_rcu_mult(...) \
	_wait_rcu_gp(IS_ENABLED(CONFIG_TINY_RCU), __VA_ARGS__)

/**
/**
 * call_rcu_tasks() - Queue an RCU for invocation task-based grace period
 * call_rcu_tasks() - Queue an RCU for invocation task-based grace period
 * @head: structure to be used for queueing the RCU updates.
 * @head: structure to be used for queueing the RCU updates.
@@ -392,10 +423,6 @@ bool __rcu_is_watching(void);
 * TREE_RCU and rcu_barrier_() primitives in TINY_RCU.
 * TREE_RCU and rcu_barrier_() primitives in TINY_RCU.
 */
 */


typedef void call_rcu_func_t(struct rcu_head *head,
			     void (*func)(struct rcu_head *head));
void wait_rcu_gp(call_rcu_func_t crf);

#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
#include <linux/rcutree.h>
#include <linux/rcutree.h>
#elif defined(CONFIG_TINY_RCU)
#elif defined(CONFIG_TINY_RCU)
+3 −0
Original line number Original line Diff line number Diff line
@@ -212,6 +212,9 @@ struct callback_head {
};
};
#define rcu_head callback_head
#define rcu_head callback_head


typedef void (*rcu_callback_t)(struct rcu_head *head);
typedef void (*call_rcu_func_t)(struct rcu_head *head, rcu_callback_t func);

/* clocksource cycle base type */
/* clocksource cycle base type */
typedef u64 cycle_t;
typedef u64 cycle_t;


+27 −10
Original line number Original line Diff line number Diff line
@@ -318,20 +318,37 @@ void wakeme_after_rcu(struct rcu_head *head)
	rcu = container_of(head, struct rcu_synchronize, head);
	rcu = container_of(head, struct rcu_synchronize, head);
	complete(&rcu->completion);
	complete(&rcu->completion);
}
}
EXPORT_SYMBOL_GPL(wakeme_after_rcu);


void wait_rcu_gp(call_rcu_func_t crf)
void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array,
		   struct rcu_synchronize *rs_array)
{
{
	struct rcu_synchronize rcu;
	int i;


	init_rcu_head_on_stack(&rcu.head);
	/* Initialize and register callbacks for each flavor specified. */
	init_completion(&rcu.completion);
	for (i = 0; i < n; i++) {
	/* Will wake me after RCU finished. */
		if (checktiny &&
	crf(&rcu.head, wakeme_after_rcu);
		    (crcu_array[i] == call_rcu ||
	/* Wait for it. */
		     crcu_array[i] == call_rcu_bh)) {
	wait_for_completion(&rcu.completion);
			might_sleep();
	destroy_rcu_head_on_stack(&rcu.head);
			continue;
		}
		init_rcu_head_on_stack(&rs_array[i].head);
		init_completion(&rs_array[i].completion);
		(crcu_array[i])(&rs_array[i].head, wakeme_after_rcu);
	}

	/* Wait for all callbacks to be invoked. */
	for (i = 0; i < n; i++) {
		if (checktiny &&
		    (crcu_array[i] == call_rcu ||
		     crcu_array[i] == call_rcu_bh))
			continue;
		wait_for_completion(&rs_array[i].completion);
		destroy_rcu_head_on_stack(&rs_array[i].head);
	}
}
}
EXPORT_SYMBOL_GPL(wait_rcu_gp);
EXPORT_SYMBOL_GPL(__wait_rcu_gp);


#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
void init_rcu_head(struct rcu_head *head)
void init_rcu_head(struct rcu_head *head)