【发布时间】:2015-04-22 13:46:14
【问题描述】:
我正在开发一个基于字符设备驱动程序的示例 Linux 模块(使用 misc 驱动程序以方便使用),我发现了一些不寻常的行为。
我有文件操作的打开、读取、写入和释放功能,我的杂项设备被命名为test_device
我的设备有一个环形缓冲区,可以存储来自写入系统调用的数据,而读取系统调用可以读取数据。如果缓冲区已满,则调用 write 系统调用的进程将休眠,如果缓冲区为空,则调用 read 系统调用的进程将休眠。
有一个信号量(计数为 1,如互斥锁)以避免多次读取,从而避免出现竞争条件。这对于单个读取和单个写入过程来说效果很好,没有任何问题
现在我使用命令将设备作为 2 个读取实例打开
cat /dev/test_device
正如预期的那样,第二个 cat 进程休眠了。我只有一个进程要写
ls > /dev/test_device
ls 命令甚至不调用 open 系统调用。谁能解释一下 open 系统调用失败的原因。
代码如下
static int hr_open(struct inode *inode, struct file *file)
{
pr_info("process %i (%s) enters open\n", current->pid, current->comm);
if (file->f_mode & FMODE_READ) down_interruptible(&rd_sem);
pr_info("process %i (%s) leaves open\n", current->pid, current->comm);
return 0;
}
static int hr_release(struct inode *inode, struct file *file)
{
pr_info("process %i (%s) enters release\n", current->pid, current->comm);
if (file->f_mode & FMODE_READ) up(&rd_sem);
pr_info("process %i (%s) leaves release\n", current->pid, current->comm);
return 0;
}
static ssize_t hr_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
pr_info("process %i (%s) enters read\n", current->pid, current->comm);
if (wait_event_interruptible(wq_rd, head != tail))
return -ERESTARTSYS;
if (put_user(buff[head], buffer))
return -EFAULT;
head = (head + 1) % BUFF_SIZE;
wake_up_interruptible(&wq_wr);
pr_info("process %i (%s) leaves read\n", current->pid, current->comm);
return 1;
}
static ssize_t hr_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
pr_info("process %i (%s) enters write\n", current->pid, current->comm);
if (wait_event_interruptible(wq_wr, tail != ((head + 1) % BUFF_SIZE)))
return -ERESTARTSYS;
if (get_user(buff[tail], buffer))
return -EFAULT;
tail = (tail + 1) % BUFF_SIZE;
wake_up_interruptible(&wq_rd);
pr_info("process %i (%s) leaves write\n", current->pid, current->comm);
return 1;
}
【问题讨论】:
-
如果你执行 "ls >/dev/test_device" 你不应该期望 ls 会打开你的设备。外壳会打开它;这就是'>'的作用。如果您确实遇到了开放式故障,那么包含 errno 会很有帮助。
-
我也使用程序来做到这一点。我有一个程序位于 while 循环中,直到我得到一些数据并且效果相同
-
创建一个简单的程序...像这样。 main() { int fd = open("/dev/test_device", O_WRONLY);如果 (fd >= 0) 写(fd, "FOO", 3); } 在 strace 下运行它,发现系统调用接口发生了什么。那么这里的人会更好地帮助你。
-
我创建了一个程序来从设备读取并运行相同的 2 个实例。第一个实例在读取时休眠,并按预期等待数据 17:30:15.967809 open("/dev/test_dev", O_RDONLY) = 3 17:30:15.967840 read(3, 第二个实例在信号量等待获取它 17:30:30.405666 open("/dev/test_dev", O_RDONLY 现在我使用命令 strace -ttT echo test>/dev/test_device 进行写入,并且 strace 没有输出。
标签: linux linux-kernel