linux Tasklet 實現


記住 tasklet 是一個特殊的函數, 可能被調度來運行, 在軟中斷上下文, 在一個系統決 定的安全時間中. 它們可能被調度運行多次, 但是 tasklet 調度不累積; ; tasklet 只 運行一次, 即便它在被投放前被重復請求. 沒有 tasklet 會和它自己並行運行, 因為它 只運行一次, 但是 tasklet 可以與 SMP 系統上的其他 tasklet 並行運行. 因此, 如果 你的驅動有多個 tasklet, 它們必須采取某類加鎖來避免彼此沖突.

 

tasklet 也保證作為函數運行在第一個調度它們的同一個 CPU 上. 因此, 一個中斷處理 可以確保一個 tasklet 在處理者結束前不會開始執行. 但是, 另一個中斷當然可能在 tasklet 在運行時被遞交, 因此, tasklet 和中斷處理之間加鎖可能仍然需要.

 

tasklet 必須使用 DECLARE_TASKLET 宏來聲明: DECLARE_TASKLET(name, function, data);

name 是給 tasklet 的名子, function 是調用來執行 tasklet (它帶一個 unsigned long 參數並且返回 void )的函數, 以及 data 是一個 unsigned long 值來傳遞給 tasklet 函數.

 

short 驅動聲明它的 tasklet 如下:

 

void short_do_tasklet(unsigned long); DECLARE_TASKLET(short_tasklet, short_do_tasklet, 0);

 

函數 tasklet_schedule 用來調度一個 tasklet 運行. 如果 short 使用 tasklet=1 來 加載, 它安裝一個不同的中斷處理來保存數據並且調度 tasklet 如下:

 

irqreturn_t short_tl_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{

do_gettimeofday((struct timeval *) tv_head); /* cast to stop 'volatile' warning */

short_incr_tv(&tv_head); tasklet_schedule(&short_tasklet);

short_wq_count++; /* record that an interrupt arrived */ return IRQ_HANDLED;

}

 

實際的 tasklet 函數, short_do_tasklet, 將在系統方便時很快執行. 如同前面提過, 這個函數進行處理中斷的大量工作; 它看來如此:

 

void short_do_tasklet (unsigned long unused)

{

int savecount = short_wq_count, written;

short_wq_count = 0; /* we have already been removed from the queue */

 

/*

*  The bottom half reads the tv array, filled by the top half,

*  and prints it to the circular text buffer, which is then consumed

*  by reading processes */

/* First write the number of interrupts that occurred before this bh */ written = sprintf((char *)short_head,"bh after %6i\n",savecount); short_incr_bp(&short_head, written);

/*

*  Then, write the time values. Write exactly 16 bytes at a time,

*  so it aligns with PAGE_SIZE */

 

 

do {


 

written = sprintf((char *)short_head,"%08u.%06u\n",

(int)(tv_tail->tv_sec % 100000000), (int)(tv_tail->tv_usec));

short_incr_bp(&short_head, written); short_incr_tv(&tv_tail);

 

} while (tv_tail != tv_head);

 

wake_up_interruptible(&short_queue); /* awake any reading process */

}

 

在別的東西中, 這個 tasklet 記錄了從它上次被調用以來有多少中斷到達. 一個如 short 一樣的設備能夠在短時間內產生大量中斷, 因此在后半部執行前有幾個中斷到達就 不是不尋常的. 驅動必須一直准備這種可能性並且必須能夠從前半部留下的信息中決定有 多少工作要做.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM