博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

Linux & Technology

邻窝 - http://muddoghole.spaces.live.com/
  muddogxp.cublog.cn

关于作者
姓名:muddog
职业:linux programer
年龄:24
位置:Suzhou
个性介绍:
|| << >> ||
我的分类


ioctl 的原子性
 
ioctl在linux系统中属于原子操作, 实际就是带锁的操作.
在写内核或驱动时,使用ioctl和应用层交互要比/proc来得安全的多.
以下是对ioctl原子性的代码分析:

1) do_ioctl, 用户层调用ioctl都会陷入到这里.

static long do_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int error = -ENOTTY;

if (!filp->f_op)
goto out;

/**
* kernel 里有unlocked ioctl, 不加锁的ioctl,
* kernel 会先check file_operations 里是否有不加锁ioctl,
* 有则优先调用
*/
if (filp->f_op->unlocked_ioctl) {
error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
if (error == -ENOIOCTLCMD)
error = -EINVAL;
goto out;
} else if (filp->f_op->ioctl) {
/* 一般情况调用到这里: */
/* lock_kernel 调用ioctl之前加锁 */
lock_kernel();
/* 调用ioctl */
error = filp->f_op->ioctl(filp->f_dentry->d_inode,
filp, cmd, arg);
/* 解锁 */
unlock_kernel();
}

out:
return error;
}

2) lock_kernel 看看如何加锁

static inline void __lock_kernel(void)
{
/**
* 禁止内核抢占, 实际上是增加当前线程结构中的
* 抢占记数
current_thread_info()->preempt_count
* 不一定能真正disable preempt
*/

preempt_disable();
if (unlikely(!_raw_spin_trylock(&kernel_flag))) {
/*
* If preemption was disabled even before this
* was called, there's nothing we can be polite
* about - just spin.
*/
/**
* 如果获得spin lock失败, 则检查抢占记数,
* 如果抢占被禁止, 则直接等待对kernel_flag加锁
*/
if (preempt_count() > 1) {
_raw_spin_lock(&kernel_flag);
return;
}

/*
* Otherwise, let's wait for the kernel lock
* with preemption enabled..
*/

/**
* 如果抢占未被禁止, 则减少抢占记数, 使能抢占,
* 等待kernel_flag锁被释放. 不过这里的等待可以被抢占
* 释放CPU给其他内核路径
*/
do {
preempt_enable();
while (spin_is_locked(&kernel_flag))
cpu_relax(); /* 可以被抢占 */
preempt_disable();
} while (!_raw_spin_trylock(&kernel_flag));
}
}

发表于: 2006-12-19,修改于: 2006-12-19 21:36,已浏览646次,有评论0条 推荐 投诉


网友评论
 发表评论