内核抢占和中断

以前一直不理解什么是内核抢占,现在好像懂了。

本文尝试解释什么是内核可抢占以及可抢占和可中断的区别。

首先被中断不是被抢占,中断和抢占是两个概念。抢占必须涉及进程上下文的切换,而中断是在中断上下文。

所谓可抢占抢的是进程上下文,人人都争取上台。可中断指的是是否可以中断当前CPU而进入我的中断处理函数。

如果内核是不可抢占的(比如说2.4的内核),一旦切进内核态,只要代码不是主动释放CPU它就可以一直占着CPU。例外,虽不可抢占,但若此时发生中断,代码还是要交出CPU,但是中断返回之后,代码又能霸占CPU了,此为可中断但不可抢占。

如果内核是可抢占的(比如2.6或之后的内核),上述情况就不会发生了。内核抢占发生在以下3种情况:

1. 从中断返回内核态时,若此时可抢占,则会强制调用schedule(),尝试抢占,被中断的内核代码不一定能继续霸着CPU。

2.内核变成可抢占状态,此时也会尝试抢占。

3.内核代码主动调用schedule()。

虽然2.6的内核提供内核抢占,但是也提供关闭的手段。是否可抢占是由preemt_count变量控制(per-cpu),有锁这个计数就+1,释放锁就-1.为0才是可抢占。每当释放锁的时候都会检查是否为0,为0则尝试抢占。

 

+++++++++++++++++++分割线++++++++++++++++++++++++++++++++

关于中断

中断分为上下两个部分。是为中断上半部(top half)、下半部(bottom half)。

上半部处理紧要事情。比如:通知硬件“我知道你请求中断了,继续干活去”,然后从设备缓冲区拷贝数据到内存。

下半部处理不那么要紧的任务。比如:网卡上来的数据推进协议栈,然后推给上层应用程序。

当前的内核有三种下半部的实现方式:softirq、tasklet、working queue。

         名称

上下文

特点

概述
Softirq

中断上下文

可中断不可睡眠 速度最快。同一个Softirq可能会同时运行在多个核上,必须非常小心的处理数据同步
Tasklet

中断上下文

可中断不可睡眠 基于Softirq实现,同一类的Tasklet不会被同时运行,编程代价小
Work queue

进程上下文

可中断可睡眠

基于内核线程实现

 

 

每天记一点,进步看的见。

KGDB && Build Ubuntu kernel

关于KGDB:GDB是GUN的调试器,用来调试普通程序。KGDB是用来调试操作系统内核的。当我还在念小学的时候,Linus严辞拒绝KGDB进入主线内核的,理由是:真正懂内核的人不需要工具来调试,人脑就能调代码[1]。可是到了2.6.26时代,却已经欣然接受KGDB,很想知道是谁说服了那个顽固的天才。

下面开始在Ubuntu 10.04下快乐的使用KGDB。

为什么是Ubuntu 10.04?我用过的发行版不多,也就Ubuntu、Archlinux、Redhat、Centos、Fedora、LFS。Ubuntu并不是最好用的,很多地方都不符合我的习惯,但是,因为手边正好有一张Ubuntu的推广光盘,这张质量上乘的推广光盘使我把附近能用的机器都装上了Ubuntu。光盘安装的便利性是各种硬盘安装、网络安装、U盘安装等繁琐手段无法比拟的。于是乎,我被Ubuntu俘虏了。

真要我说Ubuntu最吸引我的地方,大概就是它那个默认的红色配色了,看着很舒服。字体也刚刚好。

Ubuntu 不太适合搞KGDB,因为在Ubuntu上换内核特别麻烦。注意,是特别麻烦。

10.04的内核默认已经打开了KGDB选项,但是因为发行版不提供原始的vmlinux文件,因此需要重做一个(反正已经重编了内核,顺手就换下内核,好处是可以完美match 符号表,自己动手编的vmlinux文件和官方的核不能100%契合)。

官方的wiki上提供了两种编译内核的方式,一种是编Ubuntu kernel一种是编主线kernel

