美文网首页程序员
内核线程同步之signal

内核线程同步之signal

作者: 网路元素 | 来源:发表于2019-10-20 15:35 被阅读0次

    对于内核线程,尤其是在同一模块里有多个时,我们想终止其中一个,而又不想卸载模块,此时signal就帮上我们一个大忙了,在设计时让线程接收信号并处理,想停止时发信号给它,而在内核里需要用到如下信号相关函数: 

    1.signal_pending 

    在Linux内核源码include/linux/sched.h文件里,有如下函数定义:

    static inline int signal_pending(struct task_struct *p)
    {
            return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING));
    }

    该函数用于判断指定线程有没有接收到信号,即信号有没有被阻塞。上面的参数我们一般是判断当前线程,故而会用到include/asm-generic/current.h里的current宏,定义如下:

    #define current get_current()

    2.allow_signal 

    在Linux内核源码kernel/exit.c有该函数的实现,而在include/linux/sched.h文件里有如下声明:

    extern int allow_signal(int);

    其参数是SIGKILL等宏,在include/uapi/asm-generic/signal.h文件中有相应的宏定义。 内核线程允许接收信号后,还需要确保该线程是可打断的,需要用到如下宏: 

    1.set_current_state 

    在include/linux/sched.h文件中有如下宏定义:

    #define set_current_state(state_value) \
            set_mb(current->state, (state_value))

    2.TASK_INTERRUPTIBLE 

    在同一头文件中如下宏定义:

    #define TASK_INTERRUPTIBLE 1

    上面两个宏结合使用用于配置当前线程的状态是可被中断的。接下来上代码吧:

    #include <linux/module.h>
    #include <linux/kthread.h>
    #include <linux/delay.h>

    static struct task_struct * slam_thread = NULL;
    static int is_signal_exited = 0;

    static int slam_func(void *data)
    {
            printk("<xinu>%s()!\n", __func__);
            allow_signal(SIGKILL);
            mdelay(1000);

            while(!signal_pending(current) && !kthread_should_stop())
            {
                    printk("<xinu>jiffies(%lu)\n", jiffies);
                    set_current_state(TASK_INTERRUPTIBLE);
                    schedule_timeout(msecs_to_jiffies(5000));
            }

            printk("<xinu>leave slam_func!\n");
            is_signal_exited = 1;

            return 0;
    }

    static __init int kthread_signal_example_init(void)
    {
            slam_thread = kthread_run(slam_func, NULL, "slam");
            printk("<xinu>kthread_signal_example_init()!\n");

            return 0;
    }

    static __exit void kthread_signal_example_exit(void)
    {
            if(!is_signal_exited && !IS_ERR(slam_thread))
            {
                    kthread_stop(slam_thread);
            }

            printk("<xinu>%s()!\n", __FUNCTION__);
    }

    module_init(kthread_signal_example_init);
    module_exit(kthread_signal_example_exit);

    相应的Makefile文件内容如下:

    obj-m += kthread_signal_example.o

    CUR_PATH:=$(shell pwd)
    LINUX_KERNEL_PATH:=/home/xinu/linux-3.13.6

    all:
            make -C $(LINUX_KERNEL_PATH) M=$(CUR_PATH) modules

    clean:
            make -C $(LINUX_KERNEL_PATH) M=$(CUR_PATH) clean

    对应的源码文件目录树如下:

     /home/xinu/xinu/linux_kernel_driver_l1/kthread_signal_example/
    ├── kthread_signal_example.c
    └── Makefile 

    当我们编译加载模块后,使用ps aux命令可以看到有如下一行信息: 

    root 11390 0.0 0.0 0 0 ? S 17:46 0:00 [slam] 

    其中11390就是该线程的PID,此时我们通过使用kill -SIGKILL 11390发信号终止线程rmmod卸载模块的方式对比dmesg的输出情况,就可以知道信号在什么时候使用,避免每执行一条命令都看下dmesg信息。 

    参考网址: 

    http://www.cnblogs.com/zhuyp1015/archive/2012/06/13/2548494.html
    http://lwn.net/Articles/53563/
    http://reneeciou.blogspot.com/2013/08/linux-kernel-threads.html

    相关文章

      网友评论

        本文标题:内核线程同步之signal

        本文链接:https://www.haomeiwen.com/subject/satryctx.html