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

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

rcu: Create call_rcu_tasks() kthread at boot time



Currently the call_rcu_tasks() kthread is created upon first
invocation of call_rcu_tasks().  This has the advantage of avoiding
creation if there are never any invocations of call_rcu_tasks() and of
synchronize_rcu_tasks(), but it requires an unreliable heuristic to
determine when it is safe to create the kthread.  For example, it is
not safe to create the kthread when call_rcu_tasks() is invoked with
a spinlock held, but there is no good way to detect this in !PREEMPT
kernels.

This commit therefore creates this kthread unconditionally at
core_initcall() time.  If you don't want this kthread created, then
build with CONFIG_TASKS_RCU=n.

Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent 135bd1a2
Loading
Loading
Loading
Loading
+5 −19
Original line number Original line Diff line number Diff line
@@ -575,7 +575,6 @@ DEFINE_STATIC_SRCU(tasks_rcu_exit_srcu);
static int rcu_task_stall_timeout __read_mostly = RCU_TASK_STALL_TIMEOUT;
static int rcu_task_stall_timeout __read_mostly = RCU_TASK_STALL_TIMEOUT;
module_param(rcu_task_stall_timeout, int, 0644);
module_param(rcu_task_stall_timeout, int, 0644);


static void rcu_spawn_tasks_kthread(void);
static struct task_struct *rcu_tasks_kthread_ptr;
static struct task_struct *rcu_tasks_kthread_ptr;


/**
/**
@@ -600,7 +599,6 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func)
{
{
	unsigned long flags;
	unsigned long flags;
	bool needwake;
	bool needwake;
	bool havetask = READ_ONCE(rcu_tasks_kthread_ptr);


	rhp->next = NULL;
	rhp->next = NULL;
	rhp->func = func;
	rhp->func = func;
@@ -610,12 +608,9 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func)
	rcu_tasks_cbs_tail = &rhp->next;
	rcu_tasks_cbs_tail = &rhp->next;
	raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags);
	raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags);
	/* We can't create the thread unless interrupts are enabled. */
	/* We can't create the thread unless interrupts are enabled. */
	if ((needwake && havetask) ||
	if (needwake && READ_ONCE(rcu_tasks_kthread_ptr))
	    (!havetask && !irqs_disabled_flags(flags))) {
		rcu_spawn_tasks_kthread();
		wake_up(&rcu_tasks_cbs_wq);
		wake_up(&rcu_tasks_cbs_wq);
}
}
}
EXPORT_SYMBOL_GPL(call_rcu_tasks);
EXPORT_SYMBOL_GPL(call_rcu_tasks);


/**
/**
@@ -853,27 +848,18 @@ static int __noreturn rcu_tasks_kthread(void *arg)
	}
	}
}
}


/* Spawn rcu_tasks_kthread() at first call to call_rcu_tasks(). */
/* Spawn rcu_tasks_kthread() at core_initcall() time. */
static void rcu_spawn_tasks_kthread(void)
static int __init rcu_spawn_tasks_kthread(void)
{
{
	static DEFINE_MUTEX(rcu_tasks_kthread_mutex);
	struct task_struct *t;
	struct task_struct *t;


	if (READ_ONCE(rcu_tasks_kthread_ptr)) {
		smp_mb(); /* Ensure caller sees full kthread. */
		return;
	}
	mutex_lock(&rcu_tasks_kthread_mutex);
	if (rcu_tasks_kthread_ptr) {
		mutex_unlock(&rcu_tasks_kthread_mutex);
		return;
	}
	t = kthread_run(rcu_tasks_kthread, NULL, "rcu_tasks_kthread");
	t = kthread_run(rcu_tasks_kthread, NULL, "rcu_tasks_kthread");
	BUG_ON(IS_ERR(t));
	BUG_ON(IS_ERR(t));
	smp_mb(); /* Ensure others see full kthread. */
	smp_mb(); /* Ensure others see full kthread. */
	WRITE_ONCE(rcu_tasks_kthread_ptr, t);
	WRITE_ONCE(rcu_tasks_kthread_ptr, t);
	mutex_unlock(&rcu_tasks_kthread_mutex);
	return 0;
}
}
core_initcall(rcu_spawn_tasks_kthread);


/* Do the srcu_read_lock() for the above synchronize_srcu().  */
/* Do the srcu_read_lock() for the above synchronize_srcu().  */
void exit_tasks_rcu_start(void)
void exit_tasks_rcu_start(void)