让Qt得知来自硬件的中断

我的项目中,Linux驱动程序含有中断,而中断处理程序需要在GUI中处理(或者至少一部分是),我使用的是Qt,本来想能否让驱动程序像在Qt程序中一样emit 一个signal,但发现这太难实现了,因为我还不知道如何在Qt之外使用MetaObject或moc这类玩意。问了一下Qt群,Q胖说Qt是平台无关的,应该像没有Qt时一样处理。虽然听的我一头雾水,但仔细一想也大受启发,对呀,Linux下有那么多进程间通信的方法,为什么不用啊,可以在驱动程序的中断程序中用信号产生一个软件中断,唤醒Qt中的服务程序呀。虽然这可能不太及时,但满足GUI来讲应该绰绰有余。(先注明一下,本人菜鸟,说的不一定正确,试验可以,但请勿转载,若有错丢人丢不起)

于是我做了个小试验,让Qt感受到来自外进程的信号,并对其作出反应,让信号处理程序发出QEvent,利用QEvent()异步响应,不就等于将信号引入到Qt程序中了吗?(太繁了点难过)。以下是程序实现,(不好意思,用了ui)
#include <QWidget>
class Widget : public QWidget {
    Q_OBJECT
public:
    Widget(QWidget *parent = 0);
    ~Widget();
protected:
    void changeEvent(QEvent *e);
    void customEvent(QEvent *e);
private:
    Ui::Widget *ui;
};
#include "widget.h"
#include "ui_widget.h"
#include <signal.h>
#include <iostream>
#define SIGMINE 56
QObject* ow;
const QEvent::Type CustomEvent_eint = (QEvent::Type)6666;//建议用5000以上唯一的标识
void eint(int sigNo)
{
    if(sigNo==SIGMINE)
    {
        QCoreApplication::postEvent(ow, new QEvent(CustomEvent_eint)); //用new会不会内存泄漏
        //std::cerr<<"signal received"<<std::endl;
    }
}

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->textEdit->setText(tr("I'm ready"));
    ow=this;
    if(signal(SIGMINE, &eint)==SIG_ERR)
    {
        std::cerr<<"signal install failed"<<std::endl;
    }
}

Widget::~Widget()
{
    delete ui;
}

void Widget::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void Widget::customEvent(QEvent *e)
{
    switch (e->type()) {
    case CustomEvent_eint:
        {
            ui->textEdit->append(tr("I receiveed signal"));

            //delete e;    用不着delete,postevent自己就干了
            break;
        }
    default:
        break;
    }
}
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Widget w;

    w.show();

    return a.exec();
}
编译完后在终端运行,例如
./try_signal &
[2229]
向进程发信号
kill -56 2229
在textedit中显示“I receiveed signal”,说明目的达到了大笑


转念一想,Linux不会这么笨吧,难道没有一个现成的机制解决这类一般性问题?
当然有,我翻了一下Linux设备驱动程序的书,书中介绍了一个概念,专门解决这个问题——异步通知。(以下为转载和注释,这是查到的算比较清楚的了)
异步通知的意思是:一旦设备就绪,则主动通知应用程序。异步通知类似于“中断”的机制,而不像之前学的阻塞型I/O和poll。阻塞I/O意味着一直等待设备可访问后再访问,非阻塞I/O使用poll意味着查询设备是否可访问,而异步通知则意味着设备通知自身可访问,实现了异步I/O。
2、应用层中启用异步通知机制的三个步骤
1)调用signal函数,让指定的信号SIGIO与处理函数sig_handler对应。
signal(SIGIO, sig_handler);
2)指定一个进程作为文件的“属主(filp->owner)”,这样内核才知道信号要发给哪个进程。
fcntl(fd, F_SET_OWN, getpid());
3)在设备文件中添加FASYNC标志,即异步通知模式。
f_flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, f_flags | FASYNC);
    疑惑:2、3两步目的是要调用后面的XXX_fasync(),但这是系统自动实现的还是要我们自己写点什么(例如ioctrl)才能实现?
    注:查了一下,需要在驱动程序的fops结构中指定fcntl:XXX_fasync。
3、驱动中需要实现的异步通知
驱动中的3项工作和应用程序中的3项工作是一一对应的。
内核已经实现了两步,我们要实现一个简单的传参。由于FASYNC标志改变时,驱动程序中的fasync()函数得以执行,故在驱动中要实现fasync()函数。
1)定义结构体fasync_struct。
struct fasync_struct *async_queue;//异步结构体指针
2)实现XXX_fasync,把函数fasync_helper,fd,filp和定义的结构体传给内核。
int XXX_fasync (int fd, struct file *filp, int mode)
{
struct XXX_dev *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
3)当设备可写时,调用函数kill_fasync发送信号SIGIO给内核。
if (dev->async_queue){
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
}
4)当设备关闭时,需要将fasync_struct从异步队列中删除:
XXX_fasync(-1, filp, 0);
    疑惑:1中的定义是否应该写在device的struct里?不然怎么会有dev->async_queue?
        3中的kill_fasync是我改的,原文是XXX_fasync,但我实在是不能理解,到底那个对?
        4中的-1和0是什么意思,-1表示当前fd?,0表示删除?
    注:疑惑1已经证实。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值