📄 stop_machine.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, ¶m)) 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 + -