kernel/softirq.c

Source file repositories/reference/linux-study-clean/kernel/softirq.c

File Facts

System
Linux kernel
Corpus path
kernel/softirq.c
Extension
.c
Size
29112 bytes
Lines
1202
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct softirq_ctrl {
	local_lock_t	lock;
	int		cnt;
};

static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = {
	.lock	= INIT_LOCAL_LOCK(softirq_ctrl.lock),
};

#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key bh_lock_key;
struct lockdep_map bh_lock_map = {
	.name			= "local_bh",
	.key			= &bh_lock_key,
	.wait_type_outer	= LD_WAIT_FREE,
	.wait_type_inner	= LD_WAIT_CONFIG, /* PREEMPT_RT makes BH preemptible. */
	.lock_type		= LD_LOCK_PERCPU,
};
EXPORT_SYMBOL_GPL(bh_lock_map);
#endif

/**
 * local_bh_blocked() - Check for idle whether BH processing is blocked
 *
 * Returns false if the per CPU softirq::cnt is 0 otherwise true.
 *
 * This is invoked from the idle task to guard against false positive
 * softirq pending warnings, which would happen when the task which holds
 * softirq_ctrl::lock was the only running task on the CPU and blocks on
 * some other lock.
 */
bool local_bh_blocked(void)
{
	return __this_cpu_read(softirq_ctrl.cnt) != 0;
}

void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
{
	unsigned long flags;
	int newcnt;

	WARN_ON_ONCE(in_hardirq());

	lock_map_acquire_read(&bh_lock_map);

	/* First entry of a task into a BH disabled section? */
	if (!current->softirq_disable_cnt) {
		if (preemptible()) {
			if (IS_ENABLED(CONFIG_PREEMPT_RT_NEEDS_BH_LOCK))
				local_lock(&softirq_ctrl.lock);
			else
				migrate_disable();

			/* Required to meet the RCU bottomhalf requirements. */
			rcu_read_lock();
		} else {
			DEBUG_LOCKS_WARN_ON(this_cpu_read(softirq_ctrl.cnt));
		}
	}

	/*
	 * Track the per CPU softirq disabled state. On RT this is per CPU
	 * state to allow preemption of bottom half disabled sections.
	 */
	if (IS_ENABLED(CONFIG_PREEMPT_RT_NEEDS_BH_LOCK)) {
		newcnt = this_cpu_add_return(softirq_ctrl.cnt, cnt);
		/*
		 * Reflect the result in the task state to prevent recursion on the
		 * local lock and to make softirq_count() & al work.
		 */
		current->softirq_disable_cnt = newcnt;

		if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && newcnt == cnt) {
			raw_local_irq_save(flags);
			lockdep_softirqs_off(ip);
			raw_local_irq_restore(flags);
		}
	} else {
		bool sirq_dis = false;

		if (!current->softirq_disable_cnt)
			sirq_dis = true;

		this_cpu_add(softirq_ctrl.cnt, cnt);
		current->softirq_disable_cnt += cnt;
		WARN_ON_ONCE(current->softirq_disable_cnt < 0);

		if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && sirq_dis) {
			raw_local_irq_save(flags);
			lockdep_softirqs_off(ip);

Annotation

Implementation Notes