Chinaunix

标题: 2.6.24的内核是可抢占的吗?(已解决) [打印本页]

作者: ryancat    时间: 2008-09-25 14:01
标题: 2.6.24的内核是可抢占的吗?(已解决)
我让一个进程获得了自旋锁,然后执行schedule_timeout休眠10s(只是测试),之后再释放自旋锁;接着另外一个进程又想获得这个自旋锁,接着就死机了.如果内核是随处都可以抢占的话,是不应该死机的.

请教高手,不是说2.6的内核已经可以抢占了,是不是我用的内核版本编译的不对?

[ 本帖最后由 ryancat 于 2008-9-27 11:00 编辑 ]
作者: eveson    时间: 2008-09-26 20:49
单处理器上,自旋锁不能用在中断,睡眠中
作者: ryancat    时间: 2008-09-26 21:39
原帖由 eveson 于 2008-9-26 20:49 发表
单处理器上,自旋锁不能用在中断,睡眠中

是的,我这里是做个测试,看内核是否随处都可以抢占.
对这样的结果还是不能理解,如果真的是可抢占内核的话.
作者: sep    时间: 2008-09-26 23:24
对于标题,回答是肯定的
对于你说的内容,我觉得你对自旋锁没理解。自旋锁本身就用来禁止抢占的。你在临界区(获得自旋锁的代码区)内睡眠,又没中断打断,不死才怪
作者: dreamice    时间: 2008-09-27 09:47
原帖由 sep 于 2008-9-26 23:24 发表
对于标题,回答是肯定的
对于你说的内容,我觉得你对自旋锁没理解。自旋锁本身就用来禁止抢占的。你在临界区(获得自旋锁的代码区)内睡眠,又没中断打断,不死才怪


有道理!
作者: ryancat    时间: 2008-09-27 09:59
原帖由 sep 于 2008-9-26 23:24 发表
对于标题,回答是肯定的
对于你说的内容,我觉得你对自旋锁没理解。自旋锁本身就用来禁止抢占的。你在临界区(获得自旋锁的代码区)内睡眠,又没中断打断,不死才怪

是这样的,我知道获得了自旋锁后不能休眠,但是我这里这样写的目的是验证内核是否可以抢占,这段代码的流程是这样的:
1. 获得自旋锁
2. 休眠10s并调度
3. 释放自旋锁
当只有一个进程执行这段代码的时候,是不会死机的,从调试信息看,10s后确实释放了自旋锁.
但是当一个进程执行了这段代码,然后我又新启一个进程执行这段代码的时候,就系统死机了.
我认为,如果内核是随处可抢占,而不是只在某些关键点可以抢占的话,第2个进程当无法获取自旋锁,自旋一段时候后会再次调度前一个进程执行,就释放掉了自旋锁,系统就不会死机.
所以我觉得这个内核不是像真正的实时系统一样是完全可以抢占的.
代码如下:
ssize_t spin_write(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
        struct spin_dev *dev = filp->private_data;
        int delay = 10;

        printk(KERN_EMERG"process %i(%s) call %s\n", current->pid, current->comm, __FUNCTION__);
        spin_lock_irq(&dev->spinlock);
        printk(KERN_EMERG"process %i(%s) get spinlock\n", current->pid, current->comm);
        printk(KERN_EMERG"process %i(%s) begin to wait %i seconds\n", current->pid, current->comm, delay);
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(delay * HZ);
        spin_unlock_irq(&dev->spinlock);
        printk(KERN_EMERG"process %i(%s) release spinlock\n", current->pid, current->comm);

        return count;
}

[ 本帖最后由 ryancat 于 2008-9-27 10:01 编辑 ]
作者: Cyberman.Wu    时间: 2008-09-27 10:17
我印象中spin_lock主要是用于多处理器的吧,实际上是一个循环死等吧。以前Linux都是专门编译SMP版本和非SMP版本的,现在许多发行商图省事好像直接发面的是SMP版本的;当然就算是多核,你这种用法还是有可能最终全部挂死的。

我感觉你对内核“可抢占”的理解有问题,任何系统中,不管怎么设计,但终都会有一部分必须是串行执行的,所谓“可抢占”只是这一部分要尽量小而已,Linux内核的可抢占性是指它进入内核态之后许多时候还是可以被抢占的,并不是在内核的任何执行过程中都能被抢占。你见过哪一个实时操作系统可以在任何时候可以被抢占吗?VxWorks有一个kernel state,一旦进入这个状态任何抢占后最终也需要在kernel state执行的操作都会被挂在一个work queue中,最终串行地执行。
作者: ryancat    时间: 2008-09-27 10:59
原帖由 Cyberman.Wu 于 2008-9-27 10:17 发表
我印象中spin_lock主要是用于多处理器的吧,实际上是一个循环死等吧。以前Linux都是专门编译SMP版本和非SMP版本的,现在许多发行商图省事好像直接发面的是SMP版本的;当然就算是多核,你这种用法还是有可能最终 ...

