tasklet也是屬於softirq的一種,差別在於執行順序是排在softirq後面且不會有重複進入問題(reentrant),加上不是靜態編譯,因此,不需要特別修改Kernel就可以使用,因此,是一種相當適合應用在高優先級別的延遲處理機制,當然,高優先級別的機制是不適合處理太過耗時的東西,這點還是需要特別注意
使用步驟:
1. tasklet_init() 2. _test_and_set_bit() 3. __tasklet_schedule() 4. tasklet_kill()
ldd.S
.global init_module .global cleanup_module .equ BUTTON, 27 .equ IRQF_TRIGGER_RISING, 1 .equ TASKLET_STATE_SCHED, 0 .equ TASKLET_STATE_RUN, 1 .section .modinfo, "ae" __UNIQUE_ID_0: .asciz "license=GPL" __UNIQUE_ID_1: .asciz "author=Steward Fu" __UNIQUE_ID_2: .asciz "description=Linux Driver" .equ tasklet.next, 0 .equ tasklet.state, 4 .equ tasklet.count, 8 .equ tasklet.func, 12 .equ tasklet.data, 16 .struct 0 tasklet_s: i0: .struct . + 4 i1: .struct . + 4 i2: .struct . + 4 i3: .struct . + 4 i4: .struct . + 4 tasklet_e: tasklet_l = tasklet_e - tasklet_s .section .data btn_irq: .dcb 4 irq_name: .asciz "gpio_irq" task_msg: .asciz "tasklet_handler\n" mytask: .space tasklet_l .align 2 .section .text tasklet_handler: push {lr} ldr r0, =task_msg bl printk pop {pc} irq_handler: push {lr} mov r0, #TASKLET_STATE_SCHED ldr r1, =mytask add r1, #tasklet.state bl _test_and_set_bit cmp r0, #0 bne irq_exit ldr r0, =mytask bl __tasklet_schedule irq_exit: mov r0, #1 pop {pc} init_module: push {r4, r5, lr} ldr r0, =mytask ldr r1, =tasklet_handler mov r2, #0 bl tasklet_init mov r0, #BUTTON bl gpio_to_desc bl gpiod_to_irq ldr r1, =btn_irq str r0, [r1] ldr r1, =irq_handler mov r2, #0 mov r3, #IRQF_TRIGGER_RISING ldr r4, =irq_name mov r5, #0 push {r4, r5} bl request_threaded_irq pop {r4, r5} mov r0, #0 pop {r4, r5, pc} cleanup_module: push {lr} ldr r0, =btn_irq ldr r0, [r0] mov r1, #0 bl free_irq ldr r0, =mytask bl tasklet_kill pop {pc} .end
init_module: 設定GPIO中斷以及tasklet延遲處理副程式
irq_handler: 安排一個tasklet延遲處理
tasklet_handler: 列印字串
cleanup_module: 釋放中斷資源以及刪除tasklet
完成
# tasklet_handler