通知链

145 阅读14分钟

清单3.5 使用工作队列进行延后工作
#include <linux/workqueue.h>

struct workqueue_struct *wq;

/* Driver Initialization */
static int __init
mydrv_init(void)
{
/* ... */
wq = create_singlethread_workqueue("mydrv");
return 0;
}
/* Work Submission. The first argument is the work function, and
the second argument is the argument to the work function */
int
submit_work(void (*func)(void *data), void *data)
{
struct work_struct *hardwork;

hardwork = kmalloc(sizeof(struct work_struct), GFP_KERNEL);

/* Init the work structure */
INIT_WORK(hardwork, func, data);

/* Enqueue Work */
queue_work(wq, hardwork);
return 0;
}\

如果你使用了工作队列,你必须将对应模块设为GPL许可证,否则会出现连接错误。这是因为,内核仅仅将这些函数导出给GPL授权的代码。如果你查看内核工作队列的实现代码,你将发现如下的限制表达式:

MODULE_LICENSE("GPL");

通知链

通知链(Notifier chains)可用于将状态改变信息发送给请求这些改变的代码段。与硬编码不同,notifier提供了一种在感兴趣的事件产生时获得警告的技术。Notifier的初始目的是将网络事件传递给内核中感兴趣的部分,但是现在也可用于许多其他目的。内核已经为主要的事件预先定义了notifier。这样的通知的实例包括:

(1)死亡通知。当内核触发了一个陷阱和错误(由oops、缺页或断点命中引发)时被发送。例如,如果你正在为一个医疗等级卡编写设备驱动,你可能需要注册自身接受死亡通知,这样,当内核恐慌发生时,你可以关闭医疗电子。

(2)网络设备通知。当一个网络接口卡启动和关闭的时候被发送。

(3)CPU频率通知。当处理器的频率发生跳变的时候,会分发这一通知。

(4)Internet地址通知。当侦测到网络接口卡的IP地址发送改变的时候,会发送此通知。

Notifier的应用实例是drivers/net/wan/hdlc.c中的高级数据链路控制(HDLC)协议驱动,它会注册自己到网络设备通知链,以侦测载波状态的改变。

为了将你的代码与某通知链关联,你必须注册一个相关链的时间处理函数。当相应的事件发生时,事件ID和与通知相关的参数会传递给该处理函数。为了实现一个自定义的通知链,你必须另外实现底层结构,以便当事件被侦测到时,链会被激活。


\清单3.6给出了使用预定义的通知和用户自定义通知的例子,表3.2则对清单3.6中的通知链和它们传递的事件进行了简要的描述,因此,可以对照查看表3.2和清单3.6。

表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.6 通知事件处理函数\
\#include \<linux/notifier.h>\
\#include \<asm/kdebug.h>\
\#include \<linux/netdevice.h>\
\#include \<linux/inetdevice.h>\
 \
/\* Die Notifier Definition \*/\
static struct notifier_block my_die_notifier = {\
  .notifier_call = my_die_event_handler,\
};\
/\* Die notification event handler \*/\
int\
my_die_event_handler(struct notifier_block \*self,\
                          unsigned long val, void \*data)\
{\
  struct die_args \*args = (struct die_args \*)data;\
 \
  if (val == 1) { /\* '1' corresponds to an "oops" \*/\
    printk("my_die_event: OOPs! at EIP=%lx\n", args->regs->eip);\
  } /\* else ignore \*/\
  return 0;\
}\
 \
 \
/\* Net Device notifier definition \*/\
static struct notifier_block my_dev_notifier = {\
  .notifier_call = my_dev_event_handler,\
};\
 \
 \
/\* Net Device notification event handler \*/\
int my_dev_event_handler(struct notifier_block \*self,\
                              unsigned long val, void \*data)\
{\
  printk("my_dev_event: Val=%ld, Interface=%s\n", val,\
           ((struct net_device \*) data)->name);\
  return 0;\
}\
 \
 \
/\* User-defined notifier chain implementation \*/\
static BLOCKING_NOTIFIER_HEAD(my_noti_chain);\
 \
