表3.2 通知链和它们传送的事件
|
|
通知链
|
描述
|
Die Notifier Chain (die_chain)
|
通过 register_die_notifier() , my_die_event_handler() 被依附于 die_chain 死亡通知链。为了触发 my_die_event_handler() 的发生,代码中引入了一个冗余的引用,即:
int *q = 0; *q = 1;
当这段代码被执行的时候, my_die_event_handler() 将被调用,你将看到这样的信息:
my_die_event_handler: OOPs! at EIP=f00350e7
死亡事件通知将 die_args 结构体传给被注册的事件处理函数。该参数包括一个指向 regs 结构体的指针(在发生缺陷的时候,用于存放处理器的寄存器)。 my_die_event_handler() 中打印了指令指针寄存器的内容。
|
Netdevice Notifier Chain( netdev_chain)
|
通过 register_netdevice_notifier() , my_dev_event_handler() 被依附于网络设备通知链 netdev_chain 。通过改变网络接口设备(如以太网ethX和回环设备lo )的状态可以产生此事件:
bash> ifconfig eth0 up
它会导致 my_dev_event_handler() 的执行。
net_device 结构体的指针被传给该处理函数作为参数,它包含了网络接口的名字, my_dev_event_handler() 打印出了该信息:
my_dev_event_handler: Val=1, Interface=eth0
Val=1 意味着 NETDEV_UP 事件,其定义在include/linux/notifier.h文件中。
|
User-Defined Notifier Chain
|
清单3.6也实现了一个用户自定义的通知链 my_noti_chain。假定你希望当用户读取proc文件系统中一个特定的文件的时候该事件被产生,可以在相关的procfs读函数中加入如下代码:
blocking_notifier_call_chain(&my_noti_chain, 100, NULL);
当你读取相应的/proc文件时, my_event_handler() 将被调用,如下信息被打印出来:
my_event_handler: Val=100
Val 包含了产生事件的ID,本例中为100。该函数的参数没有被使用。
|
表3.3给出了本章中所使用的主要的数据结构及其源代码路径的总结。表3.4列出了本章中使用的主要内核编程接口及其源代码路径。
数据结构
|
路径
|
描述
|
wait_queue_t
|
include/linux/wait.h
|
内核线程欲等待某事件或系统资源时使用
|
list_head
|
include/linux/list.h
|
用于构造双向链表数据结构的内核结构体
|
hlist_head
|
include/linux/list.h
|
用于实现哈希表的的内核结构体
|
work_struct
|
include/linux/workqueue.h
|
实现工作队列,它是一种在内核中进行延后工作的方式
|
notifier_block
|
include/linux/notifier.h
|
实现通知链,用于将状态变更信息发生给请求此变更的代码段
|
completion
|
include/linux/completion.h
|
用于开始某线程活动并等待它们完成
|
表3.4 内核编程接口总结
内核接口 |
路径
|
描述
|
DECLARE_WAITQUEUE()
|
include/linux/wait.h
|
定义一个等待队列
|
add_wait_queue()
|
kernel/wait.c
|
将一个任务加入一个等待队列。该任务进入睡眠状态,知道它被另一个线程或中断处理函数唤醒。
|
remove_wait_queue()
|
kernel/wait.c
|
从等待队列中删除一个任务。
|
wake_up_interruptible()
|
include/linux/wait.hkernel/sched.c
|
唤醒一个正在等待队列中睡眠的任务,将其返回调度器的运行队列。
|
schedule()
|
kernel/sched.c
|
放弃CPU,让内核的其他部分运行。
|
set_current_state()
|
include/linux/sched.h
|
设置一个进程的运行状态,可以是如下状态中的一种: TASK_RUNNING、 TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPED、 TASK_TRACED、 EXIT_ZOMBIE或 EXIT_DEAD.
|
kernel_thread()
|
arch/your-arch/kernel/process.c
|
创建一个内核线程
|
daemonize()
|
kernel/exit.c
|
激活一个内核线程(未依附于用户资源),并将调用线程的父线程改为kthreadd。
|
allow_signal()
|
kernel/exit.c
|
使能某指定信号的发起
|
signal_pending()
|
include/linux/sched.h
|
检查是否有信号已经被传输。在内核中没有信号处理函数,因此,你不得不显示地检查信号的发起
|
call_usermodehelper()
|
include/linux/kmod.hkernel/kmod.c
|
执行一个用户模式的程序
|
Linked list library functions
|
include/linux/list.h
|
看表3.1
|
register_die_notifier()
|
arch/your-arch/kernel/traps.c
|
注册一个die通知
|
register_netdevice_notifier()
|
net/core/dev.c
|
注册一个netdevice通知
|
register_inetaddr_notifier()
|
net/ipv4/devinet.c
|
注册一个inetaddr通知
|
BLOCKING_NOTIFIER_HEAD()
|
include/linux/notifier.h
|
创建一个用户自定义的阻塞性的通知
|
blocking_notifier_chain_register()
|
kernel/sys.c
|
注册一个阻塞性的通知
|
blocking_notifier_call_chain()
|
kernel/sys.c
|
将事件分发给一个阻塞性的通知链
|
ATOMIC_NOTIFIER_HEAD()
|
include/linux/notifier.h
|
创建一个原子性的通知
|
atomic_notifier_chain_register()
|
kernel/sys.c
|
注册一个原子性的通知
|
DECLARE_COMPLETION()
|
include/linux/completion.h
|
静态定义一个完成实例
|
init_completion()
|
include/linux/completion.h
|
动态定义一个完成实例
|
complete()
|
kernel/sched.c
|
宣布完成
|
wait_for_completion()
|
kernel/sched.c
|
一直等待完成实例的完成
|
complete_and_exit()
|
kernel/exit.c
|
原子性的通知完成并退出
|
kthread_create()
|
kernel/kthread.c
|
创建一个内核线程
|
kthread_stop()
|
kernel/kthread.c
|
让一个内核线程停止
|
kthread_should_stop()
|
kernel/kthread.c
|
内核线程可以使用该函数轮询是否其他的执行单元已经调用 kthread_stop()让其停止
|
IS_ERR()
|
include/linux/err.h
|
查看返回值是否是一个出错码
|
本文出自 “宋宝华的博客” 博客,请务必保留此出处http://21cnbao.blog.51cto.com/109393/120805
数据结构
|
路径
|
描述
|
wait_queue_t
|
include/linux/wait.h
|
内核线程欲等待某事件或系统资源时使用
|
list_head
|
include/linux/list.h
|
用于构造双向链表数据结构的内核结构体
|
hlist_head
|
include/linux/list.h
|
用于实现哈希表的的内核结构体
|
work_struct
|
include/linux/workqueue.h
|
实现工作队列,它是一种在内核中进行延后工作的方式
|
notifier_block
|
include/linux/notifier.h
|
实现通知链,用于将状态变更信息发生给请求此变更的代码段
|
completion
|
include/linux/completion.h
|
用于开始某线程活动并等待它们完成
|
表3.4 内核编程接口总结
内核接口
|
路径
|
描述
|
DECLARE_WAITQUEUE()
|
include/linux/wait.h
|
定义一个等待队列
|
add_wait_queue()
|
kernel/wait.c
|
将一个任务加入一个等待队列。该任务进入睡眠状态,知道它被另一个线程或中断处理函数唤醒。
|
remove_wait_queue()
|
kernel/wait.c
|
从等待队列中删除一个任务。
|
wake_up_interruptible()
|
include/linux/wait.h
kernel/sched.c
|
唤醒一个正在等待队列中睡眠的任务,将其返回调度器的运行队列。
|
schedule()
|
kernel/sched.c
|
放弃
CPU
,让内核的其他部分运行。
|
set_current_state()
|
include/linux/sched.h
|
设置一个进程的运行状态,可以是如下状态中的一种:
TASK_RUNNING
、
TASK_INTERRUPTIBLE
、
TASK_UNINTERRUPTIBLE
、
TASK_STOPPED
、
TASK_TRACED
、
EXIT_ZOMBIE
或
EXIT_DEAD
.
|
kernel_thread()
|
arch/your-arch/kernel/process.c
|
创建一个内核线程
|
daemonize()
|
kernel/exit.c
|
激活一个内核线程(未依附于用户资源),并将调用线程的父线程改为
kthreadd
。
|
allow_signal()
|
kernel/exit.c
|
使能某指定信号的发起
|
signal_pending()
|
include/linux/sched.h
|
检查是否有信号已经被传输。在内核中没有信号处理函数,因此,你不得不显示地检查信号的发起
|
call_usermodehelper()
|
include/linux/kmod.h
kernel/kmod.c
|
执行一个用户模式的程序
|
Linked list library functions
|
include/linux/list.h
|
看表
3.1
|
register_die_notifier()
|
arch/your-arch/kernel/traps.c
|
注册一个
die
通知
|
register_netdevice_notifier()
|
net/core/dev.c
|
注册一个
netdevice
通知
|
register_inetaddr_notifier()
|
net/ipv4/devinet.c
|
注册一个
inetaddr
通知
|
BLOCKING_NOTIFIER_HEAD()
|
include/linux/notifier.h
|
创建一个用户自定义的阻塞性的通知
|
blocking_notifier_chain_register()
|
kernel/sys.c
|
注册一个阻塞性的通知
|
blocking_notifier_call_chain()
|
kernel/sys.c
|
将事件分发给一个阻塞性的通知链
|
ATOMIC_NOTIFIER_HEAD()
|
include/linux/notifier.h
|
创建一个原子性的通知
|
atomic_notifier_chain_register()
|
kernel/sys.c
|
注册一个原子性的通知
|
DECLARE_COMPLETION()
|
include/linux/completion.h
|
静态定义一个完成实例
|
init_completion()
|
include/linux/completion.h
|
动态定义一个完成实例
|
complete()
|
kernel/sched.c
|
宣布完成
|
wait_for_completion()
|
kernel/sched.c
|
一直等待完成实例的完成
|
complete_and_exit()
|
kernel/exit.c
|
原子性的通知完成并退出
|
kthread_create()
|
kernel/kthread.c
|
创建一个内核线程
|
kthread_stop()
|
kernel/kthread.c
|
让一个内核线程停止
|
kthread_should_stop()
|
kernel/kthread.c
|
内核线程可以使用该函数轮询是否其他的执行单元已经调用
kthread_stop()
让其停止
|
IS_ERR()
|
include/linux/err.h
|
查看返回值是否是一个出错码
|
本文出自 “宋宝华的博客” 博客,请务必保留此出处http://21cnbao.blog.51cto.com/109393/120805