正在学习用户态线程和内核态定时器的使用,有个问题请教大家:
我在用户空间建立了一个线程,内核做一个字符驱动模块,通过ioctl调用来不断读取内核定时器有没有
到期。在设备结构体里面加了一个信号量,在open调用的时候把信号量拿到,使用一个内核定时器,在内
核定时器到期的处理函数里面释放信号量,这样用户线程调ioctl的时候就获取不到信号量了,等定时器
超时了,就会释放信号量,这样ioctl就返回到用户空间了,可是下次再调用ioctl的时候就不等待信号量了,不知道为什么??
不知道这样做行不行,看书上好像都是两个内核线程间用信号量来通信,请大家指教,谢谢!
void timer_handle(void)
{
int i = 0;
mod_timer(&KDA_devp->s_timer,jiffies + HZ * 5); /*重新改变定时器的超时时间*/
up(&KDA_devp->sem); /*释放信号量,ioctl调用可以获取到该信号量*/
}
int KDA_open(struct inode *inode, struct file *filp)
{
struct KDA_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct KDA_dev, cdev);
filp->private_data = dev; /* for other methods */
init_timer(&KDA_devp->s_timer);
KDA_devp->s_timer.function = &timer_handle;
KDA_devp->s_timer.expires = jiffies + HZ * 5;
add_timer(&KDA_devp->s_timer); /*添加(注册)定时器*/
down_interruptible(&dev->sem); /*获取信号量*/
return 0;
}
int KDA_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int err = 0;
int isr_num = 100;
struct KDA_dev *dev = filp->private_data;
printk("want to get sem \n");
down_interruptible(&dev->sem);
switch(cmd)
{
case 1 :
printk("the case 1 \n");
break;
case 2 :
printk("the case 2 \n");
break;
case 3 :
__put_user(KDA_devp->ISR_flag, (int __user *)arg);
break;
default:
printk("the default case \n");
}
}
6 个解决方案
#1
我个人觉得你这样做应该能实现你要的效果,但是逻辑上有点问题,理由如下:
1、信号量适用于进程间通信,而你这里实际上只有一个进程,即用户态创建的进程(你写成了线程)。这个进程和内核之间进行通过驱动接口进行数据交流,这个过程中并没有引入新的进程。其实简单化来看:这个模型的工作就是在进程里面先down()了一下,然后再up()一下,在down和up这段时间间隔内,轮询的查看信号量是否可用。但是信号量的真正作用确是用于进程间的通信,所以说你的效果应该能实现,但是逻辑上有点问题。
2、再分析下你这个模型,轮询的查看,这个很浪费CPU的资源。而根据你的设计,似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程:我完事了,到你了。这时候用户态的进程再执行其他的操作。这样似乎效率更高一些。逻辑上也合理一些。
以上只是个人分析,未必全面,欢迎拍砖。
PS:这个确实是个挺不错的问题!
1、信号量适用于进程间通信,而你这里实际上只有一个进程,即用户态创建的进程(你写成了线程)。这个进程和内核之间进行通过驱动接口进行数据交流,这个过程中并没有引入新的进程。其实简单化来看:这个模型的工作就是在进程里面先down()了一下,然后再up()一下,在down和up这段时间间隔内,轮询的查看信号量是否可用。但是信号量的真正作用确是用于进程间的通信,所以说你的效果应该能实现,但是逻辑上有点问题。
2、再分析下你这个模型,轮询的查看,这个很浪费CPU的资源。而根据你的设计,似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程:我完事了,到你了。这时候用户态的进程再执行其他的操作。这样似乎效率更高一些。逻辑上也合理一些。
以上只是个人分析,未必全面,欢迎拍砖。
PS:这个确实是个挺不错的问题!
#2
一般性思路: 应用程序调用驱动,通常在驱动里加入同步机制,例如用信号量加条件变量。
有数据需要应用程序处理时,驱动就唤醒应用程序,否则使应用程序睡眠(挂起)。这种异步的做法比较节省资源,比应用程序轮询高效得多。
有数据需要应用程序处理时,驱动就唤醒应用程序,否则使应用程序睡眠(挂起)。这种异步的做法比较节省资源,比应用程序轮询高效得多。
#3
谢谢大家的回复,学习ing!
轮询确实很耗CPU,如果使用应用程序调用驱动的时候,要是不满足情况,应用程序就阻塞睡眠,等条件满足了,就由驱动唤醒应用程序,这样就比较好了。
要实现这个驱动唤醒应用程序,我需要看那些资料或者什么思路实现啊,谢谢大家!
轮询确实很耗CPU,如果使用应用程序调用驱动的时候,要是不满足情况,应用程序就阻塞睡眠,等条件满足了,就由驱动唤醒应用程序,这样就比较好了。
要实现这个驱动唤醒应用程序,我需要看那些资料或者什么思路实现啊,谢谢大家!
#5
我看了Ldd3 里面的一个阻塞IO的例子:
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_event_interruptible(wq, flag != 0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
“似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程。”
这个是这个意思吗,呵呵,不太懂,请指教!
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
flag = 1;
wake_up_interruptible(&wq);
return count; /* succeed, to avoid retrial */
}
是不是使用这样的例子,在内核定时器的超时处理函数里面来唤醒wake_up_interruptible(&wq);这个就可以实现驱动通知应用程序了啊?
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_event_interruptible(wq, flag != 0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
“似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程。”
这个是这个意思吗,呵呵,不太懂,请指教!
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
flag = 1;
wake_up_interruptible(&wq);
return count; /* succeed, to avoid retrial */
}
是不是使用这样的例子,在内核定时器的超时处理函数里面来唤醒wake_up_interruptible(&wq);这个就可以实现驱动通知应用程序了啊?
#6
谢谢fetag和wenxy1的回复,看了wenxy1程序,有看了Ldd3中阻塞IO的部分,现在可以实现在用户态调用就阻塞,等定时器到了,就让用户态醒来的功能了,谢谢大家,结贴给分!
#1
我个人觉得你这样做应该能实现你要的效果,但是逻辑上有点问题,理由如下:
1、信号量适用于进程间通信,而你这里实际上只有一个进程,即用户态创建的进程(你写成了线程)。这个进程和内核之间进行通过驱动接口进行数据交流,这个过程中并没有引入新的进程。其实简单化来看:这个模型的工作就是在进程里面先down()了一下,然后再up()一下,在down和up这段时间间隔内,轮询的查看信号量是否可用。但是信号量的真正作用确是用于进程间的通信,所以说你的效果应该能实现,但是逻辑上有点问题。
2、再分析下你这个模型,轮询的查看,这个很浪费CPU的资源。而根据你的设计,似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程:我完事了,到你了。这时候用户态的进程再执行其他的操作。这样似乎效率更高一些。逻辑上也合理一些。
以上只是个人分析,未必全面,欢迎拍砖。
PS:这个确实是个挺不错的问题!
1、信号量适用于进程间通信,而你这里实际上只有一个进程,即用户态创建的进程(你写成了线程)。这个进程和内核之间进行通过驱动接口进行数据交流,这个过程中并没有引入新的进程。其实简单化来看:这个模型的工作就是在进程里面先down()了一下,然后再up()一下,在down和up这段时间间隔内,轮询的查看信号量是否可用。但是信号量的真正作用确是用于进程间的通信,所以说你的效果应该能实现,但是逻辑上有点问题。
2、再分析下你这个模型,轮询的查看,这个很浪费CPU的资源。而根据你的设计,似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程:我完事了,到你了。这时候用户态的进程再执行其他的操作。这样似乎效率更高一些。逻辑上也合理一些。
以上只是个人分析,未必全面,欢迎拍砖。
PS:这个确实是个挺不错的问题!
#2
一般性思路: 应用程序调用驱动,通常在驱动里加入同步机制,例如用信号量加条件变量。
有数据需要应用程序处理时,驱动就唤醒应用程序,否则使应用程序睡眠(挂起)。这种异步的做法比较节省资源,比应用程序轮询高效得多。
有数据需要应用程序处理时,驱动就唤醒应用程序,否则使应用程序睡眠(挂起)。这种异步的做法比较节省资源,比应用程序轮询高效得多。
#3
谢谢大家的回复,学习ing!
轮询确实很耗CPU,如果使用应用程序调用驱动的时候,要是不满足情况,应用程序就阻塞睡眠,等条件满足了,就由驱动唤醒应用程序,这样就比较好了。
要实现这个驱动唤醒应用程序,我需要看那些资料或者什么思路实现啊,谢谢大家!
轮询确实很耗CPU,如果使用应用程序调用驱动的时候,要是不满足情况,应用程序就阻塞睡眠,等条件满足了,就由驱动唤醒应用程序,这样就比较好了。
要实现这个驱动唤醒应用程序,我需要看那些资料或者什么思路实现啊,谢谢大家!
#4
看看我去年写的一个手机平台,MP3编解码驱动:
http://blog.csdn.net/wenxy1/archive/2008/10/30/3182116.aspx
这个,主要看你的悟性了。
这个,主要看你的悟性了。
#5
我看了Ldd3 里面的一个阻塞IO的例子:
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_event_interruptible(wq, flag != 0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
“似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程。”
这个是这个意思吗,呵呵,不太懂,请指教!
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
flag = 1;
wake_up_interruptible(&wq);
return count; /* succeed, to avoid retrial */
}
是不是使用这样的例子,在内核定时器的超时处理函数里面来唤醒wake_up_interruptible(&wq);这个就可以实现驱动通知应用程序了啊?
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_event_interruptible(wq, flag != 0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
“似乎用condition更合适一些。即先down()一下,然后用户态的进程就在那里阻塞着,什么时候定时器超时了,这个时候再产生一个condition,通知用户态的进程。”
这个是这个意思吗,呵呵,不太懂,请指教!
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
flag = 1;
wake_up_interruptible(&wq);
return count; /* succeed, to avoid retrial */
}
是不是使用这样的例子,在内核定时器的超时处理函数里面来唤醒wake_up_interruptible(&wq);这个就可以实现驱动通知应用程序了啊?
#6
谢谢fetag和wenxy1的回复,看了wenxy1程序,有看了Ldd3中阻塞IO的部分,现在可以实现在用户态调用就阻塞,等定时器到了,就让用户态醒来的功能了,谢谢大家,结贴给分!