图省事我编的是Ubuntu kernel。

首先拿到内核源码,推荐使用git方式。

Git路径如下:

quantal

git://kernel.ubuntu.com/ubuntu/ubuntu-quantal.git

precise

git://kernel.ubuntu.com/ubuntu/ubuntu-precise.git

oneiric

git://kernel.ubuntu.com/ubuntu/ubuntu-oneiric.git

natty

git://kernel.ubuntu.com/ubuntu/ubuntu-natty.git

lucid

git://kernel.ubuntu.com/ubuntu/ubuntu-lucid.git

hardy

git://kernel.ubuntu.com/ubuntu/ubuntu-hardy.git

10.04 是lucid,所以执行

$git clone git://kernel.ubuntu.com/ubuntu/ubuntu-lucid.git

然后切换至对应的tag上。查看版本

$uname -a

Linux hacklu-desktop 2.6.32-21-generic #32-Ubuntu SMP

所以对应的tag是Ubuntu-2.6.32-21.32。

$git checkout -b my_kernel Ubuntu-2.6.32-21.32

编译选项最好在发行版的基础上修改

$cp /boot/config-2.6.32-21-generic .config

$make oldconfig

在这基础上修改自定义的配置(调试内核,需要把CONFIG_DEBUG_RODATA关闭,代码段的只读属性不去掉,KGDB无法下断点。因为断点是通过把欲断处指令改成INT3来实现)

$make menuconfig

$make-kpkg clean # only needed if you want to do a "clean" build

$cp Ubuntu-kernel-src/debian/control-scripts/{postinst,postrm,preinst,prerm} ~/kernel-package/pkg/image/

$ cp Ubuntu-kernel-src /debian/control-scripts/headers-postinst ~/kernel-package/pkg/headers/

$CONCURRENCY_LEVEL=2  fakeroot make-kpkg --initrd --append-to-version=-hacklu.v1 --overlay-dir=~/kernel-package/  kernel_image kernel_headers

 

解释下, CONCURRENCY_LEVEL=2 相当于平时的make -j2 编译速度加快。

fakeroot 是make-kpkg以为你是root

--append-to-version=-hacklu.v1 后面的字符串会自动加在编译好的内核版本后面

--overlay-dir=~/kernel-package/  make-kpkg 命令需要这个选项指定定制脚本路径,如果没有这一项,编译出来的内核缺少initramfs。

Kernel_image 表示编译image.deb

Kernel_header表示编译header.deb

命令执行完毕会在当前目录的上一级生成两个deb包,分别安装即可

$sudo dpkg -i *.deb

Image.deb会根据控制脚本自动生成initramfs,并更新grub,重启即可切换至新编出的内核。

 

此刻KGDB 和vmlinux都已经准备好了。如果有串口线则可调试实体机器,不然就放在vmware中调试。

Vmware中安装好一台ubuntu10.04的系统做被调试机,然后add device—》serial port—》named pipe

如下,记得要勾上Yield CPU on poll。

如果调试机也是虚拟机,类似添加串口设备,server和client互换。

如果调试机是局域网内一台物理机器,则可以利用命名管道转网络工具[2]把虚拟机中的被调试机器的串口转发到局域网中去。

在被调试机器上执行如下指令

$sudo -s

#echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc   #指定通信串口号

#echo g > /proc/sysrq-trigger  #挂起被调试机器,产生kgdb_breakpoint中断。此时调试端gdb可以连入

在调试机器上执行如下

$gdb vmlinux

$target remote /dev/ttyS0

之后就可以开心的使用GDB调试内核了。

Ps:最好使用Ubuntu自带的gdb来调试,10.04的内核跟7.2以上的GDB不合拍。

 

 

[1] Linus say: Without a debugger, you basically have
to go the next step: understand what the program does. Not just that
particular line. https://lkml.org/lkml/2000/9/6/65
[2] Named Pipe TCP Proxy Utility http://shvechkov.tripod.com/nptp.html