忘记密码   免费注册 查看新帖 | 论坛精华区
ChinaUnix.net
  平台论坛 博客 微博 读书 人才 精华 文库 自测 | 频道操作系统 开发 数据库 存储 服务器 网络 IT新闻 Linux 下载 Power用户组
最近访问板块 发新帖
查看: 3810 | 回复: 3

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

帖子
5
主题
3
精华
0
可用积分
37
专家积分
0
在线时间
1 小时
注册时间
2008-05-28
最后登录
2010-03-11
论坛徽章:
0
发表于 2009-01-08 02:11:44 |显示全部楼层
// 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对于内核抢占的影响。

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

帖子
234
主题
12
精华
2
可用积分
143
专家积分
0
在线时间
2 小时
注册时间
2003-05-16
最后登录
2012-02-08
论坛徽章:
0
发表于 2009-01-08 23:27:26 |显示全部楼层
首先确认一点,  如果使用了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(), 使得在不同情况下使用更安全.

帖子
5
主题
3
精华
0
可用积分
37
专家积分
0
在线时间
1 小时
注册时间
2008-05-28
最后登录
2010-03-11
论坛徽章:
0
发表于 2009-01-09 12:34:43 |显示全部楼层
原来如此!写得真详细,太有帮助了!谢谢!

帖子
37
主题
16
精华
0
可用积分
56
专家积分
0
在线时间
59 小时
注册时间
2011-12-05
最后登录
2012-02-08
论坛徽章:
0
发表于 2012-01-04 14:52:31 |显示全部楼层
很到位 高手
您需要登录后才可以回帖 登录 | 注册

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP