1.spinlock原理
为了解决这个spinlock的不公平问题,linux 2.6.25内核以后,spinlock采用了一种"FIFO ticket-based"算法的spinlock机制,可以很好的实现先来先抢占的思想。具体的做法如下:
(1)、spinlock的核心字段有owner和next,在初始时,owner=next=0
(2)、当第一个进程抢占spinlock时,会在进程函数本地保存下next的值,也就是next=0,并将spinlock的next字段加1;
(3)、当获取spinlock的进程的本地next和spinlock的owner相等时,该进程就获取到spinlock;
(4)、由于第一个进程本地的next=0,并且spinlock的owner为0,所以第一个CPU获取到spinlock;
(5)、接着当第二个进程抢占spinlock,此时spinlock的next值为1,保存到本地,然后将spinlock的next字段加1。而spinlock的owner字段依然为0,第二个进程的本地next 不等于spinlock的owner,所以一直自旋等待spinlock;
(6)、第三个进程抢占spinlock,得到本地next值为2,然后将spinlock的next字段加1。此时spinlock的owner字段还是为0,所以第三个进程自旋等待。
(7)、当第一个进程处理完临界区以后,就释放spinlock,执行的操作是将spinlock的owner字段加1;
(8)、由于第二个进程和第三个进程都还在等待spinlock,他们会不停第获取spinlock的owner字段,并和自己本地的next值进行比较。当第二个进程发现自己的next值和spinlock的owner字段相等时(此时next == owner == 2),第二个进程就获取到spinlock。第三个进程的本地next值是3,和spinlock的owner字段不相等,所以继续等待;
(9)、只有在第二个进程释放了spinlock,就会将spinlock的owner字段加1,第三个进程才有机会获取spinlock。
crash | ||
whatis | 因为mm_struct的mmap_sem成员的offset就是104(0x68), 用whatis命令可以查看结构体的声明,如 whatis -o mm_struct | |
mach | crash> mach | grep SIZE MEMORY SIZE: 1 GB PAGE SIZE: 4096 KERNEL STACK SIZE: 16384 IRQ STACK SIZE: 16384 OVERFLOW STACK SIZE: 4096 | |
task -R stack | PID: 128 TASK: ffff0000034f9b80 CPU: 1 COMMAND: "insmod" stack = 0xffff800012b20000, | |
set | set 128 进程128 上下文 | |
bt -sS 0x11 | 给一个错误地址,会打印出进程128的实际栈地址 | |
bt -T | 将内核栈的内容都打印出来 | |
bt -f/-p | (-p) 只打印panic的内核栈,-f 列出堆栈中的所有数据 | |
bt -lf | (-l)显示每层栈的源码和所在的行数 | |
rd | 打印指针范围的栈内容 rd ffffff8990 -e fffff9ffff > mm.txt | |
task <pid> | 打印进程的task_struct 内容 | |
dis <sym|addr> | 参数可以使地址、符号(函数名、变量名),对其反汇编得到该地址 对应的汇编源码 | |
mod -s <module> | 加载指定安装模块的符号调试信息 | |
mod -d xxxmodule | 删除指定模块的符号表和调试信息 | |
例如 insmod modules_list.ko后,dis 模块中的函数,发现没有反汇编 出源码 要先加载符号表 mod -s module_list.ko,后 dis <function> | ||
vm [pid] | 进程虚拟地址空间 | |
help -m | 查看每个cpu的中断栈 | |
irq_stack_size: 16384 irq_stacks[0]: ffff800010000000 irq_stacks[1]: ffff800010008000 irq_stacks[2]: ffff800012688000 irq_stacks[3]: ffff800012690000 | ||
普通的全局变量 | 普通的全局变量的值很好查看,直接p后面接函数名即可 >p jiffies_64 | |
percup全局变量 | >struct rq.clock,nr_running,cfs.h_nr_running runqueues:0,2,6 冒号后指定 CPU | |
局部变量 | ATPCS规则可知:函数调用时传递的参数,当参数数量小于等于8个时, 使用x0~x7传递,大于8个时,多余的参数使用栈传递; 函数返回时返回值保存在x0中 | |
下面命令对父函数cpu_stopper_thread函数进行反汇编, 其中"/s"参数表示显示汇编在C文件中的行数 disassemble /s cpu_stopper_thread | ||
哪些线程正在访问/访问过 指定的变量/内存/锁 | 哪些线程正在访问/访问过指定的变量 再介绍最后一个实用技巧,有时候我们在分析dump的时候经常会有这样的需求: 已经知道某一把锁在内存中的地址,我们想知道有哪些线程在等这把锁; 已经知道某个全局变量的地址或名称,我们想知道有哪些任务正在访问这个全局变量; 已经知道某个函数名称,我们想知道有哪些任务的调用栈中会调用到这个函数; 这时候我们就可以使用下面命令格式,来对系统中所有的任务的调用栈进行搜索了,其中-t是对所有的任务进行搜索,不区分任务的状态。而-T则表示只对系统中正在running的任务的调用栈进行搜索 search -t/T <变量名|变量地址|函数名|函数地址|内存地址> |