Linuxデバイスドライバ開発 カーネルスレッド

カーネルスレッド

カーネルモジュールの中でkthreadを生成し、定期処理を行なうサンプル実装

  1. #include <linux/init.h>  
  2. #include <linux/module.h>  
  3. #include <linux/types.h>          /* dev_t */  
  4. #include <linux/kdev_t.h>         /* MKDEV(), MAJOR() */  
  5. #include <linux/fs.h>             /* register_chrdev_region(), alloc_chrdev_region(), unregister_chrdev() */  
  6. #include <linux/kthread.h>            /* kthread_run(), kthread_should_stop() */  
  7.   
  8. MODULE_LICENSE("Dual BSD/GPL");  
  9.   
  10. int drv_major = 0;  
  11. int drv_minor = 0;  
  12. int drv_nr_devs = 1;  
  13. static struct task_struct *kthread_tsk;  
  14.   
  15. #define SKEL_DRV_NAME "skel_drv"  
  16.   
  17. static long get_timestamp(void)  
  18. {  
  19.     unsigned long ts_us = 0;  
  20.     struct timeval tv;  
  21.   
  22.     do_gettimeofday(&tv);  
  23.     ts_us = (unsigned long long)(tv.tv_sec)*1000000 + tv.tv_usec;  
  24.   
  25.     return ts_us;  
  26. }  
  27.   
  28. static void my_kthread_main(void)  
  29. {  
  30.     /* 
  31.      * 指定時間までCPU時間を放棄する 
  32.      * 単位はjiffiesなのでHZを指定することで1秒周期となる 
  33.      * なお、事前にstateをTASK_INTERRUPTIBLEにする必要がある 
  34.      */  
  35.     set_current_state(TASK_INTERRUPTIBLE);  
  36.     schedule_timeout(1 * HZ);  
  37.   
  38.     /* 起動後の処理 */  
  39.     pr_info("my_kthread_main:%ld\n", get_timestamp());  
  40. }  
  41.   
  42. static int my_kthread(void *arg)  
  43. {  
  44.     pr_info("%s:I %ld HZ-%d\n", __FUNCTION__, get_timestamp(), HZ);  
  45.   
  46.     while (!kthread_should_stop()) {  
  47.         my_kthread_main();  
  48.     }  
  49.   
  50.     pr_info("%s:O\n", __FUNCTION__);  
  51.     return 0;  
  52. }  
  53.   
  54. static int skel_init(void)  
  55. {  
  56.     dev_t dev = 0;  
  57.     int ret;  
  58.   
  59.     pr_info("%s\n", __FUNCTION__);  
  60.   
  61.     if (drv_major) {  
  62.         /* 指定デバイス番号を登録する */  
  63.         dev = MKDEV(drv_major, drv_minor);  
  64.         ret = register_chrdev_region(dev, drv_nr_devs, SKEL_DRV_NAME);  
  65.     }  
  66.     else {  
  67.         /* デバイス番号を動的に確保する */  
  68.         ret = alloc_chrdev_region(&dev, drv_minor, drv_nr_devs, SKEL_DRV_NAME);  
  69.         drv_major = MAJOR(dev);  
  70.     }  
  71.   
  72.     if (ret < 0) {  
  73.         pr_err("SKEL_DRV: cant't get major %d\n", drv_major);  
  74.     }  
  75.     else {  
  76.         pr_info("SKEL_DRV: char driver major number is %d\n", drv_major);  
  77.     }  
  78.   
  79.     /* カーネルスレッドの起動 */  
  80.     kthread_tsk = kthread_run(my_kthread, NULL, "skel kthread");  
  81.     if (IS_ERR(kthread_tsk)) {  
  82.         pr_err("SKEL_DRV: kthread_run failed\n");  
  83.     }  
  84.     else {  
  85.         pr_info("kthread_main pid:%d\n", kthread_tsk->pid);  
  86.     }  
  87.   
  88.     return 0;  
  89. }  
  90. static void skel_exit(void)  
  91. {  
  92.     pr_info("%s\n", __FUNCTION__);  
  93.   
  94.     /* カーネルスレッドの停止 */  
  95.     kthread_stop(kthread_tsk);  
  96.     unregister_chrdev(drv_major, SKEL_DRV_NAME);  
  97. }  
  98.   
  99. module_init(skel_init);  
  100. module_exit(skel_exit);  

実行確認

$ sudo insmod skel_drv.ko
$ sudo rmmod skel_drv
$ dmesg
 :
[514702.117329] skel_init
[514702.117332] SKEL_DRV: char driver major number is 243
[514702.117482] kthread_main pid:127959
[514702.117546] my_kthread:I 1548054143358956 HZ-250
[514703.117142] my_kthread_main:1548054144358638
[514704.117105] my_kthread_main:1548054145358691
[514705.117307] my_kthread_main:1548054146358977
[514706.117366] my_kthread_main:1548054147359125
[514706.425008] skel_exit
[514706.425015] my_kthread_main:1548054147666807
[514706.425016] my_kthread:O

ソースコード ダウンロード

目次


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS