内核中断程序

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
[huzhifeng@fc15 myirq]$ vi myirq.c
/*
Usage:
make
sudo insmod myirq.ko irq=19 devname=1119
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>

static int irq;
static char* devname;
static struct tasklet_struct mytasklet;

module_param(irq,int,0644);
module_param(devname,charp,0644);

struct myirq
{
int devid;
};
struct myirq mydev={1119};

static void mytasklet_handler(unsigned long data)
{
printk("huzhifeng test:%s(),line %d,tasklet is wroking..\n", __FUNCTION__, __LINE__);
}

static irqreturn_t myirq_handler(int irq,void* dev)
{
struct myirq mydev;
static int count=0;
mydev=*(struct myirq*)dev;
printk("huzhifeng test:%s(),line %d,count=%d,devid=%d\n", __FUNCTION__, __LINE__, count, mydev.devid);
tasklet_init(&mytasklet,mytasklet_handler,0);
tasklet_schedule(&mytasklet);
count++;
return IRQ_HANDLED;
}

static int __init myirq_init()
{
printk("huzhifeng test:%s(),line %d,module init\n", __FUNCTION__, __LINE__);
if(request_irq(irq,myirq_handler,IRQF_SHARED,devname,&mydev)!=0)
{
printk("huzhifeng test:%s(),line %d,%s request IRQ:%d failed..\n", __FUNCTION__, __LINE__, devname, irq);
return -1;
}
printk("huzhifeng test:%s(),line %d,%s rquest IRQ:%d success..\n", __FUNCTION__, __LINE__, devname, irq);
return 0;
}

static void __exit myirq_exit()
{
printk("huzhifeng test:%s(),line %d,module exit\n", __FUNCTION__, __LINE__);
free_irq(irq,&mydev);
printk("huzhifeng test:%s(),line %d,%s free IRQ:%d success..\n", __FUNCTION__, __LINE__, devname, irq);
}

module_init(myirq_init);
module_exit(myirq_exit);
MODULE_LICENSE("GPL");

阅读全文 »

利用内核链表遍历进程

内核模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
[huzhifeng@fc15 klist]$ mkdir process_list
[huzhifeng@fc15 klist]$ cd process_list/
[huzhifeng@fc15 process_list]$ vi process_list.c

1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/list.h>
4 #include <linux/sched.h> /* init_task */
5
6 MODULE_LICENSE("Dual BSD/GPL");
7
8 static int list_process_init(void)
9 {
10 struct task_struct *p = NULL, *task = NULL;
11 struct list_head *pos = NULL;
12 int count = 0;
13
14 printk(KERN_EMERG "%s(),line %d\n", __FUNCTION__, __LINE__);
15 task = &init_task;
16
17 list_for_each(pos, &task->tasks)
18 {
19 p = list_entry(pos, struct task_struct, tasks);
20 count++;
21 printk(KERN_EMERG "pid %d--->%s\n", p->pid, p->comm);
22 }
23
24 printk(KERN_EMERG "the number of process is %d\n", count);
25
26 return 0;
27 }
28
29 static void list_process_exit(void)
30 {
31 printk(KERN_EMERG "%s(),line %d\n", __FUNCTION__, __LINE__);
32 }
33
34 module_init(list_process_init);
35 module_exit(list_process_exit);
阅读全文 »

开发环境

本文是基于Fedora 15(FC15)搭建BOA webserver以及cgi环境
内核版本:

1
2
3
[huzhifeng@fc15 src]$ uname -a
Linux fc15 2.6.38.8-Zhifeng #1 SMP Wed Jun 22 22:19:59 CST 2011 i686 i686 i386 GNU/Linux
[huzhifeng@fc15 src]$

下载boa源码

最新版本是0.94.13

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[huzhifeng@fc15 Downloads]$ wget http://www.boa.org/boa-0.94.13.tar.gz
--2011-06-23 08:44:08-- http://www.boa.org/boa-0.94.13.tar.gz
Resolving www.boa.org... 192.203.178.67
Connecting to www.boa.org|192.203.178.67|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 122066 (119K) [application/x-tar]
Saving to: “boa-0.94.13.tar.gz”

100%[========================================================================================================>] 122,066 76.4K/s in 1.6s

2011-06-23 08:44:11 (76.4 KB/s) - “boa-0.94.13.tar.gz” saved [122066/122066]

[huzhifeng@fc15 Downloads]$ ls boa-0.94.13.tar.gz -l
-rw-rw-r--. 1 huzhifeng huzhifeng 122066 Jul 30 2002 boa-0.94.13.tar.gz

阅读全文 »

开发环境

Fedora 15,内核版本2.6.38.8

1
2
3
[huzhifeng@fc15 ~]$ uname -a
Linux fc15 2.6.38.8-Zhifeng #1 SMP Wed Jun 22 22:19:59 CST 2011 i686 i686 i386 GNU/Linux
[huzhifeng@fc15 ~]$

字符设备驱动程序

hzf-chrdev.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");

#define MAJOR_NUM 222

static int hzf_var = 0;

static ssize_t hzf_read(struct file *file, char __user *buf, size_t count,
loff_t *offset)
{
if(copy_to_user(buf, &hzf_var, sizeof(hzf_var)))
return -EFAULT;

return sizeof(hzf_var);
}

static ssize_t hzf_write(struct file *file, const char __user *buf,
size_t count, loff_t *offset)
{
if(copy_from_user(&hzf_var, buf, sizeof(int)))
return -EFAULT;

return sizeof(int);
}

static struct file_operations hzf_fops =
{
.owner = THIS_MODULE,
.read = hzf_read,
.write = hzf_write
};