我找到可能的原因了,在单核上面获取自旋锁一般就是关调度,这个时候其他进程就没法抢占了,所以死机.
作者: Cyberman.Wu    时间: 2008-09-28 10:20
标题: 回复 #8 ryancat 的帖子
Linux不清楚,不过一般来说CPU总要干点什么的,关调度并不见得就不能切换。

对于单核,由于同一时刻只有一个任务在招待,所以切换的时机也内有两个,一是当前任务通过调用进入内核空间引起主动切换,另一个是外部中断(包含时钟中断)而导致的切换,所以如果一个任务如果持有信号量而切换出去,后面任务还会继续运行,如果它也去获取这个信号量,就会由于获取失败而也切换出去。而对于spin lock,实际上主动是用于多CPU之前互斥的,由于是非常短的操作,通常就用“忙等”了吧。下面是2.6.9内核中i386的实现:


static inline void _raw_spin_lock(spinlock_t *lock)
{
#ifdef CONFIG_DEBUG_SPINLOCK
        if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
                printk("eip: %p\n", __builtin_return_address(0));
                BUG();
        }
#endif
        __asm__ __volatile__(
                spin_lock_string
                :"=m" (lock->lock) : : "memory");
}

#define spin_lock_string \
        "\n1:\t" \
        "lock ; decb %0\n\t" \
        "jns 3f\n" \
        "2:\t" \
        "rep;nop\n\t" \
        "cmpb $0,%0\n\t" \
        "jle 2b\n\t" \
        "jmp 1b\n" \
        "3:\n\t"

从这里可以看出是一个死循环,只到变量恢复为1为止。

如果只是想锁一下如果不行就不做某种操作应该用spin_trylock吧。另外Linux内核中如果不打开SMP开关编译实际上spin_lock是空操作,就不会出现这种情况了;不过现在的发行版本如果不自己重新编译内核都是直接支持SMP的,主要是现在多核的CPU越来越多,而对于普通用户要编译内核也是很麻烦的。

[ 本帖最后由 Cyberman.Wu 于 2008-9-28 11:02 编辑 ]
作者: jeff1115    时间: 2008-09-28 13:23
标题: 回复 #1 ryancat 的帖子
对的 2.6肯定是可以抢占的
但是自旋锁是不可中断的
作者: ryancat    时间: 2008-09-28 14:54
原帖由 jeff1115 于 2008-9-28 13:23 发表
对的 2.6肯定是可以抢占的
但是自旋锁是不可中断的



是可以抢占,但是不知道抢占的程度是什么.比如只能在某几个特殊点抢占(如isr返回,系统调用返回等),还是内核态的大部分时间都可以抢占.
自旋锁为什么不可以中断呢?那spin_lock和spin_lock_irq就没区别了.
作者: Cyberman.Wu    时间: 2008-09-29 11:23
标题: 回复 #11 ryancat 的帖子
任何系统都会有某些关键部分只能顺序执行的,或者说某些关键资源只能串行访问,严格来说所谓的可抢占只是指这一部分尽量地小,但很难完全没有的;另外也要看抢占过来的这一部分做的是什么操作,如果不需要内核操作则可以抢占过来招待。对于spin_lock,另一个CPU中断应该不会被关闭吧,如果来一个中断还是可以招待的,只是如果它如果也试图去锁定同一个spin lock才会忙等吧。另外从2.6代码看它有一个带flag的spin_lock,可以在得不到spin lock时就开中断然后再循环。

你可以看一看ucOS/II,它为了使系统的实时性尽量提高,在同一个系统调用过程中,如果前后两部分不要求一直锁中断的话,中间会开中断并且执行一个空操作,如果有外部中断的话可以及时响应,其含义其实是类似的。

[ 本帖最后由 Cyberman.Wu 于 2008-9-29 11:25 编辑 ]
作者: chinaemblinux    时间: 2008-09-30 12:49
2.6内核肯定是可以抢占的,当然需要在编译前配置内核时使能抢占;但是自旋锁只能用于多核处理器,对于单处理器来说是不起作用的;因为自旋锁的自旋是始终占用CPU的,如果在单处理器上自旋,系统就死了。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2