static struct notifier_block my_notifier = {\
  .notifier_call = my_event_handler,\
};\
 \
/\* User-defined notification event handler \*/\
int my_event_handler(struct notifier_block \*self,\
                          unsigned long val, void \*data)\
{\
  printk("my_event: Val=%ld\n", val);\
  return 0;\
}\
/\* Driver Initialization \*/\
static int \__init\
my_init(void)\
{\
  /\* ... \*/\
 \
  /\* Register Die Notifier \*/\
  register_die_notifier(\&my_die_notifier);\
 \
  /\* Register Net Device Notifier \*/\
  register_netdevice_notifier(\&my_dev_notifier);\
 \
  /\* Register a user-defined Notifier \*/\
  blocking_notifier_chain_register(\&my_noti_chain, \&my_notifier);\
 \
  /\* ... \*/\
}\
通过BLOCKING_NOTIFIER_HEAD(),清单3.6中的my_noti_chain被定义为一个阻塞通知,经由对blocking_notifier_chain_register()函数的调用,它被注册。这意味着该通知事件处理函数总是在进程上下文被调用,也允许睡眠。如果你的通知处理函数允许从中断上下文调用,你应该使用ATOMIC_NOTIFIER_HEAD()定义该通知链并使用atomic_notifier_chain_register()注册它。\
老的通知接口\
早于2.6.17的内核版本仅支持一个通用目的的通知链。通知链注册函数notifier_chain_register()内部使用自旋锁保护,但游走于通知链以分发事件给通知处理函数的函数notifier_call_chain()确是无锁的。不加锁的原因是事件处理函数可能会睡眠、在运行中注销自己或在中断上下文中被调用。但是无锁的实现却引入了竞态,而新的通知API则建立于老的接口之上,其设计中包含了克服此限制的意图。\
完成接口\
内核中的许多地方会激发一个单独的执行线索,之后等待它的完成。完成接口是一个充分的且简单的此类编码的实现模式。\
一些使用场景的例子包括:\
(1)你的驱动模块中包含了一个辅助内核线程。当你卸载这个模块时,在模块的代码从内核空间被移除之前,release()函数将被调用。release函数中要求内核线程杀死自身,它一直阻塞等待线程的退出。清单3.7实现了这个例子。\
(2)你正在编写块设备驱动(第14章《块设备驱动》讨论)中将设备读请求排队的部分。这激活了以单独线程或工作队列方式实现的一个状态机的变更,而驱动本身想一直等到该操作完成前才执行下一次操作。drivers/block/floppy.c就是这样的一个例子。\
(3)一个应用请求模拟/数字转换(ADC)驱动完成一次数据采样。该驱动初始化一个转换请求,接下来一直等待转换完成的中断产生,并返回转换后的数据。\
清单3.7 使用完成接口进行同步\
static DECLARE_COMPLETION(my_thread_exit);      /\* Completion \*/\
static DECLARE_WAIT_QUEUE_HEAD(my_thread_wait); /\* Wait Queue \*/\
int pink_slip = 0;                              /\* Exit Flag \*/\
 \
/\* Helper thread \*/\
static int\
my_thread(void \*unused)\
{\
  DECLARE_WAITQUEUE(wait, current);\
 \
  daemonize("my_thread");\
  add_wait_queue(\&my_thread_wait, \&wait);\
 \
  while (1) {\
    /\* Relinquish processor until event occurs \*/\
    set_current_state(TASK_INTERRUPTIBLE);\
    schedule();\
    /\* Control gets here when the thread is woken\
       up from the my_thread_wait wait queue \*/\
 \
    /\* Quit if let go \*/\
    if (pink_slip) {\
      break;\
    }\
    /\* Do the real work \*/\
    /\* ... \*/\
 \
  }\
 \
  /\* Bail out of the wait queue \*/\
  \__set_current_state(TASK_RUNNING);\
  remove_wait_queue(\&my_thread_wait, \&wait);\
 \
  /\* Atomically signal completion and exit \*/\
  complete_and_exit(\&my_thread_exit, 0);\
}\
 \