static int __init hzf_init(void)
{
int ret = 0;

ret = register_chrdev(MAJOR_NUM, "hzfchar", &hzf_fops);

if(ret)
printk("register hzfchar fail");
else
printk("register success");

return 0;
}

static void __exit hzf_cleanup (void)
{

int ret = 0;

unregister_chrdev(MAJOR_NUM, "hzfchar");

if(ret)
printk("unregister hzfchar fail");
else
printk("unregister success");
}

module_init(hzf_init);
module_exit(hzf_cleanup);

阅读全文 »

printk分析

在内核开发时我们经常会用到printk调试,有时打印信息太多了,可以通过修改/proc/sys/kernel/printk文件内容来控制。

1
2
3
# cat /proc/sys/kernel/printk
7 4 1 7
#

该文件有四个数字值,它们根据日志记录消息的重要性,定义将其发送到何处。关于不同日志级别的更多信息,请查阅syslog(2)联机帮助。上面显示的4个数据分别对应:
控制台日志级别:优先级 高于该值的消息将被打印至控制台
默认的消息日志级别:将用该优先级来打印没有优先级的消息
最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级)
默认的控制台日志级别:控制台日志级别的缺省值
英文原版解释为:

/proc/sys/kernel/printk
The four values in this file are console_loglevel, default_message_loglevel, minimum_console_level and default_console_loglevel. These values influence printk() behavior when printing or logging error messages. See syslog(2) for more info on the different loglevels. Messages with a higher priority than console_loglevel will be printed to the console. Messages without an explicit priority will be printed with priority default_message_level. minimum_console_loglevel is the minimum (highest) value to which console_loglevel can be set. default_console_loglevel is the default value for console_loglevel.

阅读全文 »

示例代码

在内核模块中添加自己的定时器示例
首先,在文件顶部包含相关头文件和添加全局的定时器变量timer_huzhifeng

1
2
#include <linux/timer.h>
static struct timer_list timer_huzhifeng;

其次,在模块初始化的函数里添加定时器

1
2
3
4
5
6
7
8
9
10
static int __init my_timer_init(void)
{
...
timer_huzhifeng.data = (SYS_ULONG)pDev;
timer_huzhifeng.function = timer_huzhifeng_func;
init_timer(&timer_huzhifeng);
timer_huzhifeng.expires = RUN_AT(10*HZ);//10 second: #define RUN_AT(x) (jiffies + (x))
add_timer(&timer_huzhifeng);
...
}

在模块删除的的函数里移除定时器

1
2
3
4
5
6
static void __exit my_timer_exit(void)
{
……
del_timer_sync(&timer_huzhifeng);//or del_timer(&timer_huzhifeng);
……
}

定时器处理函数

1
2
3
4
5
6
7
static SYS_VOID timer_huzhifeng_func(SYS_ULONG data)
{
static int timer_count = 0;
timer_count++;
printk("huzhifengtest func=%s;line=%d;timer_count=%d\n", __FUNCTION__, __LINE__, timer_count);
mod_timer(&timer_huzhifeng, RUN_AT(10*HZ));
}

参考

linux内核定时器的用法

EOF

在Linux下删除SVN目录的方法有很多,以下是我常用的两种
方法一:
find . -type d -name ".svn" | xargs rm -rf 或者 find . -type d -iname ".svn" -exec rm -rf {} \;

方法二:

1
2
3
4
5
6
cat svn_clean.sh
for files in `tree -difa /path/to/your/dir | grep '.svn$'`
do
echo "Cleaning" $files " ... "
rm -rf $files
done

EOF

常用命令

删除一个词用dw
插入新行:o在当前行上,O在当前行下
替换:
:s/vivian/sky/ 替换当前行第一个 vivian 为 sky
:s/vivian/sky/g 替换当前行所有 vivian 为 sky
:n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第一个 vivian 为 sky
:n,$s/vivian/sky/g 替换第 n 行开始到最后一行中每一行所有 vivian 为 sky
(n 为数字,若 n 为 .,表示从当前行开始到最后一行)
:%s/vivian/sky/(等同于 :g/vivian/s//sky/) 替换每一行的第一个 vivian 为 sky
:%s/vivian/sky/g(等同于 :g/vivian/s//sky/g) 替换每一行中所有 vivian 为 sky

显示行号

默认使用vim编辑源代码文件时不显示行号,需要在用户home目录下建一个.vimrc文件,追加一行代码set nu
如果你想对所有用户都这样,那么在/etc/vimrc(CentOS/Fedora系统)或者/etc/vim/vimrc(Debian/Ubuntu系统)文件中加入这一行(需要root权限)。
/etc/vimrc或者/etc/vim/vimrc是所有用户启动vim时都会执行的,每个用户的home目录下的.vimrc是这个用户启动vim时会执行的。
详细步骤如下:

1
2
3
4
5
6
7
8
9
[huzhifeng@srv ~]$ cd ~
[huzhifeng@srv ~]$ pwd
/home/huzhifeng
[huzhifeng@srv ~]$ vim .vimrc
set nu
~
~
".vimrc" [New] 1L, 7C written
[huzhifeng@srv ~]$

或者

1
[huzhifeng@srv ~]$ echo "set nu" >> ~/.vimrc

或者使用vim打开文件后:
显示行号执行:set nu"
取消显示行号执行:set nonu

复制/删除多行

在命令模式下按键5yy表示复制从当前行开始的5行内容,按p键粘贴, 按键5dd表示删除从当前行开始的5行内容

跳转到指定行

gg或者1G跳转到首行,G跳转到末尾行,#G跳转到第#行

TAB键设置

vim tab键默认4空格

1
2
3
4
5
vim ~/.vimrc 
1 set ts=4
2 set sw=4
3 set expandtab
4 set autoindent

按tab键时产生的是4个空格,这种方式具有最好的兼容性。

EOF