•
Softirq
是中断下半部的处理方式
(
可以在不同
cpu
上同时运行
)
•
tasklet
是基于
softirq
实现的
,
使用比
softirq
简单
.
不
能在不同
cpu
上同时运行,但是不同
cpu
可以运行不同的
tasklet
.
•
vk_tasklet_init
(&
pstDecObj
->
stDecTasklet
,
pstDecObj
->
pfnHandleDecodeDone
, (unsigned long ) (
pstDecObj
->
pstAPUClass
)
);
•
vk_tasklet_kill
(&
pstDecObj
->
stDecTasklet
);
•
vk_tasklet_schedule
(&
pstDecObj
->
stDecTasklet
);
•
•
void
tasklet_disable
(
struct
tasklet_struct
*t);
•
/*
函数暂时禁止给定的
tasklet
被
tasklet_schedule
调度,直到这个
tasklet
被再次被
enable
;若这个
tasklet
当前在运行
,
这个函数忙等待直到这个
tasklet
退出*
/
•
void
tasklet_disable_nosync
(
struct
tasklet_struct
*t);
•
/*
和
tasklet_disable
类似,但是
tasklet
可能仍然运行在另一个
CPU */
•
void
tasklet_enable
(
struct
tasklet_struct
*t);
•
/*
使能一个之前被
disable
的
tasklet
;
若这个
tasklet
已经被调度
,
它会很快运行。
tasklet_enable
和
tasklet_disable
必须匹配调用
,
因为内核跟踪每个
tasklet
的
"
禁止次数
"*/
•
void
tasklet_schedule
(
struct
tasklet_struct
*t);
•
/*
调度
tasklet
执行,如果
tasklet
在运行中被调度
,
它在完成后会再次运行
;
这保证了在其他事件被处理当中发生的事件受到应有的注意
.
这个做法也允许一个
tasklet
重新调度它自己*
/
•
void
tasklet_hi_schedule
(
struct
tasklet_struct
*t);
•
/*
和
tasklet_schedule
类似,只是在更高优先级执行。当软中断处理运行时
,
它处理高优先级
tasklet
在其他软中断之前,只有具有低响应周期要求的驱动才应使用这个函数
,
可避免其他软件中断处理引入的附加周期*
/
•
void
tasklet_kill
(
struct
tasklet_struct
*t);
•
/*
确保了
tasklet
不会被再次调度来运行,通常当一个设备正被关闭或者模块卸载时被调用。如果
tasklet
正在运行
,
这个函数等待直到它执行完毕。若
tasklet
重新调度它自己,则必须阻止在调用
tasklet_kill
前它重新调度它自己,如同使用
del_timer_sync
*/
•
Kthread
:
•
pstClass
->thread=
vk_kthread_create
( _
APU_DEC_ProcRoutine
,
pstClass
,"
aud_handleProc
"
);
•
status=
vk_kthread_stop
(
pstClass
->thread
);
•
vk_kthread_should_stop
()
•
vk_wake_up_process
(
pstClass
->thread
);
•
Kthread
状态:
•
运行态 ,
•
可被打断的睡眠状态,
•
不可被打断的睡眠状态(信号发生时,不会被重新放到运行队列)
•
停止状态
•
僵死状态(进程已经终止,父进程未等待他完成,
(
异常了
)
)
•
追踪状态(比如
debug
)
•
Linux
内核的等待队列是以双循环链表为基础数据结构,与进程调度机制紧密结合,能够用于实现核心的异步事件通知机制
•
vk_init_waitqueue_head
(&(
pstClass
->
stWaitQueue
)
);
该函数初始化一个已经存在的等待队列头,它将整个队列设置为"未上锁"状态,并将链表指针prev和next指向它自身。
•
if(
vk_waitqueue_active
(&(
pstClass
->
stWaitQueue
) )
)
查看队列中是否有等待线程
•
vk_wake_up_interruptible
(&(
pstClass
->
stWaitQueue
)
);
wake_up_interruptible只负责唤醒状态为TASK_INTERRUPTIBLE的进程
wake_up函数不仅可以唤醒状态为TASK_UNINTERRUPTIBLE的进程,而且可以唤醒状态为TASK_INTERRUPTIBLE的进程
vk_wait_event_interruptible_timeout
vk_wait_event_interruptible( pstClass->stWaitQueue, ( pstClass->u32PermitMask& u32BitMask ) == u32BitMask ); (阻塞等待condition满足)
•
在
wait_event_interruptible
()
中首先判断
conditon
是不是已经满足,如果是则直接返回
0
,否则调用
__
wait_event_interruptible
()
,并用
__ret
来存放返回值。
__
wait_event_interruptible
()
首先将定义并初始化一个
wait_queue_t
变量
__wait
,其中数据为当前进程状态
current
(
struct
task_struct
),并把
__wait
加入等待队列。在无限循环中,
__
wait_event_interruptible
()
将本进程置为可中断的挂起状态,反复检查
condition
是否成
立如
果成立则退出,如果不成立则继续休眠;条件满足后,即把本进程运行状态置为运行态,并把
__wait
从等待队列中清除,从而进程能够调度运行。
挂起的进程并不会自动转入运行的,因此,还需要一个唤醒动作,这个动作由wake_up_interruptible()完成,它将遍历作为参数传入的lock_wait等待队列,将其中所有的元素(通常都是task_struct)置为运行态,从而可被调度。
// 与之类似的还有wait_event(),不同点在于wait_event_interruptible()可以被信号唤醒。
•
__inline__
int
set_bit
(
int
nr,int
*
addr
)
//将addr的第nr(nr为0-31)位置值置为1;
•
__inline__
int
clear_bit
(
int
nr,
int
*
addr
)
//将addr的第nr(nr为0-31)位置值置为0;
•
__inline__
int
test_bit
(
int
nr,
int
*
addr
)
•
//
判断
addr
的第
nr(nr
为
0-31)
位置的值是否为
1;
用法线程函数里就是 wait + test_bit
中断Notify set_bit
等到之后再clear_bit
test_and_set_bit(int nr, volatilevoid *addr)
test_and_clear_bit