我正在为一些新颖的硬件实现设备驱动程序,并且只允许一个进程一次访问该设备。并发的读/写操作会使硬件混乱,以至于硬重置将很可能需要发生。我仍然有以下问题:
在来自Linux设备驱动程序的示例代码中,open()
调用使用锁,但close()
不使用锁。这里是否还没有竞争条件,还是scull_s_count
保证减少是原子的?基本上,在此示例中,我想知道如果一个进程试图在另一进程结束并关闭设备时正确打开设备会发生什么。
我假设不需要检查and 调用中打开标志的状态(我正在做与示例类似的操作scull_s_count
),因为进入这些调用的唯一方法是如果用户空间应用程序已经接收到在通过成功调用。这个假设正确吗?read()
write()
fd
open()
感谢tadman的评论,我对内核的atomic_t
机制进行了最粗略的搜索。这是我现在拥有的一些伪代码:
int open(struct inode *inode, struct file *filp) {
spin_lock(&lock);
if (atomic_read(&open_flag)) {
spin_unlock(&lock);
return -EBUSY;
}
atomic_set(&open_flag, 1);
/* do other open() related stuff */
spin_unlock(&lock);
return 0;
}
int close(struct inode *inode, struct file *filp) {
int rc;
/* do close() stuff */
atomic_set(&open_flag, 0);
return rc;
}
的open_flag
是atomic_t
,其是与被分配一个较大结构的一部分kzalloc()
。结果,它被初始化为零。
结果,这里的代码表明锁的目的是防止多个进程/线程同时打开设备,而事实是open_flag
则atomic_t
阻止了我在上面问题1中关注的竞争条件。此实现足够吗?另外,我仍在寻找问题2的答案。
示例代码使用自旋锁,但是互斥锁是否更合适?代码段相对较小,几乎没有争用,因此睡眠和唤醒可能比仅旋转有更少的性能。始终从用户上下文访问锁/互斥锁,因此您应该可以安全地睡眠。
您所指向的示例确实存在缺陷。绝对不能保证减量是原子的,几乎可以肯定不会。
但实际上,我认为没有编译器/ CPU组合会产生可能失败的代码。可能发生的最坏情况是,一个CPU内核可以完成关闭,然后另一个内核可以调用open并变得忙碌,因为它具有该标志的过期缓存值。
Linux提供atomic_*
了此功能以及*_bit
原子位标志操作。请参阅内核文档中的core_api / atomic_ops.rst。
一个正确而简单的模式来做一个例子,如下所示:
unsigned long mydriver_flags;
#define IN_USE_BIT 0
static int mydriver_open(struct inode *inode, struct file *filp)
{
if (test_and_set_bit(IN_USE_BIT, &mydriver_flags))
return -EBUSY;
/* continue with open */
return 0;
}
static int mydriver_close(struct inode *inode, struct file *filp)
{
/* do close stuff first */
smp_mb__before_atomic();
clear_bit(IN_USE_BIT, &mydriver_flags);
return 0;
}
对于每个设备,真正的驱动程序应具有设备状态结构mydriver_flags
。而不是像示例中那样为整个驱动程序使用单个全局变量。
也就是说,您尝试做的事情可能不是一个好主意。即使一次只有一个进程可以打开设备,进程的所有线程之间也会共享一个进程的打开文件描述符。多个线程可以同时进行read()
并write()
调用同一文件描述符。
如果某个进程打开了文件描述符并调用fork()
,则该描述符将被继承到新进程中。尽管存在上述“单次打开”限制,但是这是多个进程可以一次打开设备的一种方式。
因此,您仍然必须在驱动程序的文件操作中保持线程安全,因为用户仍然可以有多个线程/进程立即打开设备并进行同时调用。而且,如果您已确保安全,为什么还要阻止用户这样做呢?也许他们知道自己在做什么,并且可以确保驾驶员的多个开门器“轮流”而不打出有冲突的电话?
还请考虑在open调用中使用O_EXCL标志的可能性,以使单个open为可选。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句