2.6.24的内核是可抢占的吗?(已解决)
我让一个进程获得了自旋锁,然后执行schedule_timeout休眠10s(只是测试),之后再释放自旋锁;接着另外一个进程又想获得这个自旋锁,接着就死机了.如果内核是随处都可以抢占的话,是不应该死机的.
请教高手,不是说2.6的内核已经可以抢占了,是不是我用的内核版本编译的不对?
[ 本帖最后由 ryancat 于 2008-9-27 11:00 编辑 ]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
单处理器上,自旋锁不能用在中断,睡眠中
是的,我这里是做个测试,看内核是否随处都可以抢占.
对这样的结果还是不能理解,如果真的是可抢占内核的话.
对于标题,回答是肯定的
对于你说的内容,我觉得你对自旋锁没理解。自旋锁本身就用来禁止抢占的。你在临界区(获得自旋锁的代码区)内睡眠,又没中断打断,不死才怪
有道理!
是这样的,我知道获得了自旋锁后不能休眠,但是我这里这样写的目的是验证内核是否可以抢占,这段代码的流程是这样的:
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 编辑 ]
我印象中spin_lock主要是用于多处理器的吧,实际上是一个循环死等吧。以前Linux都是专门编译SMP版本和非SMP版本的,现在许多发行商图省事好像直接发面的是SMP版本的;当然就算是多核,你这种用法还是有可能最终全部挂死的。
我感觉你对内核“可抢占”的理解有问题,任何系统中,不管怎么设计,但终都会有一部分必须是串行执行的,所谓“可抢占”只是这一部分要尽量小而已,Linux内核的可抢占性是指它进入内核态之后许多时候还是可以被抢占的,并不是在内核的任何执行过程中都能被抢占。你见过哪一个实时操作系统可以在任何时候可以被抢占吗?VxWorks有一个kernel state,一旦进入这个状态任何抢占后最终也需要在kernel state执行的操作都会被挂在一个work queue中,最终串行地执行。
我找到可能的原因了,在单核上面获取自旋锁一般就是关调度,这个时候其他进程就没法抢占了,所以死机.
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 编辑 ]
对的 2.6肯定是可以抢占的
但是自旋锁是不可中断的