preempt_count_dec_and_test()用于判断当前thread的preempt_count是否零从而决定当前thread是否可以被抢占
其使用的例子如下:
#define preempt_enable() \
do { \
barrier(); \
if (unlikely(preempt_count_dec_and_test())) \
__preempt_schedule(); \
} while (0)
可以看到如果preempt_count_dec_and_test 如果返回true的话,则说明当前thread 可以被抢占
其源码分析如下:
#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER)
#define preempt_count_dec_and_test() \
({ preempt_count_sub(1); should_resched(0); })
#else
#define preempt_count_dec_and_test() __preempt_count_dec_and_test()
#endif
假定我们这里没有定义CONFIG_DEBUG_PREEMPT 或者 CONFIG_PREEMPT_TRACER。这两个是用于preempt debug的
一般情况下也不开.
static __always_inline bool __preempt_count_dec_and_test(void)
{
/*
* Because of load-store architectures cannot do per-cpu atomic
* operations; we cannot use PREEMPT_NEED_RESCHED because it might get
* lost.
*/
return !--*preempt_count_ptr() && tif_need_resched();
}
这里解释了为啥不能用PREEMPT_NEED_RESCHED来判断当前thread可以被抢占,原因是load-store 表示原子
操作,因此PREEMPT_NEED_RESCHED 可能被丢失掉.
在__preempt_count_dec_and_test 中首先通过preempt_count_ptr 减一来判断preempt是否为零
static __always_inline volatile int *preempt_count_ptr(void)
{
return ¤t_thread_info()->preempt_count;
}
也就是读取当前thread的preempt_count 后减一,看是否为零
其次调用tif_need_resched 看当前thread是否置位TIF_NEED_RESCHED
#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)
这里又是通过宏test_thread_flag 来判断是否置位TIF_NEED_RESCHED
#define test_thread_flag(flag) \
test_ti_thread_flag(current_thread_info(), flag)
这里在test_ti_thread_flag 首先通过current_thread_info 拿到当前thraed的thread_info,然后
判断thread_info 中是否置位TIF_NEED_RESCHED
static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
{
return test_bit(flag, (unsigned long *)&ti->flags);
}
所以总结一下:preempt_count_dec_and_test 用于判断当前thread是否可以被抢占,要被抢占的话
必须满足两个调价,一个是preempt为零,第二个是必须置位TIF_NEED_RESCHED