03
26

kernel space coding-如履薄冰

有碰過kernel code的人大概多少都瞭解我標題的意思,kernel code很迷人,但很危險,稍不小心,就會被kernel panic拖進地獄

拿我最近review的code當例子,截取某一段code如下,這是一段相當簡單的kernel threading code,當kernel module被insert時,會開啟kernel thread執行thread_main這個function,當remove module時,會呼叫delete_thread把kernel thread砍掉,可以仔細看看thread_kill這段function,有沒有什麼問題

  1. void thread_kill( struct thread_t *th ) 
  2. { 
  3.  
  4. wait_queue_head_t queue;
  5. int try;
  6.  
  7. try = 0;
  8.  
  9. init_waitqueue_head( &queue );
  10.  
  11. while ( ( atomic_read( &th -> dead ) == 0 ) && ( try < 5 ) ) 
  12. { 
  13.  
  14. atomic_set( &th -> kill, 1 );
  15. wake_up_interruptible( &th -> wait );
  16. interruptible_sleep_on_timeout( &queue, 100 );
  17.  
  18. try++;
  19. } 
  20. } 
  21. void delete_thread( struct thread_t *del_thread ) 
  22. { 
  23.  
  24. thread_kill( del_thread );
  25. kfree( del_thread );
  26. } 
  27. void thread_main( void *parameter ) 
  28. { 
  29. //th=route_table_thread;th->usr_func=route_activate;
  30.  
  31. struct thread_t *th;
  32.  
  33. th = ( struct thread_t* )parameter;
  34. init_waitqueue_head( &th -> wait );
  35.  
  36. atomic_set( &th -> kill, 0 );
  37. atomic_set( &th -> dead, 0 );
  38.  
  39. do 
  40. { 
  41. interruptible_sleep_on( &th -> wait ); //push thread_main into sleep;
  42.  
  43. th -> user_func();
  44.  
  45. } 
  46. while ( !atomic_read( &th -> kill ) );
  47.  
  48. atomic_set( &th -> dead, 1 );
  49. }

thread_kill這個function寫的很怪,依照這段code的寫法,它會嘗試判斷th->dead是否被設1,和try是否小於5,如果條件不合,會繼續把th->kill設為1並再沉睡一段時間
問題點一:有沒有可能kernel thread已經結束但thread_kill還是繼續執行(Yes)
問題點二:有沒有可能kernel thread根本沒砍掉但程式已經執行到kfree( del_thread ) (Yes)

上面的問題二情況比較嚴重,如果沒有在rmmod時當機,那一定在將來的某個時間點當掉,為什麼?當kernel thread從沉睡中醒來(有可能被kernel signal interrupt),發現它的th->xxx…等變數都不見了,那執行th->user_func()的結果就是當機

針對kernel thread的終結方法,我這邊建議用waiting completion的方式,所以我建議這段程式更改如下

  1. static struct completion comp;
  2.  
  3. void thread_kick( struct thread_t *th ) 
  4. { 
  5. wake_up_interruptible( &th -> wait );
  6. } 
  7.  
  8. void thread_kill( struct thread_t *th ) 
  9. { 
  10. atomic_set(&th->kill,1);
  11. thread_kick(some_thread_object);
  12. } 
  13.  
  14. void thread_main( void *parameter ) 
  15. { 
  16. //th=route_table_thread;th->usr_func=route_activate;
  17.  
  18. struct thread_t *th;
  19.  
  20. th = ( struct thread_t* )parameter;
  21. init_waitqueue_head( &th -> wait );
  22. init_completion(&comp);
  23. //以下恕刪
  24. } 
  25.  
  26. void delete_thread( struct thread_t *del_thread ) 
  27. { 
  28. thread_kill( del_thread );
  29. wait_for_completion(&comp);
  30. kfree( del_thread );
  31. }

標籤: linux
評論: 4 | 引用: 0 | 閱讀: 7954
  • 1 
elvis [ 2009-04-10 10:18 | 回覆 | 編輯 刪除 ]
不好意思,我想請問一下,有關於要 compile 自己寫的 kernel code 一定要重新 compile kernel 一次才能知道自己寫的 kernel code 是否有錯呢?
Joey [ 2009-04-11 23:02 郵箱 | 回覆 | 編輯 刪除 ]
是不用,但如果改到kernel header files就會重新compile..
elvis [ 2009-04-17 20:21 | 回覆 | 編輯 刪除 ]
不好意思,在打擾一下,
您的意思是說普通 compile 自己所寫的kernel code 就可以了嗎(已沒有修改到 kernel header files 的情況下,也就是不修改 linux/xxx.h 裡面的內容)
在編譯的時候 gcc -o... xxx.c 這邊都不用添加其他指令嗎?
Joey [ 2009-04-20 09:38 郵箱 | 回覆 | 編輯 刪除 ]
您的kernel code是指kernel module or build-in kernel source?

如果是built-in kernel source,linux的compile flag都已經內定了,不太需要自己手動改,只要把你的source加入kernel make file即可

而kernel module在2.6的Makefile有固定的寫法,所以也不用自己去下compile flag.

更進一步來說,是應該完全不用下gcc -o xxx xxx.c這種指令才對....
  • 1 
發表評論
暱 稱: 密 碼:
網 址: E - mail:
驗證碼: 驗證碼圖片 選 項:
頭 像:
內 容: