在内核开发或者驱动开发过程中,不可避免需要使用较长循环的代码处理,尤其是内核代码中有很多for(;;)获取while(1)循环 等待硬件或者某个条件触发才能退出循环,这样做其实是非常危险,如果退出条件长期达不到条件,就会一直死循环下去,直接卡住整个内核或者某个驱动模块,即使在用户层发送control +c 信号,内核层也无法补捉退出循环。
为了解决上述,为了解决死循环导致卡死问题,能够在内核层捕获control+ c信号,内核开发一系列接口fatal_signal_pending/signal_pending用于在内核层能够捕获control +信号
fatal_signal_pending/signal_pendingfatal_signal_pending/signal_pending()接口为内核提供用于捕捉信号接口,一般在开发驱动中为了防止死循环卡死内核,可以使用上述接口用于捕获KILL信号,例如使用方法如下:
while(!fatal_signal_pending(current) { // infinite loop }
用于捕获用户向当前进程发送的signal信号,在内核代码尤其是驱动代码中有大量循环中使用该方法防止各种异常导致无法终止现象,例如ext4文件系统中ext4_readdir()函数:
static int ext4_readdir(struct file *file, struct dir_context *ctx) { ... ... while (ctx->pos < inode->i_size) { struct ext4_map_blocks map; if (fatal_signal_pending(current)) { err = -ERESTARTSYS; goto errout; } ... } }
从ext4文件系统中读取当前目录,此循环会耗时比较长,为了防止各种意外发送,使用fatal_signal_pending()可以捕获异常信号或者KILL信号 从而退出循环处理。
用例可以使用一个简单用例来说明:
#include#include #include #include #include #include #include #include #include #include MODULE_LICENSE("GPL v2"); #define MY_PROC "my_proc" static struct proc_dir_entry * my_proc_entry=NULL; static DEFINE_MUTEX(my_proc_lock); static int my_proc_1_data=1; static int my_proc_1_show(struct seq_file *s, void *v) { int * value = s->private; printk(KERN_INFO "begin loop-----n"); seq_printf(s, "begin loop----n"); while(!fatal_signal_pending(current)){ }; seq_printf(s, "end loop ----n"); printk(KERN_INFO "end loop-----n"); return 0; } static int __init my_proc_init(void) { my_proc_entry = proc_mkdir(MY_PROC, NULL); if (NULL == my_proc_entry) { return -ENODEV; } proc_create_single_data("proc_1", 0, my_proc_entry, my_proc_1_show, &my_proc_1_data); return 0; } static void __exit my_proc_exit(void) { remove_proc_entry(MY_PROC, NULL); } module_init(my_proc_init); module_exit(my_proc_exit); MODULE_AUTHOR("hzk"); MODULE_DEscriptION("A simple moudule for my proc"); MODULE_VERSION("V1.0");
该驱动ko模型,insmod 之后会生成一个/proc/my_proc/proc_1文件用于用户和内核进行交互,当使用cat /proc/my_proc/ proc_1命令读取该文件时会因为my_proc_1_show()函数死循环,导致一直卡死状态,当向该进程发送KILL信号之后,该驱动模块收到KILL信号后-将会退出信号,通过dmesg 可以查看到内核有两行打印:
[1387.122592] begin loop----- ... ... [1417.552870] end loop-----参考资料
Linux-Kernel Archive: Re: [PATCH] inline __fatal_signal_pending
How to catch a signal in a kernel module - Stack Overflow
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)