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

📄 stop_machine.c

📁 linux 2.6.19 kernel source code before patching
💻 C
字号:
/* Copyright 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/semaphore.h>#include <asm/uaccess.h>/* Since we effect priority and affinity (both of which are visible * to, and settable by outside processes) we do indirection via a * kthread. *//* Thread to stop each CPU in user context. */enum stopmachine_state {	STOPMACHINE_WAIT,	STOPMACHINE_PREPARE,	STOPMACHINE_DISABLE_IRQ,	STOPMACHINE_EXIT,};static enum stopmachine_state stopmachine_state;static unsigned int stopmachine_num_threads;static atomic_t stopmachine_thread_ack;static DECLARE_MUTEX(stopmachine_mutex);static int stopmachine(void *cpu){	int irqs_disabled = 0;	int prepared = 0;	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));	/* Ack: we are alive */	smp_mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */	atomic_inc(&stopmachine_thread_ack);	/* Simple state machine */	while (stopmachine_state != STOPMACHINE_EXIT) {		if (stopmachine_state == STOPMACHINE_DISABLE_IRQ 		    && !irqs_disabled) {			local_irq_disable();			hard_irq_disable();			irqs_disabled = 1;			/* Ack: irqs disabled. */			smp_mb(); /* Must read state first. */			atomic_inc(&stopmachine_thread_ack);		} else if (stopmachine_state == STOPMACHINE_PREPARE			   && !prepared) {			/* Everyone is in place, hold CPU. */			preempt_disable();			prepared = 1;			smp_mb(); /* Must read state first. */			atomic_inc(&stopmachine_thread_ack);		}		/* Yield in first stage: migration threads need to		 * help our sisters onto their CPUs. */		if (!prepared && !irqs_disabled)			yield();		else			cpu_relax();	}	/* Ack: we are exiting. */	smp_mb(); /* Must read state first. */	atomic_inc(&stopmachine_thread_ack);	if (irqs_disabled)		local_irq_enable();	if (prepared)		preempt_enable();	return 0;}/* Change the thread state */static void stopmachine_set_state(enum stopmachine_state state){	atomic_set(&stopmachine_thread_ack, 0);	smp_wmb();	stopmachine_state = state;	while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads)		cpu_relax();}static int stop_machine(void){	int i, ret = 0;	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };	/* One high-prio thread per cpu.  We'll do this one. */	sched_setscheduler(current, SCHED_FIFO, &param);	atomic_set(&stopmachine_thread_ack, 0);	stopmachine_num_threads = 0;	stopmachine_state = STOPMACHINE_WAIT;	for_each_online_cpu(i) {		if (i == raw_smp_processor_id())			continue;		ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL);		if (ret < 0)			break;		stopmachine_num_threads++;	}	/* Wait for them all to come to life. */	while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads)		yield();	/* If some failed, kill them all. */	if (ret < 0) {		stopmachine_set_state(STOPMACHINE_EXIT);		return ret;	}	/* Now they are all started, make them hold the CPUs, ready. */	preempt_disable();	stopmachine_set_state(STOPMACHINE_PREPARE);	/* Make them disable irqs. */	local_irq_disable();	hard_irq_disable();	stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);	return 0;}static void restart_machine(void){	stopmachine_set_state(STOPMACHINE_EXIT);	local_irq_enable();	preempt_enable_no_resched();}struct stop_machine_data{	int (*fn)(void *);	void *data;	struct completion done;};static int do_stop(void *_smdata){	struct stop_machine_data *smdata = _smdata;	int ret;	ret = stop_machine();	if (ret == 0) {		ret = smdata->fn(smdata->data);		restart_machine();	}	/* We're done: you can kthread_stop us now */	complete(&smdata->done);	/* Wait for kthread_stop */	set_current_state(TASK_INTERRUPTIBLE);	while (!kthread_should_stop()) {		schedule();		set_current_state(TASK_INTERRUPTIBLE);	}	__set_current_state(TASK_RUNNING);	return ret;}struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,				       unsigned int cpu){	struct stop_machine_data smdata;	struct task_struct *p;	smdata.fn = fn;	smdata.data = data;	init_completion(&smdata.done);	down(&stopmachine_mutex);	/* If they don't care which CPU fn runs on, bind to any online one. */	if (cpu == NR_CPUS)		cpu = raw_smp_processor_id();	p = kthread_create(do_stop, &smdata, "kstopmachine");	if (!IS_ERR(p)) {		kthread_bind(p, cpu);		wake_up_process(p);		wait_for_completion(&smdata.done);	}	up(&stopmachine_mutex);	return p;}int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu){	struct task_struct *p;	int ret;	/* No CPUs can come up or down during this. */	lock_cpu_hotplug();	p = __stop_machine_run(fn, data, cpu);	if (!IS_ERR(p))		ret = kthread_stop(p);	else		ret = PTR_ERR(p);	unlock_cpu_hotplug();	return ret;}EXPORT_SYMBOL_GPL(stop_machine_run);

⌨️ 快捷键说明

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