亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

linux下面的中斷處理軟件中斷tasklet機制

系統 2014 0

參考:

《Linux內核設計與實現》

http://blog.csdn.net/fontlose/article/details/8279113

http://blog.chinaunix.net/uid-27212029-id-3386692.html


tasklet是中斷處理下半部分最經常使用的一種方法,驅動程序一般先申請中斷,在中斷處理函數內完畢中斷上半部分的工作后調用tasklet。tasklet有例如以下特點:


1.tasklet僅僅能夠在一個CPU上同步地運行,不同的tasklet能夠在不同地CPU上同步地運行。
2.tasklet的實現是建立在兩個軟件中斷的基礎之上的,即HI_SOFTIRQ和TASKLET_SOFTIRQ,本質上沒有什么差別,僅僅只是HI_SOFTIRQ的優先級更高一些
3.因為tasklet是在軟中斷上實現的,所以像軟中斷一樣不能睡眠、不能堵塞,處理函數內不能含有導致睡眠的動作,如降低信號量、從用戶空間拷貝數據或手工分配內存等。
4.一個 tasklet 可以被禁止而且之后被又一次使能; 它不會運行直到它被使能的次數與被禁止的次數同樣.
5.tasklet的串行化使tasklet函數不必是可重入的,因此簡化了設備驅動程序開發人員的工作。

6.每一個cpu擁有一個tasklet_vec鏈表,詳細是哪個cpu的tasklet_vec鏈表,是依據當前線程是執行在哪個cpu來決定的。


tasklet是驅動程序實現可延遲函數的首選方法,tasklet建立在HI_SOFTIRT和TASKLET_SOFTIRQ兩個軟中斷上。
原理
tasklet和高優先級的tasklet分別存放在tasklet_vec和tasklet_hi_vec數組中,二者都包括類型為tasklet_head的
NR_CPUS個元素,每一個元素都是指向tasklet描寫敘述符鏈表的指針。
運行過程
HI_SOFTIRQ軟中斷相關的軟中斷函數是tasklet_hi_action(),而與TASKLET_SOFTIRQ相關的函數是tasklet_action()
? ? ?1.禁止本地中斷
? ? ?2.獲得本地CPU的邏輯號n
? ? ?3.把tasklet_vec[n]或tasklet_hi_vec[n]所指向的鏈表的地址存入局部變量list
? ? ?4.把tasklet_vec[n]或tasklet_hi_vec[n]的值賦為NULL,因此已調度的tasklet描寫敘述符鏈表被清空
? ? ?5.打開本地中斷
? ? ?6.對于list所指向的每一個tasklet描寫敘述符
? ? ? ? ? ? a.在多處理器系統上,檢查tasklet的TASKLET_STATE_RUN標志。
? ? ? ? ? ? ? ? ? ? if標志被設置,list又一次插入結構數組,并激活TASKLET_SOFTIRQ或HI_SOFTIRQ軟中斷,這個tasklet
? ? 被延遲
? ? ? ? ? ? ? ? ? ? else 設置TASKLET_STATE_RUN標志,以便tasklet不能在其它CPU上執行 ? ? ? ? ? ?
? ? ? ? ? ? b.通過查看tasklet描寫敘述符的count字段,看tasklet是否被禁止。假設是清TASKLET_STATE_RUN標志,把
? ? list又一次插入結構數組,并激活對應的軟中斷。
? ? ? ? ? ? c.假設tasklet被激活,清TASKLET_STATE_SCHED標志,并運行tasklet函數
編寫一個設備驅動程序的步驟
1.分配一個新的tasklet_struct數據結構,并用tasklet_init()初始化它;
2.實現tasklet函數
3.禁止或使能tasklet

tasklet結構體

  1. struct ?tasklet_struct??
  2. {??
  3. ???? struct ?tasklet_struct?*next;??
  4. ????unsigned? long ?state;??
  5. ????atomic_t?count;??
  6. ???? void ?(*func)(unsigned? long );??
  7. ????unsigned? long ?data;??
  8. };??
  9. ??
  10. tasklet結構變量是tasklet_vec鏈表的一個節點,next是鏈表的下一節點,state使用了兩個位例如以下??
  11. enum ??
  12. {??
  13. ????TASKLET_STATE_SCHED,???? /*?1已經被調度,0表示還沒調度*/ ??
  14. ????TASKLET_STATE_RUN??? /*?1tasklet正在運行,0表示尚未運行,僅僅針對SMP有效,單處理器無意義?*/ ??
  15. };??
  16. ??
  17. count用于禁止使能,每禁止一次計數加一,沒使能一次計數減一,僅僅有禁止次數和使能次數一樣(count等于0)時tasklet才會運行調用函數。??
  18. func?運行函數不能有導致睡眠、不能堵塞的代碼。??
  19. data?運行函數的參數??


