cregit-Linux how code gets into the kernel

Release 4.15 kernel/rcu/tree_plugin.h

Directory: kernel/rcu
/*
 * Read-Copy Update mechanism for mutual exclusion (tree-based version)
 * Internal non-public definitions that provide either classic
 * or preemptible semantics.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you can access it online at
 * http://www.gnu.org/licenses/gpl-2.0.html.
 *
 * Copyright Red Hat, 2009
 * Copyright IBM Corporation, 2009
 *
 * Author: Ingo Molnar <mingo@elte.hu>
 *         Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 */

#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/oom.h>
#include <linux/sched/debug.h>
#include <linux/smpboot.h>
#include <linux/sched/isolation.h>
#include <uapi/linux/sched/types.h>
#include "../time/tick-internal.h"

#ifdef CONFIG_RCU_BOOST

#include "../locking/rtmutex_common.h"

/*
 * Control variables for per-CPU and per-rcu_node kthreads.  These
 * handle all flavors of RCU.
 */
static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
DEFINE_PER_CPU(char, rcu_cpu_has_work);

#else /* #ifdef CONFIG_RCU_BOOST */

/*
 * Some architectures do not define rt_mutexes, but if !CONFIG_RCU_BOOST,
 * all uses are in dead code.  Provide a definition to keep the compiler
 * happy, but add WARN_ON_ONCE() to complain if used in the wrong place.
 * This probably needs to be excluded from -rt builds.
 */

#define rt_mutex_owner(a) ({ WARN_ON_ONCE(1); NULL; })

#define rt_mutex_futex_unlock(x) WARN_ON_ONCE(1)

#endif /* #else #ifdef CONFIG_RCU_BOOST */

#ifdef CONFIG_RCU_NOCB_CPU

static cpumask_var_t rcu_nocb_mask; 
/* CPUs to have callbacks offloaded. */

static bool have_rcu_nocb_mask;	    
/* Was rcu_nocb_mask allocated? */

static bool __read_mostly rcu_nocb_poll;    
/* Offload kthread are to poll. */
#endif /* #ifdef CONFIG_RCU_NOCB_CPU */

/*
 * Check the RCU kernel configuration parameters and print informative
 * messages about anything out of the ordinary.
 */

