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

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條評論
主站蜘蛛池模板: 四虎影视国产精品婷婷 | 中文字幕色 | 久久www免费人成_看片美女图 | 中文字幕最新在线 | 请看一下欧美一级毛片 | 亚洲国产天堂 | 国产成人a视频在线观看 | 这里只有精品视频在线观看 | 岛国精品在线观看 | 亚洲精品aⅴ一区二区三区 亚洲精品ccc | 欧美成人se01短视频在线看 | 色婷婷综合在线视频最新 | 日韩久久影院 | 日韩影院久久 | 香蕉成人啪国产精品视频综合网 | 亚洲最新在线视频 | 日韩a无吗一区二区三区 | 日韩经典在线 | 成年女人视频免费免费看 | 欧美成人精品欧美一级乱黄 | 日本不卡在线播放 | 亚洲国产精品久久久久婷婷软件 | 99久热国产精品视频尤物不卡 | 成年毛片| 四虎影院免费在线播放 | 奇米444| 综合色久七七综合七七蜜芽 | 羞羞视频免费网站 | 性欧美极品xxxx欧美一区二区 | 久久久噜噜噜久久网 | 日韩 欧美 国产 亚洲 中文 | 国内精品伊人久久久久7777人 | 国产欧美日韩一区 | 看片久久 | 欧美在线小视频 | 精品久久中文久久久 | 日韩中文在线 | 四虎最新永久免费网址 | 日本精品久久久中文字幕 | 婷婷综合在线观看丁香 | 成人中文字幕一区二区三区 |