qnx 设备驱动开发_QNX资源管理器

资源管理器(resource manager)应该是QNX编程中最常用的,如果没写过几个资源管理器,大概都不好意思说自已做过QNX编程。唯其重要,QNX也有很多官方文档解释。这篇文章详细解释了QNX资源管理器的基本设计,管理器框架,并辅以代码。希望能够帮助读者掌握QNX上的资源管理器,从而更容易地搭建系统。

文章里提到的资源管理器示例,完整代码可以在这个链接里找到。

什么是资源管理器

资源管理器顾名思义就是管理“资源”的服务器,这里问题是,到底什么是“资源”呢?在QNX上,“资源”可以是一个硬件(硬件资源管理器其实就是我们常说的硬件驱动),“资源”也可以是一种服务,比如TCPIP网络服务,或者ntfs文件系统服务;“资源”甚至可以是一个文件(或者目录)。

如果你还记得,Unix的基本思想,就是“把驱动当成文件”,那资源管理器就非常有用了。所以/dev/ser1是一个管理串口的资源管理器,而/dev/random则是一个提供随机数的资源管理器。甚至传统Unix里那些mount point,像是根目录 /,或者用户目录 /home在QNX里也可以是一个个资源管理器。

好,show me the code,假设我们要写一个md5的资源管理器, 要怎么办呢?md5是这样一个服务,假设客户端传给它一串数据, 它计算md5值, 然后让客户端来取。

一个最基本的资源管理器

一个资源管理器基本上来说就是一个服务器。只要看过《从API开始理解QNX》那篇的同学应该很容易就可以想到最基本的资源管理器,应该就是下面这样的:

(这里只是示意代码,完整的可以在QNX上编译运行的代码可以在GitHub上找到)

#define MD5_SEND_DATA   0x00000001
#define MD5_RECV_DIGEST 0x00000002
 
typedef struct {
    int msgtype;
    int msglen;
} md5_msg_t;
 
name_attach(...);
for (;;){
    revid = MsgReceive(chid, &msg, sizeof(msg), &info);
    switch msg.msgtype {
    case MD_SEND_DATA:
        MsgRead(rcvid, ...);      
        ....
        MsgReply(rcvid, ...);
        break;
    case MD_RECV_DIGEST :
        ....
        MsgReply(rcvid, …)
        break;
    }
}

对的, 就是一个循环不断收信息, 然后按定好的信息类型进行处理就好了。客户端要怎样获取这个服务呢?

int md5_send(int fd, unsigned char *data, int len)
{
    
    md5_msg_t msg;
    iov_t iov[2];
 
    msg.msgtype = MD5_SEND_DATA;
    msg.msglen = len;
    SETIOV(&iov[0], &msg, sizeof(msg));
    SETIOV(&iov[1], data, len);
    return MsgSendv(fd, iov, 2, 0, 0);
}
 
int md5_recv(int fd, unsigned char *digest, int len)
{
    
    md5_msg_t msg;
 
    if (len < 16) {
    
        errno = EINVAL;
        return -1;
    }
 
    msg.msgtype = MD5_RECV_DIGEST;
    msg.msglen = len;
    return MsgSend(fd, &msg, sizeof(msg), digest, len);
}

当然做为一个资源管理器的开发者, 你会把md5_send(), md5_recv() 函数打包成一个库,让别人来使用你的服务。

int main(int argc, char **argv)
{
    if ((fd = name_open("md5name", 0)) == -1) {
        perror("name_open");
        return -1;
    }
 
    if ((cfd = open(argv[1], O_RDONLY)) == -1) {
        perror("open");
        return -1;
    }
 
    total = 0;
    for (;;) {
        n = read(cfd, buf, 16 * 1024);
        if (n <= 0)
            break;
 
        if (md5_send(fd, buf, n) <= 0) {
            perror("md5_send");
            return -1;
        }
 
        total += n;
    }
 
    md5_recv(fd, digest, 16);
    printf("%10dttt", total);
    for (n = 0; n < 16; n++) {
        printf(" %02X", digest[n]);
    }
    printf("n");
    return 0;
}

看上去一切都完成了,但是,没有问题吗?

首先这个服务器只能一次处理一个请求,如果有两个程序同时申请这服务时,逻辑上有错误。另外,这个解决方案,意味着每个想要使用这个md5服务的客户端都要链接一个专用的库, 难道没有办法做得通用一点吗?

答案当然是有的。既然md5服务是通过名字来提供服务的,而POSIX对于文件可以进行的操作是有标准定义的呀, 对于我们这个服务, 立刻可以想到的就是客户端可以直接write() 数据到比如 /dev/md5, 然后read() 结果的呀。

那么,资源管理器要怎么做呢,如果客户端write() 时, 我会收到什么信息? QNX已经为你准备好了,这就是,资源管理器框架。

资源管理器框架

因为一个资源管理器都是由一个路经名作为入口的,而POSIX又定义了对一个文件可进行的操作,所以QNX就替大家预定义了这些操作所需要传递的消息类型和数据格式

QNX提供的资源管理器框架大致可以分成4个部份:

  • iofunc (iomsg) 层,这一层提供了所有POSIX对文件可以进行的io操作 (sys/iofuncs.h, sys/iomsg.h)
  • resmgr层,这一层提供了登记路径名,接收数据并分发给iofunc执行具体操作。iofunc 和 resmgr,是写一个资源管理器的基础
  • dispatch层,在一些复杂的资源管理器里,“外来的消息传递”并不是唯一需要处理的。也有可能需要处理“脉冲”,或者有时候一个“信号”。dispatch层会主动识别不同的输入信息,然后转给不同的处理函数进行处理
  • thread pool层,这一层提供了一个线程池管理,可以配置实现多个线程进行资源管理。

下面我们深入地看一下各层

iofunc (iomsg) 层:

QNX总结了总共34个对文件操作,基本上POSIX对文件的处理,都可以通过这34个操作进行。而资源管理器的iofunc层,其实也就是准备回调函数,通过响应这些操作请求,来提供服务。

这34个回调函数,又根据性质不同,被分为8个 “connect" 回调函数,和26个 "io&#

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值