Reputation: 489
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
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