tasklet的定義

  1. 定義時初始化?????
  2. ????定義變量名為name的tasklets_struct變量,并初始化調用函數為func,參數為data,使能tasklet??
  3. ????DECLARE_TASKLET(name,?func,?data);?????#define?DECLARE_TASKLET(name,?func,?data)?\??
  4. ???? struct ?tasklet_struct?name?=?{?NULL,?0,?ATOMIC_INIT(0),?func,?data?}??
  5. ??
  6. ????定義變量名為name的tasklets_struct變量,并初始化調用函數為func,參數為data,禁止tasklet??
  7. ????DECLARE_TASKLET_DISABLED(name,?func,?data);??
  8. ????#define?DECLARE_TASKLET_DISABLED(name,?func,?data)?\ ??
  9. ???? struct ?tasklet_struct?name?=?{?NULL,?0,?ATOMIC_INIT(1),?func,?data?}??
  10. ??
  11. 執行中初始化????先定義???? struct ?tasklet_struct?name?;??
  12. ????后初始化????
  13. ??
  14. void ?tasklet_init( struct ?tasklet_struct?*t, void ?(*func)(unsigned? long ),?unsigned? long ?data)??
  15. {??
  16. ????t->next?=?NULL;?????????????? // ??
  17. ????t->state?=?0;???????????????? //設置為未調度?未執行?? ??
  18. ????atomic_set(&t->count,?0);???? //默認使能 ??
  19. ????t->func?=?func;?????????????? //調用函數 ??
  20. ????t->data?=?data;?????????????? //調用函數參數 ??
  21. }??

