忘记密码   免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
查看: 10147 | 回复: 3

cond_resched函数是否会忽略preempt_disable? [复制链接]

论坛徽章:
0
发表于 2009-01-08 02:11 |显示全部楼层
// preempt_disable()会使preempt_count加1
#define preempt_disable() \
do { \
        inc_preempt_count(); \
        barrier(); \
} while (0)

//  只检查了PREEMPT_ACTIVE标志
int __sched _cond_resched(void)
{
        if (need_resched() && !(preempt_count() & PREEMPT_ACTIVE) &&
                                        system_state == SYSTEM_RUNNING) {
                __cond_resched();
                return 1;
        }
        return 0;
}

如上代码,假如先调用了preempt_disable使preempt_count加1,显示禁用了内核抢占,
接着调用了某个会调用cond_resched的函数,然后_cond_resched函数只会检查PREEMPT_ACTIVE
标志,对0~7位的抢占计数器视而不见,使得该函数会调用schedule(),发生内核抢占。从而
忽略掉preempt_disable对于内核抢占的影响。

不知道我以上推断是否正确?如果是这样,那为什么要这么设计啊?还请各位指教一下。

论坛徽章:
0
发表于 2009-01-08 23:27 |显示全部楼层
首先确认一点,  如果使用了preempt_disable(), 是不允许调用cond_resched的, 如果调用, schedule()应该会打印出错信息.
这个很好理解, cond_resched()的目的是提高系统实时性, 主动放弃cpu供优先级更高的任务使用, 如果调用了preempt_disable(), 不允许抢占, 就不应该调用有cond_resched()的函数.

2.6.28内核, schedule()会在这里捕获这个错误:
asmlinkage void __sched schedule(void)
{
        struct task_struct *prev, *next;
        unsigned long *switch_count;
        struct rq *rq;
        int cpu;

need_resched:
        preempt_disable();
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
        rcu_qsctr_inc(cpu);
        prev = rq->curr;
        switch_count = &prev->nivcsw;

        release_kernel_lock(prev);
need_resched_nonpreemptible:

        schedule_debug(prev);
...

static inline void schedule_debug(struct task_struct *prev)
{
       /* 如果preempt值不等于1, 说明出错, 等于1而不是0是因为schedule()中要关闭抢占, 在上面有这句 */
        if (unlikely(in_atomic_preempt_off() && !prev->exit_state))
                __schedule_bug(prev);


怎么解决这个preempt_disable()和cond_resched()的冲突?
preempt_disable()是一个最底层的接口,  如果你要使用这个接口关抢占, 必须要熟悉会调用cond_resched()的函数, 或者知道如何调试这个bug, 这种bug发现和解决应该不难.
一般都是通过mutex, spinlock, 关中断, 关软中断等方法, 顺带关抢占. 如果是上面的几种情况, 最新的内核提供:
extern int cond_resched_lock(spinlock_t * lock);
extern int cond_resched_softirq(void);
static inline int cond_resched_bkl(void);
来代替cond_resched(), 使得在不同情况下使用更安全.

论坛徽章:
0
发表于 2009-01-09 12:34 |显示全部楼层
原来如此!写得真详细,太有帮助了!谢谢!

论坛徽章:
0
发表于 2012-01-04 14:52 |显示全部楼层
很到位 高手
您需要登录后才可以回帖 登录 | 注册

本版积分规则

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号 北京市公安局海淀分局网监中心备案编号:11010802020122
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:wangnan@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP