解析Linux内核的同步与互斥机制(三)
来源:互联网 发布:java软件系统技术合同 编辑:程序博客网 时间:2024/04/30 19:14
源出处:http://www.startos.com/linux/tips/2011011921499_3.html
在决定调用sleep_on系列函数到真正调用schedule系列函数期间,若等待的条件为真,若此时继续schedule,相当于丢失了一次唤醒机会。因此sleep_on系列函数会引入竞态,导致系统的不安全。
另外对于interruptible系列函数,其返回时并不能确定是因为资源可用返回还是遇到了signal,因此在程序中用户需要再次判断资源是否可用。如:
static ssize_t at91_mcp2510_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
CanData candata_ret;
retry:
if (mcp2510dev.nCanReadpos != mcp2510dev.nCanRevpos) {// 需求的资源
int count;
count = MCP2510_RevRead(&candata_ret);
if (count) copy_to_user(buffer, (char *)&candata_ret, count);
return count;
} else { //不可用
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
interruptible_sleep_on(&(mcp2510dev.wq));
if (signal_pending(current)) // 遇到信号,返回
return -ERESTARTSYS;
goto retry; //重新判断资源是否可用
}
DPRINTK("read data size=%d\n", sizeof(candata_ret));
return sizeof(candata_ret);
}
综合上述两个因素,sleep_on系列函数应避免在驱动程序中出现,未来的2.7版内核中将删除此类函数。
2.3 等待队列的接口
2.3.1 初始化等待队列
#define DEFINE_WAIT(name) \
wait_queue_t name = { \
.private = current, \
.func = autoremove_wake_function, \
.task_list = LIST_HEAD_INIT((name).task_list), \
}
#define init_wait(wait) \
do { \
(wait)->private = current; \
(wait)->func = autoremove_wake_function; \
INIT_LIST_HEAD(&(wait)->task_list); \
} while (0)
专用的初始化等待队列函数,将当前进程添加到等待队列中,注意和通用的接口 DECLARE_WAITQUEUE及init_waitqueue_entry区别。同时唤醒处理不一样,autoremove_wake_function在default_wake_function的基础之上,将当前进程从等待队列中删除。
2.3.2 添加或从等待队列中删除
添加删除的原始接口
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
list_add(&new->task_list, &head->task_list);
}
static inline void __add_wait_queue_tail(wait_queue_head_t *head,
wait_queue_t *new)
{
list_add_tail(&new->task_list, &head->task_list);
}
static inline void __remove_wait_queue(wait_queue_head_t *head,
wait_queue_t *old)
{
list_del(&old->task_list);
}
等待队列是公用资源,但上述接口没有加任何保护措施,适用于已经获得锁的情况下使用。
带锁并设置属性的添加删除
void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
wait->flags &= ~WQ_FLAG_EXCLUSIVE;
spin_lock_irqsave(&q->lock, flags);
__add_wait_queue(q, wait);
spin_unlock_irqrestore(&q->lock, flags);
}
EXPORT_SYMBOL(add_wait_queue);
void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
wait->flags |= WQ_FLAG_EXCLUSIVE;
spin_lock_irqsave(&q->lock, flags);
__add_wait_queue_tail(q, wait);
spin_unlock_irqrestore(&q->lock, flags);
}
EXPORT_SYMBOL(add_wait_queue_exclusive);
void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
__remove_wait_queue(q, wait);
spin_unlock_irqrestore(&q->lock, flags);
}
EXPORT_SYMBOL(remove_wait_queue);
此三对函数的特点是调用同名的内部函数,同时添加一些保障安全特性的代码。WQ_FLAG_EXCLUSIVE属性的进程添加到队尾,而非 WQ_FLAG_EXCLUSIVE从队头添加。这样可以保证每次都能唤醒所有的非WQ_FLAG_EXCLUSIVE进程。
无锁但设置属性的添加删除
static inline void add_wait_queue_exclusive_locked(wait_queue_head_t *q,
wait_queue_t * wait)
{
wait->flags |= WQ_FLAG_EXCLUSIVE;
__add_wait_queue_tail(q, wait);
}
/* Must be called with the spinlock in the wait_queue_head_t held.*/
static inline void remove_wait_queue_locked(wait_queue_head_t *q,
wait_queue_t * wait)
{
__remove_wait_queue(q, wait);
}
Locked系列适用于在已经获得锁的情况下调用,通常用于信号量后者complete系列函数中。
上述三组函数,__add_wait_queue是内部函数,无任何保护,无任何属性设置;而另外两组分别适用于当前是否加锁的两种场合,是对外的接口函数。这种根据适用场合不同提供不同的接口函数的方法值得借鉴。
- 解析Linux内核的同步与互斥机制(三)
- 全面解析Linux内核的同步与互斥机制
- 解析Linux内核的同步与互斥机制(一)
- 解析Linux内核的同步与互斥机制(二)
- 解析Linux内核的同步与互斥机制(四)
- 解析Linux内核的同步与互斥机制(五)
- 解析Linux内核的同步与互斥机制(六)
- 解析Linux内核的同步与互斥机制(七)
- 全面解析Linux内核的同步与互斥机制--同步篇
- 全面解析Linux内核的同步与互斥机制--同步篇 收藏
- 全面解析Linux内核的同步与互斥机制--同步篇(转)
- 全面解析Linux内核的同步与互斥机制--同步篇
- 全面解析Linux内核的同步与互斥机制--同步篇
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】全面解析Linux内核的同步与互斥机制--同步篇
- Linux内核中的互斥与同步机制
- Linux内核同步与互斥--锁机制
- Linux内核中的互斥与同步机制
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】全面解析Linux内核的同步与互斥机制--互斥篇
- 解析Linux内核的同步与互斥机制(二)
- C++函数学习(五)
- <最快速度找到内存泄漏> <Visual Leak Detector 2.2.3 Visual C++内存检测工具 >
- 黑马程序员--asp.net有关如何批量上传图片
- /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory问题
- 解析Linux内核的同步与互斥机制(三)
- 钩子的使用
- ASP提示
- 解析Linux内核的同步与互斥机制(四)
- JDBC连接数据库
- 工具的使用
- 【linux文件操作】文件备份/文件移动/文件改名
- javascript延迟使用方法
- 解析Linux内核的同步与互斥机制(五)