tasklet的調用過程

  1. static ? inline ? void ?tasklet_schedule( struct ?tasklet_struct?*t);使用此函數就可以完畢調用??
  2. static ? inline ? void ?tasklet_schedule( struct ?tasklet_struct?*t)??
  3. {??
  4. ???? /*test_and_set_bit設置調度位TASKLET_STATE_SCHED,test_and_set_bit返回t->state設置前狀態,假設設置前狀態為1(已被調用)那么直接退出否則進入__tasklet_schedule函數*/ ??
  5. ???? if ?(!test_and_set_bit(TASKLET_STATE_SCHED,?&t->state))??
  6. ????????__tasklet_schedule(t);??
  7. }??
  8. ??
  9. ??
  10. void ?fastcall?__tasklet_schedule( struct ?tasklet_struct?*t)??
  11. {??
  12. ????unsigned? long ?flags;??
  13. ????local_irq_save(flags);?????????????????????? //關中斷保存中斷狀態 ??
  14. ????t->next?=?__get_cpu_var(tasklet_vec).list;?? //這兩行用于將新插入的節點?放置在tasklet_vec鏈表的頭部 ??
  15. ????__get_cpu_var(tasklet_vec).list?=?t;???????? //? ??
  16. ????raise_softirq_irqoff(TASKLET_SOFTIRQ);?????? //觸發一個軟終端 ??
  17. ????local_irq_restore(flags);??????????????????? //使能中斷的同一時候還恢復了由?local_irq_save()?所保存的中斷狀態 ??
  18. }??
  19. 至此調度函數已經觸發了一個軟中斷,詳細中斷函數看tasklet的初始化??
  20. void ?__init?softirq_init( void )??
  21. {??
  22. ????????open_softirq(TASKLET_SOFTIRQ,?tasklet_action,?NULL); //能夠看到軟中斷觸發后會運行tasklet_action這個函數 ??
  23. ????????open_softirq(HI_SOFTIRQ,?tasklet_hi_action,?NULL);??
  24. }??
  25. ??
  26. ??
  27. static ? void ?tasklet_action( struct ?softirq_action?*a)??
  28. {??
  29. ???? struct ?tasklet_struct?*list;??
  30. ??
  31. ????local_irq_disable();??????????????????????? //這里先關中斷?保證原子操作 ??
  32. ????list?=?__get_cpu_var(tasklet_vec).list;???? //取出tasklet_vec鏈表表頭 ??
  33. ????__get_cpu_var(tasklet_vec).list?=?NULL;???? //由于以下將會一次處理完,這里能夠預先清空tasklet_vec鏈表,對于為處理完的會又一次增加鏈表 ??
  34. ??????????????????????????????????????????????? //也能夠實如今tasklet的處理函數中又一次增加自己。 ??
  35. ????local_irq_enable();??
  36. ??
  37. ??
  38. ??
  39. ???? while ?(list)?{??
  40. ???????? struct ?tasklet_struct?*t?=?list;??????? //取一節點 ??
  41. ??
  42. ????????list?=?list->next;????????????????????? //循環遍歷所有節點? ??
  43. ??
  44. ???????? if ?(tasklet_trylock(t))?{?????????????? //這里僅僅是測試TASKLET_STATE_RUN標記,防止tasklet反復調用?? ??
  45. ??????????????????????????????????????????????? //疑問:這里假設推斷tasklet已經在上執行了,trylock失敗,那么為什么后面會被又一次增加鏈表呢,那不是下次又執行了? ??
  46. ???????????? if ?(!atomic_read(&t->count))?{????? //疑問:?假設tasklet被禁止了那么后面有把它加回鏈表中又一次觸發一次軟中斷,這樣不是一直有軟中斷了嗎?為什么不在禁止的時候移出鏈表,使能時候在增加呢??? ??
  47. ???????????????? if ?(!test_and_clear_bit(TASKLET_STATE_SCHED,?&t->state))? //檢查可調度位是否設置了,正常應該設置了的 ??
  48. ?????????????????????BUG();?????????????????????
  49. ????????????????t->func(t->data);?????????????? //處理調用函數 ??
  50. ????????????????tasklet_unlock(t);????????????? //清TASKLET_STATE_RUN標記 ??
  51. ???????????????? continue ;??
  52. ????????????}??
  53. ????????????tasklet_unlock(t);??
  54. ????????}??
  55. ??
  56. ????????local_irq_disable();??
  57. ????????t->next?=?__get_cpu_var(tasklet_vec).list;? //對于trylock失敗和tasklet禁止的節點會被又一次增加鏈表 ??
  58. ????????__get_cpu_var(tasklet_vec).list?=?t;??
  59. ????????__raise_softirq_irqoff(TASKLET_SOFTIRQ);??? //發起新的軟中斷,這里有兩條鏈表一條是處理中的鏈表list,一個是當前tasklet_vec中的鏈表,當出現不能處理的節點時將節點又一次增加tasklet_vec中后發起新的軟中斷,那么未處理的節點也會在下次中斷中處理。 ??
  60. ????????local_irq_enable();??
  61. ????}??
  62. }??

