免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 886 | 回复: 0
打印 上一主题 下一主题

AIO --异步IO [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-06-28 17:01 |只看该作者 |倒序浏览
为支持异步通知机制,驱动程序涉及以下3项工作
支持F_SETOWN命令设备,能在这个控制命令中设置filp->owner为对应PID,已经由内核完成
支持F_SETFL命令处理,每当FASYNC标志改变的时候,驱动程序中的fasync()函数将得以执行
在资源可获得时,调用kill_fasync()函数发出信号
处理FASYNC标志变更的函数
int fasync(int fd, struct file *filp, int mode, struct fasync_struct **fa)
发出信号的函数
void kill(struct fasync_struct **fa, int sig, int band);
支持异步通知的fasync()模板
static int xxx_fasync(int fd, ;file *filp, int mode)
{
struct xxx_dev *dev = filp->private_data;
return fasync_helper(fd, filp,mode, &dev->async_queue)
}
异步IO
可以同时发起多个传输操作,通过aiob结构进行区分,结构包含有关传输的所有信息,包括为数据准备
的用户缓冲。
int aio_read(struct aiocb *aiocbp);
请求对一个有效的文件描述符进行异步读操作。该函数在请求进行排队后立即返回。0成功,-1设置errno
int aio_write(struct aiocb *aiocbp); errno
int aio_error(struct aiocb *aiocbp);确定请求的状态
返回EINPROGRESS
    ECANCELLED
ssize_t aio_return(struct aiocb *aiocbp);
-------------------------------------
用户空间的异步请求示例
#include
...
int fd, ret;
struct aiocb my_aiocb;
fd = open("file.text", O_RDONLY);
if(fd0)
{
获得返回值
}else{
失败 分析errno
}
---------------------------------------------------------
用户可以使用aio_suspend()挂起调用进程,直到完成
int aio_suspend(const struct aiocb *const cblist[], int n, const struct timespec *timeout);
取消
int aio_cancel(int fd, struct aiocb *aiocb);成功AIO_CANCELED,完成了AIO_NOTCANCELED
NULL,取消对某描述符的全部。AIO_ALLDONE
int lio_listio(int mode, struct aiocb *list[],int nent,struct sigevent *sig)
mode : LIO_WAIT 阻塞直到所有完成,LIO_NOWAIT排队
----------------------------------------------------------
使用信号进行异步通知
使用信号进行进程间通信(IPC)是 UNIX 中的一种传统机制,AIO 也可以支持这种机制。在这种范例中,应用程序需要定义信号处理程序,在产生指定的信号时就会调用这个处理程序。应用程序然后配置一个异步请求将在请求完成时产生一个信号。作为信号上下文的一部分,特定的 aiocb 请求被提供用来记录多个可能会出现的请求。清单 5 展示了这种通知方法。
清单 5. 使用信号作为 AIO 请求的通知
  
void setup_io( ... )
{
  int fd;
  struct sigaction sig_act;
  struct aiocb my_aiocb;
  ...
  /* Set up the signal handler */
  sigemptyset(&sig_act.sa_mask);
  sig_act.sa_flags = SA_SIGINFO;
  sig_act.sa_sigaction = aio_completion_handler;
  /* Set up the AIO request */
  bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
  my_aiocb.aio_fildes = fd;
  my_aiocb.aio_buf = malloc(BUF_SIZE+1);
  my_aiocb.aio_nbytes = BUF_SIZE;
  my_aiocb.aio_offset = next_offset;
  /* Link the AIO request with the Signal Handler */
  my_aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
  my_aiocb.aio_sigevent.sigev_signo = SIGIO;
  my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
  /* Map the Signal to the Signal Handler */
  ret = sigaction( SIGIO, &sig_act, NULL );
  ...
  ret = aio_read( &my_aiocb );
}
void aio_completion_handler( int signo, siginfo_t *info, void *context )
{
  struct aiocb *req;
  /* Ensure it's our signal */
  if (info->si_signo == SIGIO) {
    req = (struct aiocb *)info->si_value.sival_ptr;
    /* Did the request complete? */
    if (aio_error( req ) == 0) {
      /* Request completed successfully, get the return status */
      ret = aio_return( req );
    }
  }
  return;
}


在清单 5 中,我们在 aio_completion_handler 函数中设置信号处理程序来捕获 SIGIO 信号。
然后初始化 aio_sigevent 结构产生 SIGIO 信号来进行通知(这是通过 sigev_notify 中的 SIGEV_SIGNAL 定义来指定的)。当读操作完成时,信号处理程序就从该信号的 si_value 结构中提取出 aiocb,并检查错误状态和返回状态来确定 I/O 操作是否完成。
对于性能来说,这个处理程序也是通过请求下一次异步传输而继续进行 I/O 操作的理想地方。采用这种方式,在一次数据传输完成时,我们就可以立即开始下一次数据传输操作。
使用回调函数进行异步通知
另外一种通知方式是系统回调函数。这种机制不会为通知而产生一个信号,而是会调用用户空间的一个函数来实现通知功能。我们在 sigevent 结构中设置了对 aiocb 的引用,从而可以惟一标识正在完成的特定请求。请参看清单 6。
清单 6. 对 AIO 请求使用线程回调通知
  
void setup_io( ... )
{
  int fd;
  struct aiocb my_aiocb;
  ...
  /* Set up the AIO request */
  bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
  my_aiocb.aio_fildes = fd;
  my_aiocb.aio_buf = malloc(BUF_SIZE+1);
  my_aiocb.aio_nbytes = BUF_SIZE;
  my_aiocb.aio_offset = next_offset;
  /* Link the AIO request with a thread callback */
  my_aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
  my_aiocb.aio_sigevent.notify_function = aio_completion_handler;
  my_aiocb.aio_sigevent.notify_attributes = NULL;
  my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
  ...
  ret = aio_read( &my_aiocb );
}
void aio_completion_handler( sigval_t sigval )
{
  struct aiocb *req;
  req = (struct aiocb *)sigval.sival_ptr;
  /* Did the request complete? */
  if (aio_error( req ) == 0) {
    /* Request completed successfully, get the return status */
    ret = aio_return( req );
  }
  return;
}
在创建自己的 aiocb 请求之后,我们使用 SIGEV_THREAD 请求了一个线程回调函数来作为通知方法。然后我们将指定特定的通知处理程序,并将要传输的上下文加载到处理程序中(在这种情况中,是个对 aiocb 请求自己的引用)。在这个处理程序中,我们简单地引用到达的 sigval 指针并使用 AIO 函数来验证请求已经完成。
对 AIO 进行系统优化
proc 文件系统包含了两个虚拟文件,它们可以用来对异步 I/O 的性能进行优化:
/proc/sys/fs/aio-nr 文件提供了系统范围异步 I/O 请求现在的数目。
/proc/sys/fs/aio-max-nr 文件是所允许的并发请求的最大个数。最大个数通常是 64KB,这对于大部分应用程序来说都已经足
======================================================================================
AIO与驱动
内核中每个IO请求对应一个kiocb结构体,其ki_filp成员指向对应的file指针。通过is_sync_kiocb()
可以判断kiocb是否为同步IO请求。
file_operations :
ssize_t (*aio_read)(struct kiocb *iocb, char *buffer,size_t count, loff_t offset);
ssize_t (*aio_write)(struct kiocb *iocb, const char *buffer,size_t count, loff_t offset);
ssize_t (*aio_read)(struct kiocb *iocb, int datasync);
--
static ssize_t xxx_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos)
{
return xxx_defer_op(0,iocb,buf,count, pos);
}
static ssize_t xxx_aio_write(struct kiocb *iocb,const char *buf, size_t count, loff_t pos)
{
return xxx_defer_op(1,iocb,(char *)buf,count, pos);
}
static int xxx_defer_op(int write,struct kiocb *iocb,const char *buf, size_t count, loff_t pos)
{
struct async_work *async_wk;
int reult;
if(write)
result =xxx_write(iocb->ki_filp, buf,count, &pos);
else
result = xxx_read(iocb->ki_filp,buf, count , &pos);
if(is_sync_kiocb(iocb))
return result;
async_wk = kmalloc(sizeof(*async_wk),GFP_KERNEL);
if(async_wk ==NULL)
return result;
async_wk->iocb =iocb;
async_wk->result = result;
INIT_WORK(&async_wk->work,xxx_do_deferred_op,async_wk);
schedule_delayed_work(&async_wk->work, HZ/100)
return -EIOCBQUEUED;
}
static void xxx_do_deferred_op(void *p)
{
struct  async_work *async_wk = (struct async_work *)p;
aio_complete(async_wk->iocb,async_wk->result,0);通知内核已完成
kfree(async_wk);
}
struct async_work
{
struct kiocb *iocb,
int result,
struct work_struct  work,
}

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/69624/showart_1019124.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP