字符驱动程序中的手动睡眠会永远停止 read()
Manual sleep in char driver halts read() forever
我正在学习 linux 设备驱动程序。我遇到了一个话题 'manual sleep'。所以我写了一个简单的字符驱动程序,如果没有数据写入缓冲区,读取方法将休眠
问题是读取方法永远休眠,即使数据已经写入
代码中可能存在的错误是什么?
在此先感谢您的帮助。
字符驱动程序的代码片段是
wait_queue_head_t q;
wait_queue_t wait;
int major_no, flag=0;
char device_buffer[100];
ssize_t myread(struct file *p, char __user *buf, size_t len, loff_t *s)
{
printk(KERN_ALERT "myread() method\n");
prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
if(flag!=1)
{
schedule();
}
copy_to_user(buf, device_buffer, strlen(device_buffer));
flag=0;
return 0;
}
ssize_t mywrite(struct file *p, const char __user *buf, size_t len, loff_t *s)
{
printk(KERN_ALERT "mywrite() method\n");
memset(device_buffer, 0, 100);
copy_from_user(device_buffer, buf, len);
flag=1;
finish_wait(&q, &wait);
printk("%s", device_buffer);
return 0;
}
struct file_operations p={
.open=myopen,
.release=myclose,
.write=mywrite,
.read=myread
};
int start(void)
{
printk(KERN_ALERT "module registered\n");
memset(device_buffer, 0, 100);
major_no=register_chrdev(0, "mydriver", &p);
printk(KERN_ALERT "driver major no : %d\n", major_no);
init_waitqueue_head(&q);
init_wait(&wait);
return 0;
}
user-space 应用程序的完整代码是
#include<fcntl.h>
main()
{
char option, m[100];
memset(m, 0, 100);
int fd=open("my_dev_file", O_RDWR);
printf("%d\n", fd);
printf("read : r\nwrite : w\n");
scanf("%c", &option);
switch(option)
{
case 'w':
printf("msg : ");
scanf("%s", m);
write(fd, m, strlen(m));
break;
case 'r':
read(fd, m, 100);
printf("msg = %s\n", m);
break;
default:
printf("wrong choice\n");
}
return 0;
}
函数 prepare_to_wait
和 finish_wait
是单个 wait.
的一部分
它们 不是 wait()
和 notify()
high-level 语言的类似物,例如 java.
更正确的等待实现可能是:
// Global scope: no need to declare `wait`, it will be locally declared in *myread*
// myread
DEFINE_WAIT(wait); // this is a *declaration*, so it should come before function's call like `printk`.
prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
if(flag!=1)
{
schedule();
}
finish_wait(&q, &wait); // This is *finalization* for waiting
...
// mywrite
flag = 1;
wake_up(&q);
请注意,这不是一个完全正确的示例:至少,flag
应该检查并设置在某些关键部分下,例如持有自旋锁。但它只适用于您的简单场景。
或者,您可以使用 完成:
// Global scope
#include <linux/completion.h>
DECLARE_COMPLETION(comp);
// myread
wait_for_completion_interruptible(&comp);
// mywrite
complete(&comp);
在这种情况下,等待完成后会自动重新武装。
我正在学习 linux 设备驱动程序。我遇到了一个话题 'manual sleep'。所以我写了一个简单的字符驱动程序,如果没有数据写入缓冲区,读取方法将休眠
问题是读取方法永远休眠,即使数据已经写入
代码中可能存在的错误是什么? 在此先感谢您的帮助。
字符驱动程序的代码片段是
wait_queue_head_t q;
wait_queue_t wait;
int major_no, flag=0;
char device_buffer[100];
ssize_t myread(struct file *p, char __user *buf, size_t len, loff_t *s)
{
printk(KERN_ALERT "myread() method\n");
prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
if(flag!=1)
{
schedule();
}
copy_to_user(buf, device_buffer, strlen(device_buffer));
flag=0;
return 0;
}
ssize_t mywrite(struct file *p, const char __user *buf, size_t len, loff_t *s)
{
printk(KERN_ALERT "mywrite() method\n");
memset(device_buffer, 0, 100);
copy_from_user(device_buffer, buf, len);
flag=1;
finish_wait(&q, &wait);
printk("%s", device_buffer);
return 0;
}
struct file_operations p={
.open=myopen,
.release=myclose,
.write=mywrite,
.read=myread
};
int start(void)
{
printk(KERN_ALERT "module registered\n");
memset(device_buffer, 0, 100);
major_no=register_chrdev(0, "mydriver", &p);
printk(KERN_ALERT "driver major no : %d\n", major_no);
init_waitqueue_head(&q);
init_wait(&wait);
return 0;
}
user-space 应用程序的完整代码是
#include<fcntl.h>
main()
{
char option, m[100];
memset(m, 0, 100);
int fd=open("my_dev_file", O_RDWR);
printf("%d\n", fd);
printf("read : r\nwrite : w\n");
scanf("%c", &option);
switch(option)
{
case 'w':
printf("msg : ");
scanf("%s", m);
write(fd, m, strlen(m));
break;
case 'r':
read(fd, m, 100);
printf("msg = %s\n", m);
break;
default:
printf("wrong choice\n");
}
return 0;
}
函数 prepare_to_wait
和 finish_wait
是单个 wait.
它们 不是 wait()
和 notify()
high-level 语言的类似物,例如 java.
更正确的等待实现可能是:
// Global scope: no need to declare `wait`, it will be locally declared in *myread*
// myread
DEFINE_WAIT(wait); // this is a *declaration*, so it should come before function's call like `printk`.
prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
if(flag!=1)
{
schedule();
}
finish_wait(&q, &wait); // This is *finalization* for waiting
...
// mywrite
flag = 1;
wake_up(&q);
请注意,这不是一个完全正确的示例:至少,flag
应该检查并设置在某些关键部分下,例如持有自旋锁。但它只适用于您的简单场景。
或者,您可以使用 完成:
// Global scope
#include <linux/completion.h>
DECLARE_COMPLETION(comp);
// myread
wait_for_completion_interruptible(&comp);
// mywrite
complete(&comp);
在这种情况下,等待完成后会自动重新武装。