/\* Module Initialization \*/\
static int \__init\
my_init(void)\
{\
  /\* ... \*/\
 \
  /\* Kick start the thread \*/\
  kernel_thread(my_thread, NULL,\
                CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);\
 \
  /\* ... \*/\
}\
 \
/\* Module Release \*/\
static void \__exit\
my_release(void)\
{\
  /\* ... \*/\
  pink_slip = 1;                        /\* my_thread must go \*/\
  wake_up(\&my_thread_wait);             /\* Activate my_thread \*/\
  wait_for_completion(\&my_thread_exit); /\* Wait until my_thread\
                                           quits \*/\
  /\* ... \*/\
}\
可以使用DECLARE_COMPLETION()静态地定义一个完成实例,或者使用init_completion()动态地创建之。而一个执行线索可以使用complete()或complete_all()来标识一个完成。调用者自身则通过wait_for_completion()等待完成。\
在清单3.7中的my_release()函数中,在唤醒my_thread()之前,它通过pink_slip设置了一个退出请求标志。接下来,它调用wait_for_completion()等待my_thread()完成其退出。my_thread()函数醒来后,发现pink_slip被设置,它进行如下工作:\
(1)向my_release()函数通知完成;\
(2)杀死自身\
my_thread()使用complete_and_exit()函数原子性地完成了这2个步骤。complete_and_exit()关闭了模块退出和线程退出之间的那扇窗,而如果使用complete()和exit()函数2步操作的话,此窗口则是开放的。\
在第11章中,开发一个遥测设备驱动的时候,我们会使用完成接口。\
Kthread辅助接口\
Kthread为原始的线程创建函数添加了一层外衣由此简化了线程管理的任务。\
清单3.8使用kthread接口重写了清单3.7my_init()现在调用kthread_create()而不是kernel_thread(),你可以将线程的名字传入kthread_create(),而不再需要明确地在线程内调用daemonize()。\
Kthread允许你自由地调用内建的由完成接口所实现的退出同步机制。因此,如清单3.8my_release()函数所为,你可以直接调用kthread_stop()而不再需要设置pink_slip、唤醒my_thread()并使用wait_for_completion()等待它的完成。相似地,my_thread()可以进行一个简洁的对kthread_should_stop()的调用以确认其是否应该退出。\
清单3.8 使用Kthread辅助接口完成同步\
/\* '+' and '-' show the differences from Listing 3.7 \*/\
 \
\#include \<linux/kthread.h>\
 \