static void __init rcu_bootup_announce_oddness(void) { if (IS_ENABLED(CONFIG_RCU_TRACE)) pr_info("\tRCU event tracing is enabled.\n"); if ((IS_ENABLED(CONFIG_64BIT) && RCU_FANOUT != 64) || (!IS_ENABLED(CONFIG_64BIT) && RCU_FANOUT != 32)) pr_info("\tCONFIG_RCU_FANOUT set to non-default value of %d\n", RCU_FANOUT); if (rcu_fanout_exact) pr_info("\tHierarchical RCU autobalancing is disabled.\n"); if (IS_ENABLED(CONFIG_RCU_FAST_NO_HZ)) pr_info("\tRCU dyntick-idle grace-period acceleration is enabled.\n"); if (IS_ENABLED(CONFIG_PROVE_RCU)) pr_info("\tRCU lockdep checking is enabled.\n"); if (RCU_NUM_LVLS >= 4) pr_info("\tFour(or more)-level hierarchy is enabled.\n"); if (RCU_FANOUT_LEAF != 16) pr_info("\tBuild-time adjustment of leaf fanout to %d.\n", RCU_FANOUT_LEAF); if (rcu_fanout_leaf != RCU_FANOUT_LEAF) pr_info("\tBoot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf); if (nr_cpu_ids != NR_CPUS) pr_info("\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%u.\n", NR_CPUS, nr_cpu_ids); #ifdef CONFIG_RCU_BOOST pr_info("\tRCU priority boosting: priority %d delay %d ms.\n", kthread_prio, CONFIG_RCU_BOOST_DELAY); #endif if (blimit != DEFAULT_RCU_BLIMIT) pr_info("\tBoot-time adjustment of callback invocation limit to %ld.\n", blimit); if (qhimark != DEFAULT_RCU_QHIMARK) pr_info("\tBoot-time adjustment of callback high-water mark to %ld.\n", qhimark); if (qlowmark != DEFAULT_RCU_QLOMARK) pr_info("\tBoot-time adjustment of callback low-water mark to %ld.\n", qlowmark); if (jiffies_till_first_fqs != ULONG_MAX) pr_info("\tBoot-time adjustment of first FQS scan delay to %ld jiffies.\n", jiffies_till_first_fqs); if (jiffies_till_next_fqs != ULONG_MAX) pr_info("\tBoot-time adjustment of subsequent FQS scan delay to %ld jiffies.\n", jiffies_till_next_fqs); if (rcu_kick_kthreads) pr_info("\tKick kthreads if too-long grace period.\n"); if (IS_ENABLED(CONFIG_DEBUG_OBJECTS_RCU_HEAD)) pr_info("\tRCU callback double-/use-after-free debug enabled.\n"); if (gp_preinit_delay) pr_info("\tRCU debug GP pre-init slowdown %d jiffies.\n", gp_preinit_delay); if (gp_init_delay) pr_info("\tRCU debug GP init slowdown %d jiffies.\n", gp_init_delay); if (gp_cleanup_delay) pr_info("\tRCU debug GP init slowdown %d jiffies.\n", gp_cleanup_delay); if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG)) pr_info("\tRCU debug extended QS entry/exit.\n"); rcupdate_announce_bootup_oddness(); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney27696.50%1482.35%
Clark Williams51.75%15.88%
Alexander Gordeev41.40%15.88%
Alexey Dobriyan10.35%15.88%
Total286100.00%17100.00%

#ifdef CONFIG_PREEMPT_RCU RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu); static struct rcu_state *const rcu_state_p = &rcu_preempt_state; static struct rcu_data __percpu *const rcu_data_p = &rcu_preempt_data; static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, bool wake); /* * Tell them what RCU they are running. */
static void __init rcu_bootup_announce(void) { pr_info("Preemptible hierarchical RCU implementation.\n"); rcu_bootup_announce_oddness(); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney17100.00%5100.00%
Total17100.00%5100.00%

/* Flags for rcu_preempt_ctxt_queue() decision table. */ #define RCU_GP_TASKS 0x8 #define RCU_EXP_TASKS 0x4 #define RCU_GP_BLKD 0x2 #define RCU_EXP_BLKD 0x1 /* * Queues a task preempted within an RCU-preempt read-side critical * section into the appropriate location within the ->blkd_tasks list, * depending on the states of any ongoing normal and expedited grace * periods. The ->gp_tasks pointer indicates which element the normal * grace period is waiting on (NULL if none), and the ->exp_tasks pointer * indicates which element the expedited grace period is waiting on (again, * NULL if none). If a grace period is waiting on a given element in the * ->blkd_tasks list, it also waits on all subsequent elements. Thus, * adding a task to the tail of the list blocks any grace period that is * already waiting on one of the elements. In contrast, adding a task * to the head of the list won't block any grace period that is already * waiting on one of the elements. * * This queuing is imprecise, and can sometimes make an ongoing grace * period wait for a task that is not strictly speaking blocking it. * Given the choice, we needlessly block a normal grace period rather than * blocking an expedited grace period. * * Note that an endless sequence of expedited grace periods still cannot * indefinitely postpone a normal grace period. Eventually, all of the * fixed number of preempted tasks blocking the normal grace period that are * not also blocking the expedited grace period will resume and complete * their RCU read-side critical sections. At that point, the ->gp_tasks * pointer will equal the ->exp_tasks pointer, at which point the end of * the corresponding expedited grace period will also be the end of the * normal grace period. */
static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp) __releases(rnp->lock) /* But leaves rrupts disabled. */ { int blkd_state = (rnp->gp_tasks ? RCU_GP_TASKS : 0) + (rnp->exp_tasks ? RCU_EXP_TASKS : 0) + (rnp->qsmask & rdp->grpmask ? RCU_GP_BLKD : 0) + (rnp->expmask & rdp->grpmask ? RCU_EXP_BLKD : 0); struct task_struct *t = current; lockdep_assert_held(&rnp->lock); WARN_ON_ONCE(rdp->mynode != rnp); WARN_ON_ONCE(rnp->level != rcu_num_lvls - 1); /* * Decide where to queue the newly blocked task. In theory, * this could be an if-statement. In practice, when I tried * that, it was quite messy. */ switch (blkd_state) { case 0: case RCU_EXP_TASKS: case RCU_EXP_TASKS + RCU_GP_BLKD: case RCU_GP_TASKS: case RCU_GP_TASKS + RCU_EXP_TASKS: /* * Blocking neither GP, or first task blocking the normal * GP but not blocking the already-waiting expedited GP. * Queue at the head of the list to avoid unnecessarily * blocking the already-waiting GPs. */ list_add(&t->rcu_node_entry, &rnp->blkd_tasks); break; case RCU_EXP_BLKD: case RCU_GP_BLKD: case RCU_GP_BLKD + RCU_EXP_BLKD: case RCU_GP_TASKS + RCU_EXP_BLKD: case RCU_GP_TASKS + RCU_GP_BLKD + RCU_EXP_BLKD: case RCU_GP_TASKS + RCU_EXP_TASKS + RCU_GP_BLKD + RCU_EXP_BLKD: /* * First task arriving that blocks either GP, or first task * arriving that blocks the expedited GP (with the normal * GP already waiting), or a task arriving that blocks * both GPs with both GPs already waiting. Queue at the * tail of the list to avoid any GP waiting on any of the * already queued tasks that are not blocking it. */ list_add_tail(&t->rcu_node_entry, &rnp->blkd_tasks); break; case RCU_EXP_TASKS + RCU_EXP_BLKD: case RCU_EXP_TASKS + RCU_GP_BLKD + RCU_EXP_BLKD: case RCU_GP_TASKS + RCU_EXP_TASKS + RCU_EXP_BLKD: /* * Second or subsequent task blocking the expedited GP. * The task either does not block the normal GP, or is the * first task blocking the normal GP. Queue just after * the first task blocking the expedited GP. */ list_add(&t->rcu_node_entry, rnp->exp_tasks); break; case RCU_GP_TASKS + RCU_GP_BLKD: case RCU_GP_TASKS + RCU_EXP_TASKS + RCU_GP_BLKD: /* * Second or subsequent task blocking the normal GP. * The task does not block the expedited GP. Queue just * after the first task blocking the normal GP. */ list_add(&t->rcu_node_entry, rnp->gp_tasks); break; default: /* Yet another exercise in excessive paranoia. */ WARN_ON_ONCE(1); break; } /* * We have now queued the task. If it was the first one to * block either grace period, update the ->gp_tasks and/or * ->exp_tasks pointers, respectively, to reference the newly * blocked tasks. */ if (!rnp->gp_tasks && (blkd_state & RCU_GP_BLKD)) rnp->gp_tasks = &t->rcu_node_entry; if (!rnp->exp_tasks && (blkd_state & RCU_EXP_BLKD)) rnp->exp_tasks = &t->rcu_node_entry; WARN_ON_ONCE(!(blkd_state & RCU_GP_BLKD) != !(rnp->qsmask & rdp->grpmask)); WARN_ON_ONCE(!(blkd_state & RCU_EXP_BLKD) != !(rnp->expmask & rdp->grpmask)); raw_spin_unlock_rcu_node(rnp); /* interrupts remain disabled. */ /* * Report the quiescent state for the expedited GP. This expedited * GP should not be able to end until we report, so there should be * no need to check for a subsequent expedited GP. (Though we are * still in a quiescent state in any case.) */ if (blkd_state & RCU_EXP_BLKD && t->rcu_read_unlock_special.b.exp_need_qs) { t->rcu_read_unlock_special.b.exp_need_qs = false; rcu_report_exp_rdp(rdp->rsp, rdp, true); } else { WARN_ON_ONCE(t->rcu_read_unlock_special.b.exp_need_qs); } }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney40799.51%1292.31%
Boqun Feng20.49%17.69%
Total409100.00%13100.00%

/* * Record a preemptible-RCU quiescent state for the specified CPU. Note * that this just means that the task currently running on the CPU is * not in a quiescent state. There might be any number of tasks blocked * while in an RCU read-side critical section. * * As with the other rcu_*_qs() functions, callers to this function * must disable preemption. */
static void rcu_preempt_qs(void) { RCU_LOCKDEP_WARN(preemptible(), "rcu_preempt_qs() invoked with preemption enabled!!!\n"); if (__this_cpu_read(rcu_data_p->cpu_no_qs.s)) { trace_rcu_grace_period(TPS("rcu_preempt"), __this_cpu_read(rcu_data_p->gpnum), TPS("cpuqs")); __this_cpu_write(rcu_data_p->cpu_no_qs.b.norm, false); barrier(); /* Coordinate with rcu_preempt_check_callbacks(). */ current->rcu_read_unlock_special.b.need_qs = false; } }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney7092.11%1191.67%
Steven Rostedt67.89%18.33%
Total76100.00%12100.00%

/* * We have entered the scheduler, and the current task might soon be * context-switched away from. If this task is in an RCU read-side * critical section, we will no longer be able to rely on the CPU to * record that fact, so we enqueue the task on the blkd_tasks list. * The task will dequeue itself when it exits the outermost enclosing * RCU read-side critical section. Therefore, the current grace period * cannot be permitted to complete until the blkd_tasks list entries * predating the current grace period drain, in other words, until * rnp->gp_tasks becomes NULL. * * Caller must disable interrupts. */
static void rcu_preempt_note_context_switch(bool preempt) { struct task_struct *t = current; struct rcu_data *rdp; struct rcu_node *rnp; lockdep_assert_irqs_disabled(); WARN_ON_ONCE(!preempt && t->rcu_read_lock_nesting > 0); if (t->rcu_read_lock_nesting > 0 && !t->rcu_read_unlock_special.b.blocked) { /* Possibly blocking in an RCU read-side critical section. */ rdp = this_cpu_ptr(rcu_state_p->rda); rnp = rdp->mynode; raw_spin_lock_rcu_node(rnp); t->rcu_read_unlock_special.b.blocked = true; t->rcu_blocked_node = rnp; /* * Verify the CPU's sanity, trace the preemption, and * then queue the task as required based on the states * of any ongoing and expedited grace periods. */ WARN_ON_ONCE((rdp->grpmask & rcu_rnp_online_cpus(rnp)) == 0); WARN_ON_ONCE(!list_empty(&t->rcu_node_entry)); trace_rcu_preempt_task(rdp->rsp->name, t->pid, (rnp->qsmask & rdp->grpmask) ? rnp->gpnum : rnp->gpnum + 1); rcu_preempt_ctxt_queue(rnp, rdp); } else if (t->rcu_read_lock_nesting < 0 && t->rcu_read_unlock_special.s) { /* * Complete exit from RCU read-side critical section on * behalf of preempted instance of __rcu_read_unlock(). */ rcu_read_unlock_special(t); } /* * Either we were not in an RCU read-side critical section to * begin with, or we have now recorded that critical section * globally. Either way, we can now note a quiescent state * for this CPU. Again, if we were in an RCU read-side critical * section, and if that critical section was blocking the current * grace period, then the fact that the task has been enqueued * means that we continue to block the current grace period. */ rcu_preempt_qs(); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney19098.45%1890.00%
Lai Jiangshan21.04%15.00%
Frédéric Weisbecker10.52%15.00%
Total193100.00%20100.00%

/* * Check for preempted RCU readers blocking the current grace period * for the specified rcu_node structure. If the caller needs a reliable * answer, it must hold the rcu_node's ->lock. */
static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp) { return rnp->gp_tasks != NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney18100.00%3100.00%
Total18100.00%3100.00%

/* * Advance a ->blkd_tasks-list pointer to the next entry, instead * returning NULL if at the end of the list. */
static struct list_head *rcu_next_node_entry(struct task_struct *t, struct rcu_node *rnp) { struct list_head *np; np = t->rcu_node_entry.next; if (np == &rnp->blkd_tasks) np = NULL; return np; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney47100.00%1100.00%
Total47100.00%1100.00%

/* * Return true if the specified rcu_node structure has tasks that were * preempted within an RCU read-side critical section. */
static bool rcu_preempt_has_tasks(struct rcu_node *rnp) { return !list_empty(&rnp->blkd_tasks); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney21100.00%1100.00%
Total21100.00%1100.00%

/* * Handle special cases during rcu_read_unlock(), such as needing to * notify RCU core processing or task having blocked during the RCU * read-side critical section. */
void rcu_read_unlock_special(struct task_struct *t) { bool empty_exp; bool empty_norm; bool empty_exp_now; unsigned long flags; struct list_head *np; bool drop_boost_mutex = false; struct rcu_data *rdp; struct rcu_node *rnp; union rcu_special special; /* NMI handlers cannot block and cannot safely manipulate state. */ if (in_nmi()) return; local_irq_save(flags); /* * If RCU core is waiting for this CPU to exit its critical section, * report the fact that it has exited. Because irqs are disabled, * t->rcu_read_unlock_special cannot change. */ special = t->rcu_read_unlock_special; if (special.b.need_qs) { rcu_preempt_qs(); t->rcu_read_unlock_special.b.need_qs = false; if (!t->rcu_read_unlock_special.s) { local_irq_restore(flags); return; } } /* * Respond to a request for an expedited grace period, but only if * we were not preempted, meaning that we were running on the same * CPU throughout. If we were preempted, the exp_need_qs flag * would have been cleared at the time of the first preemption, * and the quiescent state would be reported when we were dequeued. */ if (special.b.exp_need_qs) { WARN_ON_ONCE(special.b.blocked); t->rcu_read_unlock_special.b.exp_need_qs = false; rdp = this_cpu_ptr(rcu_state_p->rda); rcu_report_exp_rdp(rcu_state_p, rdp, true); if (!t->rcu_read_unlock_special.s) { local_irq_restore(flags); return; } } /* Hardware IRQ handlers cannot block, complain if they get here. */ if (in_irq() || in_serving_softirq()) { lockdep_rcu_suspicious(__FILE__, __LINE__, "rcu_read_unlock() from irq or softirq with blocking in critical section!!!\n"); pr_alert("->rcu_read_unlock_special: %#x (b: %d, enq: %d nq: %d)\n", t->rcu_read_unlock_special.s, t->rcu_read_unlock_special.b.blocked, t->rcu_read_unlock_special.b.exp_need_qs, t->rcu_read_unlock_special.b.need_qs); local_irq_restore(flags); return; } /* Clean up if blocked during RCU read-side critical section. */ if (special.b.blocked) { t->rcu_read_unlock_special.b.blocked = false; /* * Remove this task from the list it blocked on. The task * now remains queued on the rcu_node corresponding to the * CPU it first blocked on, so there is no longer any need * to loop. Retain a WARN_ON_ONCE() out of sheer paranoia. */ rnp = t->rcu_blocked_node; raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */ WARN_ON_ONCE(rnp != t->rcu_blocked_node); WARN_ON_ONCE(rnp->level != rcu_num_lvls - 1); empty_norm = !rcu_preempt_blocked_readers_cgp(rnp); empty_exp = sync_rcu_preempt_exp_done(rnp); smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ np = rcu_next_node_entry(t, rnp); list_del_init(&t->rcu_node_entry); t->rcu_blocked_node = NULL; trace_rcu_unlock_preempted_task(TPS("rcu_preempt"), rnp->gpnum, t->pid); if (&t->rcu_node_entry == rnp->gp_tasks) rnp->gp_tasks = np; if (&t->rcu_node_entry == rnp->exp_tasks) rnp->exp_tasks = np; if (IS_ENABLED(CONFIG_RCU_BOOST)) { /* Snapshot ->boost_mtx ownership w/rnp->lock held. */ drop_boost_mutex = rt_mutex_owner(&rnp->boost_mtx) == t; if (&t->rcu_node_entry == rnp->boost_tasks) rnp->boost_tasks = np; } /* * If this was the last task on the current list, and if * we aren't waiting on any CPUs, report the quiescent state. * Note that rcu_report_unblock_qs_rnp() releases rnp->lock, * so we must take a snapshot of the expedited state. */ empty_exp_now = sync_rcu_preempt_exp_done(rnp); if (!empty_norm && !rcu_preempt_blocked_readers_cgp(rnp)) { trace_rcu_quiescent_state_report(TPS("preempt_rcu"), rnp->gpnum, 0, rnp->qsmask, rnp->level, rnp->grplo, rnp->grphi, !!rnp->gp_tasks); rcu_report_unblock_qs_rnp(rcu_state_p, rnp, flags); } else { raw_spin_unlock_irqrestore_rcu_node(rnp, flags); } /* Unboost if we were boosted. */ if (IS_ENABLED(CONFIG_RCU_BOOST) && drop_boost_mutex) rt_mutex_futex_unlock(&rnp->boost_mtx); /* * If this was the last task on the expedited lists, * then we need to report up the rcu_node hierarchy. */ if (!empty_exp && empty_exp_now) rcu_report_exp_rnp(rcu_state_p, rnp, true); } else { local_irq_restore(flags); } }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney49492.16%2882.35%
Lai Jiangshan295.41%12.94%
Steven Rostedt61.12%12.94%
Peter Zijlstra40.75%25.88%
Thomas Gleixner20.37%12.94%
Boqun Feng10.19%12.94%
Total536100.00%34100.00%

/* * Dump detailed information for all tasks blocking the current RCU * grace period on the specified rcu_node structure. */
static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp) { unsigned long flags; struct task_struct *t; raw_spin_lock_irqsave_rcu_node(rnp, flags); if (!rcu_preempt_blocked_readers_cgp(rnp)) { raw_spin_unlock_irqrestore_rcu_node(rnp, flags); return; } t = list_entry(rnp->gp_tasks->prev, struct task_struct, rcu_node_entry); list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) sched_show_task(t); raw_spin_unlock_irqrestore_rcu_node(rnp, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney7795.06%571.43%
Boqun Feng22.47%114.29%
Patrick Daly22.47%114.29%
Total81100.00%7100.00%

/* * Dump detailed information for all tasks blocking the current RCU * grace period. */
static void rcu_print_detail_task_stall(struct rcu_state *rsp) { struct rcu_node *rnp = rcu_get_root(rsp); rcu_print_detail_task_stall_rnp(rnp); rcu_for_each_leaf_node(rsp, rnp) rcu_print_detail_task_stall_rnp(rnp); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney37100.00%1100.00%
Total37100.00%1100.00%


static void rcu_print_task_stall_begin(struct rcu_node *rnp) { pr_err("\tTasks blocked on level-%d rcu_node (CPUs %d-%d):", rnp->level, rnp->grplo, rnp->grphi); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney28100.00%2100.00%
Total28100.00%2100.00%


static void rcu_print_task_stall_end(void) { pr_cont("\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney13100.00%2100.00%
Total13100.00%2100.00%

/* * Scan the current list of tasks blocked within RCU read-side critical * sections, printing out the tid of each. */
static int rcu_print_task_stall(struct rcu_node *rnp) { struct task_struct *t; int ndetected = 0; if (!rcu_preempt_blocked_readers_cgp(rnp)) return 0; rcu_print_task_stall_begin(rnp); t = list_entry(rnp->gp_tasks->prev, struct task_struct, rcu_node_entry); list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) { pr_cont(" P%d", t->pid); ndetected++; } rcu_print_task_stall_end(); return ndetected; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney7997.53%685.71%
Patrick Daly22.47%114.29%
Total81100.00%7100.00%

/* * Scan the current list of tasks blocked within RCU read-side critical * sections, printing out the tid of each that is blocking the current * expedited grace period. */
static int rcu_print_task_exp_stall(struct rcu_node *rnp) { struct task_struct *t; int ndetected = 0; if (!rnp->exp_tasks) return 0; t = list_entry(rnp->exp_tasks->prev, struct task_struct, rcu_node_entry); list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) { pr_cont(" P%d", t->pid); ndetected++; } return ndetected; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney72100.00%1100.00%
Total72100.00%1100.00%

/* * Check that the list of blocked tasks for the newly completed grace * period is in fact empty. It is a serious bug to complete a grace * period that still has RCU readers blocked! This function must be * invoked -before- updating this rnp's ->gpnum, and the rnp's ->lock * must be held by the caller. * * Also, if there are blocked tasks on the list, they automatically * block the newly created grace period, so set up ->gp_tasks accordingly. */
static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) { struct task_struct *t; RCU_LOCKDEP_WARN(preemptible(), "rcu_preempt_check_blocked_tasks() invoked with preemption enabled!!!\n"); WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp)); if (rcu_preempt_has_tasks(rnp)) { rnp->gp_tasks = rnp->blkd_tasks.next; t = container_of(rnp->gp_tasks, struct task_struct, rcu_node_entry); trace_rcu_unlock_preempted_task(TPS("rcu_preempt-GPS"), rnp->gpnum, t->pid); } WARN_ON_ONCE(rnp->qsmask); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney88100.00%7100.00%
Total88100.00%7100.00%

/* * Check for a quiescent state from the current CPU. When a task blocks, * the task is recorded in the corresponding CPU's rcu_node structure, * which is checked elsewhere. * * Caller must disable hard irqs. */
static void rcu_preempt_check_callbacks(void) { struct task_struct *t = current; if (t->rcu_read_lock_nesting == 0) { rcu_preempt_qs(); return; } if (t->rcu_read_lock_nesting > 0 && __this_cpu_read(rcu_data_p->core_needs_qs) && __this_cpu_read(rcu_data_p->cpu_no_qs.b.norm)) t->rcu_read_unlock_special.b.need_qs = true; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney65100.00%15100.00%
Total65100.00%15100.00%

#ifdef CONFIG_RCU_BOOST
static void rcu_preempt_do_callbacks(void) { rcu_do_batch(rcu_state_p, this_cpu_ptr(rcu_data_p)); }

Contributors

PersonTokensPropCommitsCommitProp
David Shaohua Li1583.33%125.00%
Paul E. McKenney211.11%250.00%
Christoph Lameter15.56%125.00%
Total18100.00%4100.00%

#endif /* #ifdef CONFIG_RCU_BOOST */ /** * call_rcu() - Queue an RCU callback for invocation after a grace period. * @head: structure to be used for queueing the RCU updates. * @func: actual callback function to be invoked after the grace period * * The callback function will be invoked some time after a full grace * period elapses, in other words after all pre-existing RCU read-side * critical sections have completed. However, the callback function * might well execute concurrently with RCU read-side critical sections * that started after call_rcu() was invoked. RCU read-side critical * sections are delimited by rcu_read_lock() and rcu_read_unlock(), * and may be nested. * * Note that all CPUs must agree that the grace period extended beyond * all pre-existing RCU read-side critical section. On systems with more * than one CPU, this means that when "func()" is invoked, each CPU is * guaranteed to have executed a full memory barrier since the end of its * last RCU read-side critical section whose beginning preceded the call * to call_rcu(). It also means that each CPU executing an RCU read-side * critical section that continues beyond the start of "func()" must have * executed a memory barrier after the call_rcu() but before the beginning * of that RCU read-side critical section. Note that these guarantees * include CPUs that are offline, idle, or executing in user mode, as * well as CPUs that are executing in the kernel. * * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the * resulting RCU callback function "func()", then both CPU A and CPU B are * guaranteed to execute a full memory barrier during the time interval * between the call to call_rcu() and the invocation of "func()" -- even * if CPU A and CPU B are the same CPU (but again only if the system has * more than one CPU). */
void call_rcu(struct rcu_head *head, rcu_callback_t func) { __call_rcu(head, func, rcu_state_p, -1, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney2696.30%480.00%
Boqun Feng13.70%120.00%
Total27100.00%5100.00%

EXPORT_SYMBOL_GPL(call_rcu); /** * synchronize_rcu - wait until a grace period has elapsed. * * Control will return to the caller some time after a full grace * period has elapsed, in other words after all currently executing RCU * read-side critical sections have completed. Note, however, that * upon return from synchronize_rcu(), the caller might well be executing * concurrently with new RCU read-side critical sections that began while * synchronize_rcu() was waiting. RCU read-side critical sections are * delimited by rcu_read_lock() and rcu_read_unlock(), and may be nested. * * See the description of synchronize_sched() for more detailed * information on memory-ordering guarantees. However, please note * that -only- the memory-ordering guarantees apply. For example, * synchronize_rcu() is -not- guaranteed to wait on things like code * protected by preempt_disable(), instead, synchronize_rcu() is -only- * guaranteed to wait on RCU read-side critical sections, that is, sections * of code protected by rcu_read_lock(). */
void synchronize_rcu(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() in RCU read-side critical section"); if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE) return; if (rcu_gp_is_expedited()) synchronize_rcu_expedited(); else wait_rcu_gp(call_rcu); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney4792.16%1083.33%
Antti P. Miettinen23.92%18.33%
Thomas Gleixner23.92%18.33%
Total51100.00%12100.00%

EXPORT_SYMBOL_GPL(synchronize_rcu); /** * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete. * * Note that this primitive does not necessarily wait for an RCU grace period * to complete. For example, if there are no RCU callbacks queued anywhere * in the system, then rcu_barrier() is within its rights to return * immediately, without waiting for anything, much less an RCU grace period. */
void rcu_barrier(void) { _rcu_barrier(rcu_state_p); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney12100.00%2100.00%
Total12100.00%2100.00%

EXPORT_SYMBOL_GPL(rcu_barrier); /* * Initialize preemptible RCU's state structures. */
static void __init __rcu_init_preempt(void) { rcu_init_one(rcu_state_p); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney1392.86%266.67%
Lai Jiangshan17.14%133.33%
Total14100.00%3100.00%

/* * Check for a task exiting while in a preemptible-RCU read-side * critical section, clean up if so. No need to issue warnings, * as debug_check_no_locks_held() already does this if lockdep * is enabled. */
void exit_rcu(void) { struct task_struct *t = current; if (likely(list_empty(&current->rcu_node_entry))) return; t->rcu_read_lock_nesting = 1; barrier(); t->rcu_read_unlock_special.b.blocked = true; __rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney50100.00%2100.00%
Total50100.00%2100.00%

#else /* #ifdef CONFIG_PREEMPT_RCU */ static struct rcu_state *const rcu_state_p = &rcu_sched_state; /* * Tell them what RCU they are running. */
static void __init rcu_bootup_announce(void) { pr_info("Hierarchical RCU implementation.\n"); rcu_bootup_announce_oddness(); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney17100.00%4100.00%
Total17100.00%4100.00%

/* * Because preemptible RCU does not exist, we never have to check for * CPUs being in quiescent states. */
static void rcu_preempt_note_context_switch(bool preempt) { }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney8100.00%2100.00%
Total8100.00%2100.00%

/* * Because preemptible RCU does not exist, there are never any preempted * RCU readers. */
static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney14100.00%2100.00%
Total14100.00%2100.00%

/* * Because there is no preemptible RCU, there can be no readers blocked. */
static bool rcu_preempt_has_tasks(struct rcu_node *rnp) { return false; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney1392.86%266.67%
Pranith Kumar17.14%133.33%
Total14100.00%3100.00%

/* * Because preemptible RCU does not exist, we never have to check for * tasks blocked within RCU read-side critical sections. */
static void rcu_print_detail_task_stall(struct rcu_state *rsp) { }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney10100.00%1100.00%
Total10100.00%1100.00%

/* * Because preemptible RCU does not exist, we never have to check for * tasks blocked within RCU read-side critical sections. */
static int rcu_print_task_stall(struct rcu_node *rnp) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney14100.00%2100.00%
Total14100.00%2100.00%

/* * Because preemptible RCU does not exist, we never have to check for * tasks blocked within RCU read-side critical sections that are * blocking the current expedited grace period. */
static int rcu_print_task_exp_stall(struct rcu_node *rnp) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney14100.00%3100.00%
Total14100.00%3100.00%

/* * Because there is no preemptible RCU, there can be no readers blocked, * so there is no need to check for blocked tasks. So check only for * bogus qsmask values. */
static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) { WARN_ON_ONCE(rnp->qsmask); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney18100.00%2100.00%
Total18100.00%2100.00%

/* * Because preemptible RCU does not exist, it never has any callbacks * to check. */
static void rcu_preempt_check_callbacks(void) { }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney7100.00%3100.00%
Total7100.00%3100.00%

/* * Because preemptible RCU does not exist, rcu_barrier() is just * another name for rcu_barrier_sched(). */
void rcu_barrier(void) { rcu_barrier_sched(); }

Contributors

PersonTokensPropCommitsCommitProp
Paul E. McKenney10100.00%1100.00%
Total10100.00%1100.00%

EXPORT_SYMBOL_GPL(rcu_barrier); /* * Because preemptible RCU does not exist, it need not be initialized. */