qnx之resource manager(二)
来源:互联网 发布:网络产品线是干什么的 编辑:程序博客网 时间:2024/06/13 15:43
qnx之resource manager(二)
学习目的:
- 编写一个简单的resource manager
- 编写connect函数 (io_open())
- 编写I/O函数(io_read(), io_write())
1. 编写一个简单的resource manager
1.1:编写resource manager的总体步骤
1 . 创建和初始化各种结构体
(a dispatch structure, list of conncet message handles, list of I/O message handles, device structure, resource-manager attribute, dispatch context)
2 . 绑定一个路径名,并传递以上参数
3 . 编写一个大循环
(• 阻塞,并等待接收消息;
• 调用相应的处理函数。该处理函数将处理相应的消息并返回给指定的路径)
1.1.1创建和初始化各种结构体
1 . 创建并初始化dpp
dispatch_t *dpp;dpp = dispatch_create();
注:1. dpp是resource manager framework用于控制所有部分的粘合剂,是一个全局变量。 2.该结构体的成员是被隐藏的,不透明的。我们看不到它的内容。
2 . 创建并初始化resource manager attributes
resmgr_attr_t resmgr_attr;memset(&resmgr_attr, 0, sizeof resmgr_attr);resmgr_attr.nparts_max = 1;resmgr_attr.msg_max_size = 2048;
注:该结构体用于设置接收buffer。将通过resmgr_attach传递给resource manager
nparts_max: 用于当使用IOV library时,设置要处理接收buffer 的个数。比如用于MsgReplyv(),该值表示返回的buffer的个数。默认值为1。
msg_max_size: 设置接收buffer的大小。其值一般是 client请求buffer 的最大值。
3 . 初始化操作函数(connect functions和I/O functions 例如: open(filename, …), unlink(filename), read(fd, …), write(fd, …), …)
connection-functions structure 结构体详解:
typedef struct _resmgr_connect_funcs {unsigned nfuncs;int (*open) (/* actual prototype */);int (*unlink) (…);int (*rename) (…);} resmgr_connect_funcs_t;
I/O-functions structure 结构体详解:
如上,有以下成员
nfuncs, read, write, close_ocb,stat, notify, devctl, unblock,pathconf, lseek, chmod, chown,utime, openfd, fdinfo, lock,space, shutdown, mmap, msg,umount, dup, close_dup, lock_ocb,unlock_ocb, sync
声明和初始化connect和I/O函数:
resmgr_connect_funcs_t connect_funcs;resmgr_io_funcs_t io_funcs;iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_funcs,_RESMGR_IO_NFUNCS, &io_funcs);connect_funcs.open = io_open;io_funcs.read = io_read;io_funcs.write = io_write;
4 . 初始化设备属性结构体 device structure iofunc_attr_t
iofunc_attr_t ioattr;iofunc_attr_init (&ioattr, S_IFCHR | 0666, NULL, NULL);
注:这是具体指定设备的数据结构;被 iofunc_*() 类函数使用;可以被扩展,用于包含自己的数据。作为参数传递给resmgr_attach()。
1.1.2 绑定一个路径名,并传递以上参数
1.resmgr_attach()
id = resmgr_attach (dpp, &rattr, path, file_type,flags, &connect_funcs, &io_funcs, handle);
注:
dpp :dispatch_create()返回的指针。
rattr : NULL 或者resmgr_attr_t结构体
path = “/dev/example”
file_type = _FTYPE_ANY; (the usual case)
flags = 0 or control flags…
(_RESMGR_FLAG_BEFORE,_RESMGR_FLAG_AFTER,_RESMGR_FLAG_DIR)
connect_funcs and io_funcs point to the tables of functions
we just created
handle = pointer to device attribues
id = id of this pathname, used for resmgr_detach() call
当多个文件注册到该resource manager时,优先级:BEFORE>non-flagged>AFTER
2 . 分配一个 dispatch context structure
dispatch_context_t *ctp;ctp = dispatch_context_alloc (dpp);
注:这是消息循环的操作参数;传递给阻塞函数和操作函数;它包含了如 rcvid,指向接收buffer和message info structure;将传递给connect and I/O functions的resmgr_context_t *ctp参数。
1.1.3 编写一个大循环
while (1) {ctp = dispatch_block (ctp);dispatch_handler (ctp);}
注:dispatch_block用于等待消息
dispatch_handler用于操作这些消息。包括调用前面的回调函数。(connect function, I/O functions)
总体函数归纳:
#include <errno.h>#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/iofunc.h>#include <sys/dispatch.h>int io_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb);static char *buffer = "Hello world\n";static resmgr_connect_funcs_t connect_funcs;static resmgr_io_funcs_t io_funcs;static iofunc_attr_t attr;int main(int argc, char **argv){ /* declare variables we'll be using */ resmgr_attr_t resmgr_attr; dispatch_t *dpp; dispatch_context_t *ctp; int id; /* initialize dispatch interface */ if((dpp = dispatch_create()) == NULL) { fprintf(stderr, "%s: Unable to allocate dispatch handle.\n", argv[0]); return EXIT_FAILURE; } /* initialize resource manager attributes */ memset(&resmgr_attr, 0, sizeof resmgr_attr); resmgr_attr.nparts_max = 1; resmgr_attr.msg_max_size = 2048; /* initialize functions for handling messages */ iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs, _RESMGR_IO_NFUNCS, &io_funcs); io_funcs.read = io_read; /* initialize attribute structure used by the device */ iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0); attr.nbytes = strlen(buffer)+1; /* attach our device name */ if((id = resmgr_attach(dpp, &resmgr_attr, "/dev/sample", _FTYPE_ANY, 0, &connect_funcs, &io_funcs, &attr)) == -1) { fprintf(stderr, "%s: Unable to attach name.\n", argv[0]); return EXIT_FAILURE; } /* allocate a context structure */ ctp = dispatch_context_alloc(dpp); /* start the resource manager message loop */ while(1) { if((ctp = dispatch_block(ctp)) == NULL) { fprintf(stderr, "block error\n"); return EXIT_FAILURE; } dispatch_handler(ctp); } return EXIT_SUCCESS;}
2. 编写connect函数 (io_open())
2.1 引子:
当客户端使用 /dev/example device时的效果
执行命令:
cat /dev/example
cat命令实际的执行过程:
fd = open(“/dev/example”,O_RDONLY);while (read (fd, buf, BUFSIZ) > 0)/* write buf to stdout */close (fd);
客户端的行为如下:
Communications with the Process Manager
给process manager发送一个query消息:
客户端问:谁负责 /dev/example?
process manager回答:返回一个reply(nd, pid, chid),即返回负责该filename的resource manager的特征。Communications with example
1 . 一个open 消息
(包括: 1. open message“open this device for read”;2. returns a reply, “yes, open succeeded, proceed”; 3. the open() library call returns a file descriptor, fd)。
2 . 一个read消息
(包括: 1.“get me some data“; 2. returns a reply,)。
3 . 一个close消息
图解:
注:在客户端方,所有这些消息的交互均是在c库中完成。如 open(), read(), and close()等。
2.2 io_open()的编写
int io_open (resmgr_context_t *ctp, io_open_t *msg, RESMGR_HANDLE_T *handle, void *extra);
参数解析:
- ctp (实际为dispatch context ctp)
1.指向 resource-manager context structure(dispatch context ctp)
2.关于接收消息的相关信息
3.包含成员
typedef struct _resmgr_context {int rcvid;struct _msg_info info;resmgr_iomsgs_t *msg;unsigned msg_max_size;int status;int offset;IOV iov [1];} resmgr_context_t;
成员解析:rcvid:MsgReceive()函数的返回值,并且会返回给客户端。
info: MsgReceive()返回的message information structure
*msg:the receive buffer;被声明为一个union,以适应所有可能的消息类型。
msg_max_size:被msg指向的receive buffer的大小
status:用于对client的reply
offset: receive buffer的header大小
iov:是由传递给resmgr_attach()的rattr确定。用于多个buffer的reply。
- msg
io_open_t *msg:typedef union{ // contains at least the following struct _io_connect connect;} io_open_t;struct _io_connect{ // contains at least the following uint16_t type; uint32_t mode; char path [1]; // variable length};
- handle (实际为device structure iofunc_attr_t)
用 resmgr_attach()函数初始化的。本例中的iofunc_attr_t被赋值给handle
简单的io_open()函数的框架:
intio_open (resmgr_context_t *ctp, io_open_t *msg,RESMGR_HANDLE_T *handle, void *extra){printf("got an open message\n");return iofunc_open_default (ctp, msg, handle, extra);}
3. 编写I/O函数(io_read(), io_write())
int io_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb);int io_write (resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *ocb);
3.1 ocb的解析
- open contral block
- one ocb per open()
- 维护open()函数和I/O函数的上下文(在例子中是由 iofunc_open_default()分配并初始化,供I/O函数使用。)
- 将也可以是一个iofunc_ocb_t
- iofunc_ocb_t可以添加自己的私有数据。
- 指向已打开的设备的device structure iofunc_attr_t
图解:
3.2 io_read()函数的编写
3.2.1 read消息将由read()函数产生
bytes_read = read( fd, buf, nbytes ){ struct _io_read hdr; hdr.type = _IO_READ; hdr.nbytes = nbytes; ... return( MsgSend( fd, &hdr, sizeof(hdr), buf, nbytes ) );}
3.2.2 接收到的消息
typedef union{ struct _io_read i;} io_read_t;struct _io_read{ // contains at least the following unsigned short type; // message type = _IO_READ long nbytes; // number of bytes to be read uint32_t xtype; // extended type};
注:union可以用于扩展其他消息类型。
3.2.3 the reply 即read()的回应
- 如果read函数指向成功
the reply message将是你读取的数据(并且没有header)
要使得read()函数中的MsgSend()的返回值为成功读取的数据量的大小。需要进行设置。方法如下:
_IO_SET_READ_NBYTES (ctp, nbytes_read);SETIOV (ctp->iov, data, nbytes_read);return _RESMGR_NPARTS(1);
当从the resource manager library返回时,系统将nbytes_read 作为参数传递给MsgReplyv()。然后read()函数将会返回此值。
- 如果失败
return errno_value;
3.2.4 the xtype member
通常为_IO_XTYPE_NONE
具体代码:
intio_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb){ int nleft; int nbytes; int nparts; int status; if ((status = iofunc_read_verify (ctp, msg, ocb, NULL)) != EOK) return (status); if ((msg->i.xtype & _IO_XTYPE_MASK) != _IO_XTYPE_NONE) return (ENOSYS); /* * On all reads (first and subsequent), calculate * how many bytes we can return to the client, * based upon the number of bytes available (nleft) * and the client's buffer size */ nleft = ocb->attr->nbytes - ocb->offset; nbytes = min (msg->i.nbytes, nleft); if (nbytes > 0) { /* set up the return data IOV */ SETIOV (ctp->iov, buffer + ocb->offset, nbytes); /* set up the number of bytes (returned by client's read()) */ _IO_SET_READ_NBYTES (ctp, nbytes); /* * advance the offset by the number of bytes * returned to the client. */ ocb->offset += nbytes; nparts = 1; } else { /* * they've asked for zero bytes or they've already previously * read everything */ _IO_SET_READ_NBYTES (ctp, 0); nparts = 0; } /* mark the access time as invalid (we just accessed it) */ if (msg->i.nbytes > 0) ocb->attr->flags |= IOFUNC_ATTR_ATIME; return (_RESMGR_NPARTS (nparts));}
3.3 io_write()函数的编写
3.2.1 write消息将由write()函数产生
bytes_written = write( fd, buf, nbytes ){ struct _io_write hdr; iov_t iov[2]; hdr.type = _IO_WRITE; hdr.nbytes = nbytes; ... SETIOV(&iov[0], &hdr, sizeof(hdr)); SETIOV(&iov[1], buf, nbytes ); return( MsgSendv( fd, iov, 2, NULL, 0 ) );}
3.2.2 接收到的消息
typedef union{ struct _io_write i;} io_write_t;/* the data to be written usually follows the io_write_t */struct _io_write{ // contains at least the following unsigned short type; // message type = _IO_WRITE long nbytes; // number of bytes to write uint32_t xtype; // extended type};
3.2.3 the reply 即write()的回应
这里写代码片
if successful:
• there is no data to reply with
• the return value from the write()’s MsgSendv() would be the
number of bytes successfully written. To set this do:
_IO_SET_WRITE_NBYTES (ctp, nbytes_written);return _RESMGR_NPARTS(0);
When you return to the resource manager library, it will pass
nbytes_written as the status parameter to MsgReplyv().
The write() will return this value.
- if failed, do:
return errno_value;
3.2.4 the xtype member
_IO_XTYPE_OFFSET
具体代码:
int io_write (resmgr_context_t *ctp, io_write_t *msg,RESMGR_OCB_T *ocb){ int status; if ((status = iofunc_write_verify(ctp, msg, ocb, NULL)) != EOK) return status; if ((msg->i.xtype & _IO_XTYPE_MASK) != _IO_XTYPE_NONE) // msg -> i.nbytes is the number of byte to be written, // we are telling it that we wrote everything (msg -> i.nbytes) _IO_SET_WRITE_NBYTES (ctp, msg -> i.nbytes); if (msg->i.nbytes > 0) /* mark times for update */ ocb->attr->flags |= IOFUNC_ATTR_MTIME | IOFUNC_ATTR_CTIME; return _RESMGR_NPARTS (0);}
3.2.5 getting the data
io_write回调函数:
int io_write (resmgr_context_t *ctp, io_write_t *msg, …)
有这些信息:
msg->i.nbytes:发送buffer的大小
ctp->msg:接收buffer的基地址
ctp->msg_max_size:接收buffer的大小
ctp->info.msglen:实际发送到接收buffer数据的大小。包括header
ctp->offset:header的大小
1 . 发送方的buffer大小和接收方实际接收的buffer大小相等, 我们可以一次接收所有的 write data
2 . 发送方的buffer大小比接收方buffer大小大,不能一次接收所有数据
对于第一种情况,我们可以一次性直接接收所有数据。
对于第二种情况,我们不能一次接收所有数据。解决方案:需要找一个地方存数据,以及用resmgr_msgread()函数接收剩余的数据。
注:在ctp->offset以自动添加了resmgr_msgread()。
情况1的code:
`
int io_write (resmgr_context_t *ctp, io_write_t *msg,
RESMGR_OCB_T *ocb)
{
if( need_more_data ) {
char *buf;
buf = malloc( msg->i.nbytes );
...
resmgr_msgread (ctp, buf, msg -> i.nbytes,
sizeof (msg -> i)); //因为函数已经自动添加了header,所以从i开始。
// do something with buf
free( buf );
...
}
}
情况2的解决方案:
- find available cache buffers and use resmgr_msgreadv() to fill them
- use a small buffer and multiple resmgr_msgread() calls to work through the client’s message, a piece at a time
- copy the already received data from the receive buffer, and then use resmgr_msgread() for the rest
- ensure in advance that the receive buffer will be large enough for your largest write
注:我们可以通过resmgr_attr_t结构体来设置the size of the receive buffer,然后传递给resmgr_attach()。
- qnx之resource manager(二)
- qnx之resource manager(一)
- qnx之resource manager(三)
- qnx resource manager概述
- QNX实时操作系统学习笔记之嵌入式系统(二)
- QNX实时操作系统学习笔记之嵌入式系统(二)
- QNX system architecture 6 - Process manager
- HGE 的Resource Manager
- HGE 的Resource Manager
- Oracle resource manager
- Resource Manager plan
- Oracle using resource manager
- Oracle Database Resource Manager
- Oracle Resource Manager 概述
- 25、Oracle resource manager
- RESOURCE MANAGER的使用
- Oracle resource manager
- Oracle Resource Manager
- 快速排序-java实现
- poj 2376 Cleaning Shifts 区间覆盖
- 238. Product of Array Except Self
- listView的item中有checkbox,重复被选中的问题
- 我是ATP~
- qnx之resource manager(二)
- Decode Alien Message模拟
- JavaScript异步编程设计快速响应的网络应用
- 安卓应用保活实践(双进程守护)
- 经典面试题-约瑟夫环
- 二叉树的几种遍历方法及递归和非递归的实现
- MYSQL添加新用户 MYSQL为用户创建数据库 MYSQL为新用户分配权限
- 计算机CPU体系结构以及指令流水原理介绍
- JVM内存区域划分 EDEN SPACE、SURVIVOR SPACE、TENURED GEN