kthread_create和kernel_thread的区别和总结

在看linux驱动代码的时候,经常惠会碰到kthread_create这个函数,google一下,发现很多人在讲二者的区别,但是都在讲源码的区别而已,总结不够,感觉没有说出二者之间的本质区别,自己总结下。
    一. 源码分析(linux-2.6.39)
1.  kthread_create源码分析

  1. #define kthread_create( threadfn, data, namefmt, arg. . . ) / kthread_create_on_node( threadfn, data, - 1, namefmt, ##arg)
  2. 149 struct task_struct * kthread_create_on_node( int ( * threadfn) ( void * data) ,
  3. 150 void * data,
  4. 151 int node,
  5. 152 const char namefmt[ ] ,
  6. 153 . . . )
  7. 154 {
  8. 155 struct kthread_create_info create;
  9. 156
  10. 157 create. threadfn = threadfn;
  11. 158 create. data = data;
  12. 159 create. node = node;
  13.     /*kthread_create采用了完成量机制,不明白的同学可以先去查阅下等待量机制的原理*/
  14. 160 init_completion( & create. done) ;
  15. 161
  16. 162 spin_lock( & kthread_create_lock) ;
  17.     /*注意这个全局链表kthread_create_list, 所用通过kthread_create创建的内核线程都会挂在这*/
  18. 163 list_add_tail( & create. list, & kthread_create_list) ;
  19. 164 spin_unlock( & kthread_create_lock) ;
  20.     /*这是最重要的地方,从代码看是唤醒了kthreadd_task这个进程,如果对代码比较熟悉的话,就会想到这是内核中  的1号进程kthreadd*/
  21. 166 wake_up_process( kthreadd_task) ;
  22.    /*当前进程在完成量上睡眠等待*/
  23. 167 wait_for_completion( & create. done) ;
  24. 168
  25. 169 if ( ! IS_ERR( create. result) ) {
  26. 170 static const struct sched_param param = { . sched_priority = 0 } ;
  27. 171 va_list args;
  28. 172
  29. 173 va_start( args, namefmt) ;
  30. 174 vsnprintf( create. result- > comm, sizeof( create. result- > comm) ,
  31. 175 namefmt, args) ;
  32. 176 va_end( args) ;
  33. 177 / *
  34. 178 * root may have changed our ( kthreadd' s) priority or CPU mask.
  35. 179 * The kernel thread should not inherit these properties.
  36. 180 * /
  37. 181 sched_setscheduler_nocheck( create. result, SCHED_NORMAL, & param) ;
  38. 182 set_cpus_allowed_ptr( create. result, cpu_all_mask) ;
  39. 183 }
  40. 184 return create. result;
  41. 185 }

具体讲解参见注释,上面代码的执行路径跳转到kthreadd这个内核线程,下面分析下kthreadd的代码:

  1. 249
  2. 250 int kthreadd( void * unused)
  3. 251 {
  4. 252 struct task_struct * tsk = current;
  5. 253
  6. 254 / * Setup a clean context for our children to inherit. * /
  7.     /*上面这段注释尤为重要,个人认为这就是kthread_create和kernel_thread的本质区别,对current做了一些       /*处理:设置当前进程的进程名,清空当前进程的信号等,都是为了保证一个干净的上下文环境*/
  8. 255 set_task_comm( tsk, "kthreadd" ) ;
  9. 256 ignore_signals( tsk) ;
  10. 257 set_cpus_allowed_ptr( tsk, cpu_all_mask) ;
  11. 258 set_mems_allowed( node_states[ N_HIGH_MEMORY] ) ;
  12. 259
  13. 260 current- > flags | = PF_NOFREEZE | PF_FREEZER_NOSIG;
  14. 261
  15. 262 for ( ; ; ) {
  16. 263 set_current_state( TASK_INTERRUPTIBLE) ;
  17. 264 if ( list_empty( & kthread_create_list) )
  18. 265 schedule( ) ;   /*如果没有内核线程需要创建,即不是通过kthread_create入口进来的,当前进程就应该调度*/
  19. 266 __set_current_state( TASK_RUNNING) ;
  20. 267
  21. 268 spin_lock( & kthread_create_lock) ;
  22. 269 while ( ! list_empty( & kthread_create_list) ) { /*遍历全局链表kthread_create_list,创建内核线程*/
  23. 270 struct kthread_create_info * create;
  24. 271
  25. 272 create = list_entry( kthread_create_list. next ,
  26. 273 struct kthread_create_info, list) ;
  27. 274 list_del_init( & create- > list) ;
  28. 275 spin_unlock( & kthread_create_lock) ;
  29. 276
  30. 277 create_kthread( create) ; /代码执行路径转入create_kthread/
  31. 278
  32. 279 spin_lock( & kthread_create_lock) ;

代码执行路径转到create_kthread。

  1. 112 static void create_kthread( struct kthread_create_info * create)
  2. 113 {
  3. 114 int pid;
  4. 115
  5. 116 #ifdef CONFIG_NUMA
  6. 117 current- > pref_node_fork = create- > node;
  7. 118 #endif
  8. 119 / * We want our own signal handler ( we take no signals by default) . * /
  9. 120 pid = kernel_thread( kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD) ;
  10. 121 if ( pid < 0) {
  11. 122 create- > result = ERR_PTR( pid) ;
  12. 123 complete( & create- > done) ;
  13. 124 }
  14. 125 }
  15. 126

这里我们看到了kernel_thread,而且通过kthread_create入口进来的内核线程创建路径都具有统一的线程函数kthread。

  1. 74 static int kthread( void * _create)
  2.  75 {
  3.  76 / * Copy data: it' s on kthread' s stack * /
  4.  77 struct kthread_create_info * create = _create;
  5.  78 int ( * threadfn) ( void * data) = create- > threadfn;
  6.  79 void * data = create- > data;
  7.  80 struct kthread self;
  8.  81 int ret;
  9.  82
  10.  83 self. should_stop = 0;
  11.  84 self. data = data;
  12.  85 init_completion( & self. exited) ;
  13.  86 current- > vfork_done = & self. exited;
  14.  87
  15.  88 / * OK, tell user we' re spawned, wait for stop or wakeup * /
  16.     /*这里需要注意:创建的新的内核线程被置为TASK_UNINTERRUPTIBLE,需要显示的被唤醒才能运行*/
  17.  89 __set_current_state( TASK_UNINTERRUPTIBLE) ;
  18.  90 create- > result = current;
  19.  91 complete( & create- > done) ; /*这里显示的唤醒在完成量上等待的进程,然后发生调度,唤醒的是调用kthread_create函数的进程*/
  20.  92 schedule( ) ;
  21.  93
  22.  94 ret = - EINTR;
  23.  95 if ( ! self. should_stop)
  24.  96 ret = threadfn( data) ;
  25.  97
  26.  98 / * we can' t just return, we must preserve "self" on stack * /
  27.  99 do_exit( ret) ;
  28. 100 }

到此为止,一共出现了这么几个进程(线程):(本文中进程和线程不做区分)
(1)调用kthread_create的进程,假设为进程A
(2)kthreadd进程
(3)新创建的进程,假设为进程B
整个执行流程为:
A 调用kthread_create, 然后在kthread_create中唤醒kthreadd进程,A进程自己在完成量上睡眠,等待kthreadd进程创建过程完成,当kthreadd 最后创建完新进程B,即kthread函数中,再去唤醒睡眠的进程A,如果B进程想要运行,还要显示的对他唤醒。

二 区别总结
上面分析了kthread_create和kernel_thread的代码的不同部分,其中也提到了几点不同,现在总结一下:
(1)最重要的不同:kthread_create创建的内核线程有干净的上那上下文环境,适合于驱动模块或用户空间的程序创建内核线程使用,不会把某些内核信息暴露给用户程序
(2)二者创建的进程的父进程不同: kthread_create创建的进程的父进程被指定为kthreadd, 而kernel_thread创建的进程可以是init或其他内核线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值