/\* Assistant Thread \*/\
static int\
my_thread(void \*unused)\
{\
   DECLARE_WAITQUEUE(wait, current);\
\-   daemonize("my_thread");\
 \
\-   while (1) {\
\+   /\* Continue work if no other thread has\
\+    \* invoked kthread_stop() \*/\
\+   while (!kthread_should_stop()) {\
      /\* ... \*/\
\-     /\* Quit if let go \*/\
\-     if (pink_slip) {\
\-       break;\
\-     }\
      /\* ... \*/\
    }\
    \__set_current_state(TASK_RUNNING);\
    remove_wait_queue(\&my_thread_wait, \&wait);\
 \
\-   complete_and_exit(\&my_thread_exit, 0);\
\+   return 0;\
 }\
 \
\+   struct task_struct \*my_task;\
 \
 /\* Module Initialization \*/\
 static int \__init\
 my_init(void)\
 {\
    /\* ... \*/\
\-   kernel_thread(my_thread, NULL,\
\-                 CLONE_FS | CLONE_FILES | CLONE_SIGHAND |\
                  SIGCHLD);\
\+   my_task = kthread_create(my_thread, NULL, "%s", "my_thread");\
\+   if (my_task) wake_up_process(my_task);\
 \
    /\* ... \*/\
 }\
 \
 /\* Module Release \*/\
 static void \__exit\
 my_release(void)\
 {\
    /\* ... \*/\
\-   pink_slip = 1;\
\-   wake_up(\&my_thread_wait);\
\-   wait_for_completion(\&my_thread_exit);\
\+   kthread_stop(my_task);\
 \
    /\* ... \*/\
 }\
代替使用kthread_create()创建线程,接下来再使用wake_up_process()激活它,你可以使用下面的一次调用达到目的:\
kthread_run(my_thread, NULL, "%s", "my_thread");\
错误处理助手\
    数个内核函数返回指针值。调用者通常将返回值与NULL对比以检查是否失败,但是它们很可能需要更多的信息以分析出确切的错误发生原因。由于内核地址有冗余比特,可以覆盖它以包含错误语义信息。一套辅助函数完成了此功能,清单3.9给出了一个简单的例子。\
\#include \<linux/err.h>\
 \
char \*\
collect_data(char \*userbuffer)\
{\
 \
  char \*buffer;\
 \
  /\* ... \*/\
  buffer = kmalloc(100, GFP_KERNEL);\
  if (!buffer) { /\* Out of memory \*/\
    return ERR_PTR(-ENOMEM);\
  }\
 \
  /\* ... \*/\
  if (copy_from_user(buffer, userbuffer, 100)) {\
    return ERR_PTR(-EFAULT);\
  }\
  /\* ... \*/\
 \
  return(buffer);\
}\
 \
 \
int\
my_function(char \*userbuffer)\
{\
  char \*buf;\
 \
  /\* ... \*/\
  buf = collect_data(userbuffer);\
  if (IS_ERR(buf)) {\
    printk("Error returned is %d!\n", PTR_ERR(buf));\
  }\
  /\* ... \*/\
 \
}\
在清单3.9中,如果collect_data()中的kmalloc()失败,你将获得如下信息:\
Error returned is -12!\
但是,如果collect_data()执行成功,它将返回一个数据缓冲区的指针。\
再来一个例子,我们给清单3.8中的线程创建代码添加错误处理(使用IS_ERR()和PTR_ERR()):\
my_task = kthread_create(my_thread, NULL, "%s", "mydrv");\
 \
\+  if (!IS_ERR(my_task)) {\
\+    /\* Success \*/\
     wake_up_process(my_task);\
\+  } else {\
\+    /\* Failure \*/\
\+    printk("Error value returned=%d\n", PTR_ERR(my_task));\
\+  }\
查看源代码\
ksoftirqd、pdflush和 khubd内核线程代码分别在kernel/softirq.c, mm/pdflush.c和 drivers/usb/core/hub.c文件中。\
kernel/exit.c可以找到daemonize(),以用户模式助手的实现见于kernel/kmod.c文件。\
list和hlist库函数位于include/linux/list.h。在整个类型中都有对它们的使用,因此在大多数子目录中,都能找到例子。其中的一个例子是include/linux/blkdev.h中定义的request_queue结构体,它存放磁盘I/O请求的链表。在第14章中我们会分析此数据结构。\
查看\[url]www\.ussg.iu.edu/hypermail/linux/kernel/0007.3/0805.html\[/url]可以跟踪到Torvalds和Andi Kleen之间关于使用hlist实现list库的利弊的争论。\
内核工作队列的实现位于kernel/workqueue.c文件,为了理解工作队列的用法,可以查看drivers/net/wireless/ipw2200.c中PRO/Wireless 2200网卡驱动。\
内核通知链的实现位于kernel/sys.c和include/linux/notifier.h文件。查看kernel/sched.c和include/linux/completion.h文件可以挖掘完成接口的实现机理。kernel/kthread.c包含了kthread辅助接口的源代码,include/linux/err.h则包含了错误处理接口的定义。\


表3.3给出了本章中所使用的主要的数据结构及其源代码路径的总结。表3.4列出了本章中使用的主要内核编程接口及其源代码路径。

\
\


**表3.3 数据结构总结**

| **数据结构**       | **路径**                     | **描述**                          |
| -------------- | -------------------------- | ------------------------------- |
| 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/)” 博客,请务必保留此出处<http://21cnbao.blog.51cto.com/109393/120805>

\


[](http://21cnbao.blog.51cto.com/109393/120805)

**表3.3 数据结构总结**

| **数据结构**       | **路径**                     | **描述**                          |
| -------------- | -------------------------- | ------------------------------- |
| 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/)” 博客,请务必保留此出处<http://21cnbao.blog.51cto.com/109393/120805>