相關函數

  1. /*和tasklet_disable類似,可是tasklet可能仍然執行在還有一個?CPU?*/ ??
  2. static ? inline ? void ?tasklet_disable_nosync( struct ?tasklet_struct?*t)??
  3. {??
  4. ????atomic_inc(&t->count);?????? //降低計數后,t可能正在執行 ??
  5. ????smp_mb__after_atomic_inc();? //保證在多處理器時同步 ??
  6. }??
  7. /*函數臨時禁止給定的tasklet被tasklet_schedule調度,直到這個tasklet被再次被enable;若這個tasklet當前在執行,?這個函數忙等待直到這個tasklet退出*/ ??
  8. ??
  9. static ? inline ? void ?tasklet_disable( struct ?tasklet_struct?*t){??
  10. ???tasklet_disable_nosync(t);???
  11. ???tasklet_unlock_wait(t);?? //等待TASKLET——STATE_RUN標記清零??? ??
  12. ???smp_mb();??
  13. }??
  14. ??
  15. static ? inline ? int ?tasklet_trylock( struct ?tasklet_struct?*t){??
  16. ??? return ?!test_and_set_bit(TASKLET_STATE_RUN,?&(t)->state);??
  17. }??
  18. ??
  19. static ? inline ? void ?tasklet_unlock( struct ?tasklet_struct?*t){?????
  20. ????????smp_mb__before_clear_bit();???????
  21. ????????clear_bit(TASKLET_STATE_RUN,?&(t)->state);??
  22. }??
  23. ??
  24. static ? inline ? void ?tasklet_unlock_wait( struct ?tasklet_struct?*t){??
  25. ???? while ?(test_bit(TASKLET_STATE_RUN,?&(t)->state))?{??
  26. ??????????barrier();???
  27. ?????}??
  28. }??
  29. ??
  30. /*使能一個之前被disable的tasklet;若這個tasklet已經被調度,?它會非常快執行。tasklet_enable和tasklet_disable必須匹配調用,?由于內核跟蹤每一個tasklet的"禁止次數"*/ ???
  31. static ? inline ? void ?tasklet_enable( struct ?tasklet_struct?*t)??
  32. {??
  33. ????smp_mb__before_atomic_dec();??
  34. ????atomic_dec(&t->count);??
  35. }??
  36. ??
  37. /*和tasklet_schedule類似,僅僅是在更高優先級執行。當軟中斷處理執行時,?它處理高優先級?tasklet?在其它軟中斷之前,僅僅有具有低響應周期要求的驅動才應使用這個函數,?可避免其它軟件中斷處理引入的附加周期*/ ??
  38. void ?tasklet_hi_schedule( struct ?tasklet_struct?*t);??
  39. ??
  40. /*確保了?tasklet?不會被再次調度來執行,通常當一個設備正被關閉或者模塊卸載時被調用。假設?tasklet?正在執行,?這個函數等待直到它執行完成。若?tasklet?又一次調度它自己,則必須阻止在調用?tasklet_kill?前它又一次調度它自己,如同使用?del_timer_sync*/ ??
  41. void ?tasklet_kill( struct ?tasklet_struct?*t)??
  42. {??
  43. ???? if ?(in_interrupt())??
  44. ????????printk( "Attempt?to?kill?tasklet?from?interrupt\n" );??
  45. ??
  46. ???????? while ?(test_and_set_bit(TASKLET_STATE_SCHED,?&t->state))?{? //檢測t是否被調度 ??
  47. ???????? do ??
  48. ????????????yield();??
  49. ???????? while ?(test_bit(TASKLET_STATE_SCHED,?&t->state));?????????? //等待t調度位清零,還未運行調用函數 ??
  50. ????}??
  51. ????tasklet_unlock_wait(t);???????????????????????????????????????? //等待t調用函數運行完 ??
  52. ????clear_bit(TASKLET_STATE_SCHED,?&t->state);????????????????????? //函數調用完可能t被又一次增加鏈表,所以再清一次保證不再調用 ??
  53. }??
  54. 這個函數不是真的去殺掉被調度的tasklet,而是保證tasklet不再調用 ?

linux下面的中斷處理軟件中斷tasklet機制


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产妇乱子伦视频免费 | 亚洲精品国产自在久久出水 | 韩国办公室激情 | 国产精品国产色综合色 | 成人深夜网站 | 男人爱看的网站 | 国产乱码精品一区二区三区四川 | 免费一级欧美毛片 | 精品国产一区二区三区四区不 | 麻豆亚洲一区 | 狠狠狠狠狠狠狠狠 | 国产精品成人免费视频不卡 | 亚洲精品中文字幕一区在线 | 深夜免费在线视频 | 国产精品亚洲欧美大片在线看 | 999yy成年在线视频免费看 | 国产一级在线视频 | 青青青在线视频人视频在线 | 在线不卡福利 | 久久精品综合免费观看 | 天天干天天爽天天操 | 亚洲精品亚洲一区二区 | heyzo在线播放4k岛国 | 欧美福利视频在线观看 | 一本一本久久a久久精品综合麻豆 | 奇米影视4444 | 欧美国产日韩久久久 | 台湾亚洲精品一区二区tv | 在线500福利视频国产 | 国产欧美日韩第一页 | 色香欲综合成人免费视频 | 日韩美一区二区三区 | 综合色伊人 | 亚洲日韩精品欧美一区二区一 | 青草草在线观看 | 免费一看一级毛片 | 亚州在线播放 | 亚洲欧美日产综合一区二区三区 | 国产永久 | 成人小视频在线 | 亚洲在线国产 |