Debesh Mohanty
Debesh Mohanty

Reputation: 489

Manual sleep in char driver halts read() forever

I am learning linux device drivers. I came across a topic 'manual sleep'. So I wrote a simple char driver in which the read method will sleep if no data is written into the buffer

The problem is the read method sleeps forever even if data has been written

What can be the possible error in the code? Thanks in advance for any help.

the code snippets from the char driver are

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

The complete code for user-space app is

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

Upvotes: 1

Views: 127

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 65936

Functions prepare_to_wait and finish_wait are part of single wait.

They are not wait() and notify() analogues of high-level languages such as java.

More correct waiting implementation could be:

// 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);

Note, that this is not a fully correct example: at least, flag should be checked and set under some critical section, e.g. with spinlock held. But it just works in your simple scenario.

Alternatively, you may use completion:

// Global scope
#include <linux/completion.h>
DECLARE_COMPLETION(comp);

// myread
wait_for_completion_interruptible(&comp);

// mywrite
complete(&comp);

In this case completion will be automatically rearmed after waiting.

Upvotes: 1

Related Questions