char驱动程序中的手动睡眠会永久停止read()

时间:2015-12-31 06:52:52

标签: c linux linux-kernel operating-system kernel-module

我正在学习linux设备驱动程序。我遇到了一个话题“手动睡眠”。所以我写了一个简单的char驱动程序,如果没有数据写入缓冲区,read方法将会休眠

问题是即使已写入数据,read方法也会永远休眠

代码中可能出现的错误是什么? 提前感谢您的帮助。

来自char驱动程序的代码片段是

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;
}

用户空间应用的完整代码是

#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;
}

1 个答案:

答案 0 :(得分:1)

函数prepare_to_waitfinish_wait 是单个等待 的一部分。

他们不是 wait()notify()高级语言的类似物,例如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);

在这种情况下,完成将在等待后自动重新启动。