异想天开

What's the true meaning of light, Could you tell me why

linux源码阅读-dumpstack

日期:2015-07-14 22:28:43
  
最后更新日期:2015-07-14 22:59:19
在看sample/kprobe.c时,钩子函数注释中说可以调用dumpstack打印堆栈。看到这个函数是这样的:
[code lang="cpp"]
#ifdef CONFIG_SMP
static atomic_t dump_lock = ATOMIC_INIT(-1);

asmlinkage void dump_stack(void)
{
int was_locked;
int old;
int cpu;

/*
* Permit this cpu to perform nested stack dumps while serialising
* against other CPUs
*/
preempt_disable();

retry:
cpu = smp_processor_id();
old = atomic_cmpxchg(&dump_lock, -1, cpu);
if (old == -1) {
was_locked = 0;
} else if (old == cpu) {
was_locked = 1;
} else {
cpu_relax();
goto retry;
}

__dump_stack();

if (!was_locked)
atomic_set(&dump_lock, -1);

preempt_enable();
}
#else
asmlinkage void dump_stack(void)
{
__dump_stack();
}
#endif
EXPORT_SYMBOL(dump_stack);
[/code]
该段代码考虑是否为SMP多核的情况,单核的情况直接__dump_stack()打印。那么多核的编码就成上面那个样子了。
1.首先调用preempt_disable(),这里的实现会利用到一个内存屏障。
[code lang="cpp"]
#define barrier() __asm__ __volatile__("": : :"memory")
[/code]
内存屏障主要是阻止cpu乱序执行某些指令。
一个例子:
[code lang="cpp"]
Processor #1:
x = f = 0
loop:
load the value in location f, if it is 0 goto loop
print the value in location x

Processor #2:
store the value 42 into location x
store the value 1 into location f
[/code]
如果CPU按照上诉代码书写方式执行代码,那么结果应该是打印42。但是对于cpu 2而已,两个赋值语句就有可能赋值f发生在赋值x之前。从而打印0。加上内存屏障则可以避免这种情况,显示地告诉编译器和cpu让barrier()后代码执行在后。

2.后面通过smp_processor_id()获得该核的id,类似原子性的操作(cmp and set技术),不过这里是cmp and exchange,否则返回旧值。若old_cpu为-1,那么atomic_cmpxchg会原子性的赋值。若old_cpu为当前cpu,那么状态已经锁定过,最后,若old_cpu不等于当前cpu,则一直忙等待,直到获得获得锁,这就是自旋锁的机制。
忙等待的实现,先调用cpu_relax,那么看一下cpu_relax:
[code lang="cpp"]

/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
static inline void rep_nop(void)
{
asm volatile("rep; nop" ::: "memory");
}

static inline void cpu_relax(void)
{
rep_nop();
}

[/code]
1.volatitle的作用也是阻止编译器优化代码,和c语言一样。
2.注释中说到rep;nop等效于pause指令是对的,为什么这样,搜索intel指令手册。同时后面的损坏部分memory,也有内存屏障的功能,防止下面的语句出现到上面执行。
这个dumpstack主要是在多核的情况防止竞争,安全打印stack信息。