1. CPU状态
在Linux内核include/linux/notifier.h文件中,定义了几种CPU状态,如下所示:
#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */
#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */
#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */
#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */
#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */
#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */
#define CPU_DYING 0x0008 /* CPU (unsigned)v not running any task,
* not handling interrupts, soon dead.
* Called on the dying cpu, interrupts
* are already disabled. Must not
* sleep, must not fail */
#define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug lock is dropped */
#define CPU_STARTING 0x000A /* CPU (unsigned)v soon running.
* Called on the new cpu, just before
* enabling interrupts. Must not sleep,
* must not fail */
2. 状态变化通知链
为了让内核中其他模块能觉察到CPU状态的变化,在内核中定义了一个全局链表cpu_chain。需要觉察CPU状态变化的模块,会调用函数register_cpu_notifier,此函数会将模块提供的struct notifier_block结构体变量加入到全局链表cpu_chain中。
具体代码如下所示:
在kernel/cpu.c文件中,定义了全局链表cpu_chain。如下所示:
static RAW_NOTIFIER_HEAD(cpu_chain);
函数register_cpu_notifier实现如下所示:
int __ref register_cpu_notifier(struct notifier_block *nb)
{
int ret;
……;
ret = raw_notifier_chain_register(&cpu_chain, nb);
……;
return ret;
}
在内核其他模块kernel/watchdog.c文件中对函数register_cpu_notifier的调用如下所示:
static int __cpuinit
cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
if (watchdog_prepare_cpu(hotcpu))
return NOTIFY_BAD;
break;
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
if (watchdog_enable(hotcpu))
return NOTIFY_BAD;
break;
……
}
return NOTIFY_OK;
}
static struct notifier_block __cpuinitdata cpu_nfb = {
.notifier_call = cpu_callback
};
static int __init spawn_watchdog_task(void)
{
……
register_cpu_notifier(&cpu_nfb);
……
return 0;
}
early_initcall(spawn_watchdog_task);
Linux内核中相关模块为了觉察CPU状态变化注册了相关函数,那么CPU状态变化又是如何通知到这些模块的呢?在kernel/cpu.c文件中,定义了两个函数cpu_notify和__cpu_notify,它们会通过调用其他功能函数来遍历全局链表cpu_chain,遍历过程中会调用其他模块注册的结构体变量notifier_block中的notifier_call函数。
3. CPU状态变化
通过在内核文件中查找cpu_notify函数和此函数调用的__cpu_notify函数,可以得到CPU状态变化的代码段,如下所示:
在kernel/cpu.c文件中,_cpu_up函数如下所示:
static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
{
……
ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
……
/* Now call notifier in preparation. */
cpu_notify(CPU_ONLINE | mod, hcpu);
out_notify:
if (ret != 0)
__cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
……;
}
_cpu_down函数如下所示:
static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
{
……
err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
if (err) {
__cpu_notify(CPU_DOWN_FAILED | mod, hcpu, nr_calls, NULL);
}
……
/* CPU is completely dead: tell everyone. Too late to complain. */
cpu_notify_nofail(CPU_DEAD | mod, hcpu);
out_release:
if (!err)
cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
return err;
}
notify_cpu_starting函数如下所示:
void __cpuinit notify_cpu_starting(unsigned int cpu)
{
unsigned long val = CPU_STARTING;
cpu_notify(val, (void *)(long)cpu);
}