[图片]
[图片]
Multiple clients opening various devices
iofunc_*()默认函数的运行假设是:使用了context块和attribute结构的默认定义,这是一个可靠的假设,原因有二:
Combine messages
QNX支持将IO消息或connect消息组合成一个消息,从而进行一些类似原子性的操作。比如通过将io_lseek和io_read消息组合成一个消息,资源管理器在收到这个消息时,readblock()函数就会允许线程去原子性的执行lseek()和read()操作。
Message types详细介绍
在前文中也提到过,资源管理器需要处理两类消息:
connect message,连接消息
I/O message, IO消息
4.1 connect message
客户端发出connect message来执行基于路径名的操作。当调用resmgr_attach()函数时,会将一个指针传递给resmgr_connect_funcs_t结构,该结构定义了一系列连接函数:
typedef struct _resmgr_connect_funcs {
unsigned nfuncs;
int (*open) (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void *extra);
int (*unlink) (resmgr_context_t *ctp, io_unlink_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*rename) (resmgr_context_t *ctp, io_rename_t *msg,
RESMGR_HANDLE_T *handle,
io_rename_extra_t *extra);
int (*mknod) (resmgr_context_t *ctp, io_mknod_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*readlink) (resmgr_context_t *ctp, io_readlink_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*link) (resmgr_context_t *ctp, io_link_t *msg,
RESMGR_HANDLE_T *handle,
io_link_extra_t *extra);
int (*unblock) (resmgr_context_t *ctp, io_pulse_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*mount) (resmgr_context_t *ctp, io_mount_t *msg,
RESMGR_HANDLE_T *handle,
io_mount_extra_t *extra);
} resmgr_connect_funcs_t;
可以调用iofunc_func_init()接口来用默认的处理程序指针来初始化这个结构。自己也可以重写某些接口,进行覆盖即可。
需要注意的是,resmgr_attach()接口只是将函数指针拷贝到resmgr_connect_func_t和resmgr_io_funcs_t结构中,而不是拷贝整个结构。需要分配这些结构,将它们声明为静态的或者全局变量。如果资源管理器用于具有不同处理程序的多个设备,则应该分开定义独立的结构。
这些连接消息都有一个_IO_CONNECT类型,此外还有子类型来进行分类,各个字段介绍如下:
nfuncs,结构中函数的个数,可用于扩展;
open,处理客户端的open()/fopen()/sopen()等请求,消息子类型包括_IO_CONNECT_COMBINE, _IO_CONNECT_COMBINE_CLOSE, _IO_CONNECT_OPEN等;
unlink,处理客户端unlink()请求,消息子类型为_IO_CONNECT_UNLINK;
rename,处理客户端rename()请求,消息子类型为_IO_CONNECT_RENAME;
mknod,处理客户端mkdir()/mkfifo()/mknod()请求,消息子类型为_IO_CONNECT_MKNOD;
readlink,处理客户端readlink()请求,消息子类型为_IO_CONNECT_READLINK;
link,处理客户端link()请求,消息子类型为_IO_CONNECT_LINK;
unlock,处理来自内核的请求,以便在连接消息阶段接触对客户端的阻塞;
mount,处理客户端mount()请求,消息子类型为_IO_CONNECT_MOUNT;
4.2 I/O messages
I/O消息依赖于客户端和资源管理器之间已有的绑定关系,比如当客户端调用read()函数发送_IO_READ消息时,需要先通过open()函数来与资源管理器建立绑定关系,进而获取到文件描述符。
regmgr_io_funcs_t结构体定义了I/O消息处理函数:
typedef struct resmgr_io_funcs {
unsigned nfuncs;
int (*read) (resmgr_context_t *ctp, io_read_t *msg,
RESMGR_OCB_T *ocb);
int (*write) (resmgr_context_t *ctp, io_write_t *msg,
RESMGR_OCB_T *ocb);
int (*close_ocb) (resmgr_context_t *ctp, void *reserved,
RESMGR_OCB_T *ocb);
int (*stat) (resmgr_context_t *ctp, io_stat_t *msg,
RESMGR_OCB_T *ocb);
int (*notify) (resmgr_context_t *ctp, io_notify_t *msg,
RESMGR_OCB_T *ocb);
int (*devctl) (resmgr_context_t *ctp, io_devctl_t *msg,
RESMGR_OCB_T *ocb);
int (*unblock) (resmgr_context_t *ctp, io_pulse_t *msg,
RESMGR_OCB_T *ocb);
int (*pathconf) (resmgr_context_t *ctp, io_pathconf_t *msg,
RESMGR_OCB_T *ocb);
int (*lseek) (resmgr_context_t *ctp, io_lseek_t *msg,
RESMGR_OCB_T *ocb);
int (*chmod) (resmgr_context_t *ctp, io_chmod_t *msg,
RESMGR_OCB_T *ocb);
int (*chown) (resmgr_context_t *ctp, io_chown_t *msg,
RESMGR_OCB_T *ocb);
int (*utime) (resmgr_context_t *ctp, io_utime_t *msg,
RESMGR_OCB_T *ocb);
int (*openfd) (resmgr_context_t *ctp, io_openfd_t *msg,
RESMGR_OCB_T *ocb);
int (*fdinfo) (resmgr_context_t *ctp, io_fdinfo_t *msg,
RESMGR_OCB_T *ocb);
int (*lock) (resmgr_context_t *ctp, io_lock_t *msg,
RESMGR_OCB_T *ocb);
int (*space) (resmgr_context_t *ctp, io_space_t *msg,
RESMGR_OCB_T *ocb);
int (*shutdown) (resmgr_context_t *ctp, io_shutdown_t *msg,
RESMGR_OCB_T *ocb);
int (*mmap) (resmgr_context_t *ctp, io_mmap_t *msg,
RESMGR_OCB_T *ocb);
int (*msg) (resmgr_context_t *ctp, io_msg_t *msg,
RESMGR_OCB_T *ocb);
int (*reserved) (resmgr_context_t *ctp, void *msg,
RESMGR_OCB_T *ocb);
int (*dup) (resmgr_context_t *ctp, io_dup_t *msg,
RESMGR_OCB_T *ocb);
int (*close_dup) (resmgr_context_t *ctp, io_close_t *msg,
RESMGR_OCB_T *ocb);
int (*lock_ocb) (resmgr_context_t *ctp, void *reserved,
RESMGR_OCB_T *ocb);
int (*unlock_ocb) (resmgr_context_t *ctp, void *reserved,
RESMGR_OCB_T *ocb);
int (*sync) (resmgr_context_t *ctp, io_sync_t *msg,
RESMGR_OCB_T *ocb);
int (*power) (resmgr_context_t *ctp, io_power_t *msg,
RESMGR_OCB_T *ocb);
} resmgr_io_funcs_t;
这个结构的使用与resmgr_connect_funcs_t一样,对应到客户端的不同请求,及消息类型。
4.3 Default message handling
由于资源管理器接收的大量消息处理的是一组公共的属性,因此QNX提供了一个iofunc*()共享库,实现了一些默认的消息处理函数。目前实现的默认函数可用于处理客户端的以下请求:
chmod()
chown()
close()
devctl()
fpathconf()
fseek()
fstat()
lockf()
lseek()
mmap()
open()
pathconf()
stat()
utime()
nparts_max
分配给IOV数组的组件数量。
msg_max_size
消息缓冲的大小。
这些成员在实现自己的处理函数时很重要。
other_func
other_func可用于指定一个例程,在资源管理器接收到不能理解的I/O消息时调用。要使用这个成员,需要在flag字段里置上RESMGR_FLAG_ATTACH_OTHERFUNC。如果other_func成员设置成NULL的话,资源管理器在收到不能理解的消息时,便会返回ENOSYS错误给客户端。
对于非I/O消息类型时,需要使用message_attach()接口来将消息绑定到dispatch handle上。
Ways of adding functionality to the resource manager
6.1 Using the default functions
下边是一个使用自己的io_open处理程序的示例:
main (int argc, char **argv)
{
…
/* install all of the default functions /
iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_funcs,
_RESMGR_IO_NFUNCS, &io_funcs);
/ take over the open function */
connect_funcs.open = io_open;
…
}
int
io_open (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void extra)
{
return (iofunc_open_default (ctp, msg, handle, extra));
}
上述的代码只是一个增量步骤,可以允许在调用默认处理函数之前或者之后执行某些操作,比如可以实现如下代码:
/ example of doing something before */
extern int accepting_opens_now;
int
io_open (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void extra)
{
if (!accepting_opens_now) {
return (EBUSY);
}
/
* at this point, we're okay to let the open happen,
* so let the default function do the "work".
*/
return (iofunc_open_default (ctp, msg, handle, extra));
}
或者:
/* example of doing something after */
int
io_open (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void extra)
{
int sts;
/
* have the default function do the checking
* and the work for us
/
sts = iofunc_open_default (ctp, msg, handle, extra);
/
* if the default function says it's okay to let the open
* happen, we want to log the request
*/
if (sts == EOK) {
log_open_request (ctp, msg);
}
return (sts);
}
这种方法的优势是,只需要很少的工作就可以添加到标准的默认POSIX处理程序中。
6.2 Using the helper functions
在很多默认处理函数中,都调用到了帮助函数,比如下边的iofunc_chmod_default()和iofunc_stat_default():
int
iofunc_chmod_default (resmgr_context_t *ctp, io_chmod_t *msg,
iofunc_ocb_t *ocb)
{
return (iofunc_chmod (ctp, msg, ocb, ocb -> attr));
}
int
iofunc_stat_default (resmgr_context_t *ctp, io_stat_t *msg,
iofunc_ocb_t *ocb)
{
iofunc_time_update (ocb -> attr);
iofunc_stat (ocb -> attr, &msg -> o);
return (_RESMGR_PTR (ctp, &msg -> o,
sizeof (msg -> o)));
}
在上边的代码中分别都调用到了iofunc_chmod()、iofunc_time_update()、iofunc_stat()等帮助函数。
更复杂的case如下:
int
iofunc_open_default (resmgr_context_t *ctp, io_open_t *msg,
iofunc_attr_t *attr, void *extra)
{
int status;
iofunc_attr_lock (attr);
if ((status = iofunc_open (ctp, msg, attr, 0, 0)) != EOK) {
iofunc_attr_unlock (attr);
return (status);
}
if ((status = iofunc_ocb_attach (ctp, msg, 0, attr, 0))
!= EOK) {
iofunc_attr_unlock (attr);
return (status);
}
iofunc_attr_unlock (attr);
return (EOK);
}
调用了以下帮助函数: