⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stop_machine.c

📁 Kernel code of linux kernel
💻 C
字号:
/* Copyright 2008, 2005 Rusty Russell rusty@rustcorp.com.au IBM Corporation. * GPL v2 and any later version. */#include <linux/cpu.h>#include <linux/err.h>#include <linux/kthread.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/stop_machine.h>#include <linux/syscalls.h>#include <linux/interrupt.h>#include <asm/atomic.h>#include <asm/uaccess.h>/* This controls the threads on each CPU. */enum stopmachine_state {	/* Dummy starting state for thread. */	STOPMACHINE_NONE,	/* Awaiting everyone to be scheduled. */	STOPMACHINE_PREPARE,	/* Disable interrupts. */	STOPMACHINE_DISABLE_IRQ,	/* Run the function */	STOPMACHINE_RUN,	/* Exit */	STOPMACHINE_EXIT,};static enum stopmachine_state state;struct stop_machine_data {	int (*fn)(void *);	void *data;	int fnret;};/* Like num_online_cpus(), but hotplug cpu uses us, so we need this. */static unsigned int num_threads;static atomic_t thread_ack;static struct completion finished;static DEFINE_MUTEX(lock);static void set_state(enum stopmachine_state newstate){	/* Reset ack counter. */	atomic_set(&thread_ack, num_threads);	smp_wmb();	state = newstate;}/* Last one to ack a state moves to the next state. */static void ack_state(void){	if (atomic_dec_and_test(&thread_ack)) {		/* If we're the last one to ack the EXIT, we're finished. */		if (state == STOPMACHINE_EXIT)			complete(&finished);		else			set_state(state + 1);	}}/* This is the actual thread which stops the CPU.  It exits by itself rather * than waiting for kthread_stop(), because it's easier for hotplug CPU. */static int stop_cpu(struct stop_machine_data *smdata){	enum stopmachine_state curstate = STOPMACHINE_NONE;	/* Simple state machine */	do {		/* Chill out and ensure we re-read stopmachine_state. */		cpu_relax();		if (state != curstate) {			curstate = state;			switch (curstate) {			case STOPMACHINE_DISABLE_IRQ:				local_irq_disable();				hard_irq_disable();				break;			case STOPMACHINE_RUN:				/* |= allows error detection if functions on				 * multiple CPUs. */				smdata->fnret |= smdata->fn(smdata->data);				break;			default:				break;			}			ack_state();		}	} while (curstate != STOPMACHINE_EXIT);	local_irq_enable();	do_exit(0);}/* Callback for CPUs which aren't supposed to do anything. */static int chill(void *unused){	return 0;}int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus){	int i, err;	struct stop_machine_data active, idle;	struct task_struct **threads;	active.fn = fn;	active.data = data;	active.fnret = 0;	idle.fn = chill;	idle.data = NULL;	/* This could be too big for stack on large machines. */	threads = kcalloc(NR_CPUS, sizeof(threads[0]), GFP_KERNEL);	if (!threads)		return -ENOMEM;	/* Set up initial state. */	mutex_lock(&lock);	init_completion(&finished);	num_threads = num_online_cpus();	set_state(STOPMACHINE_PREPARE);	for_each_online_cpu(i) {		struct stop_machine_data *smdata = &idle;		struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };		if (!cpus) {			if (i == first_cpu(cpu_online_map))				smdata = &active;		} else {			if (cpu_isset(i, *cpus))				smdata = &active;		}		threads[i] = kthread_create((void *)stop_cpu, smdata, "kstop%u",					    i);		if (IS_ERR(threads[i])) {			err = PTR_ERR(threads[i]);			threads[i] = NULL;			goto kill_threads;		}		/* Place it onto correct cpu. */		kthread_bind(threads[i], i);		/* Make it highest prio. */		if (sched_setscheduler_nocheck(threads[i], SCHED_FIFO, &param))			BUG();	}	/* We've created all the threads.  Wake them all: hold this CPU so one	 * doesn't hit this CPU until we're ready. */	get_cpu();	for_each_online_cpu(i)		wake_up_process(threads[i]);	/* This will release the thread on our CPU. */	put_cpu();	wait_for_completion(&finished);	mutex_unlock(&lock);	kfree(threads);	return active.fnret;kill_threads:	for_each_online_cpu(i)		if (threads[i])			kthread_stop(threads[i]);	mutex_unlock(&lock);	kfree(threads);	return err;}int stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus){	int ret;	/* No CPUs can come up or down during this. */	get_online_cpus();	ret = __stop_machine(fn, data, cpus);	put_online_cpus();	return ret;}EXPORT_SYMBOL_GPL(stop_machine);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -