一个epoll/aio/eventfd结合使用的简单例子

From: http://blog.sina.com.cn/s/blog_6b19f21d0100znza.html

 

#define _GNU_SOURCE
#define __STDC_FORMAT_MACROS

#include <stdio.h>
#include <errno.h>
#include <libaio.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>

#define TEST_FILE    "aio_test_file"
#define TEST_FILE_SIZE   (127 * 1024)
#define NUM_EVENTS   128
#define ALIGN_SIZE   512
#define RD_WR_SIZE   1024

struct custom_iocb
{
      struct iocb iocb;
      int nth_request;
};

void aio_callback(io_context_t ctx, struct iocb *iocb, long res, long res2)
{
      struct custom_iocb *iocbp = (struct custom_iocb *)iocb;
      printf("nth_request: %d, request_type: %s, offset: %lld, length: %lu, res: %ld, res2: %ld\n", 
                  iocbp->nth_request, (iocb->aio_lio_opcode == IO_CMD_PREAD) ? "READ" : "WRITE",
                  iocb->u.c.offset, iocb->u.c.nbytes, res, res2);
}

int main(int argc, char *argv[])
{
      int efd, fd, epfd;
      io_context_t ctx;
      struct timespec tms;
      struct io_event events[NUM_EVENTS];
      struct custom_iocb iocbs[NUM_EVENTS];
      struct iocb *iocbps[NUM_EVENTS];
      struct custom_iocb *iocbp;
      int i, j, r;
      void *buf;
      struct epoll_event epevent;

      efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
      if (efd == -1) {
            perror("eventfd");
            return 2;
      }

      fd = open(TEST_FILE, O_RDWR | O_CREAT | O_DIRECT, 0644);
      if (fd == -1) {
            perror("open");
            return 3;
      }
      ftruncate(fd, TEST_FILE_SIZE);
      
      ctx = 0;
      if (io_setup(8192, &ctx)) {
            perror("io_setup");
            return 4;
      }

      if (posix_memalign(&buf, ALIGN_SIZE, RD_WR_SIZE)) {
            perror("posix_memalign");
            return 5;
      }
      printf("buf: %p\n", buf);

      for (i = 0, iocbp = iocbs; i < NUM_EVENTS; ++i, ++iocbp) {
            iocbps[i] = &iocbp->iocb;
            io_prep_pread(&iocbp->iocb, fd, buf, RD_WR_SIZE, i * RD_WR_SIZE);
            io_set_eventfd(&iocbp->iocb, efd);
            io_set_callback(&iocbp->iocb, aio_callback);
            iocbp->nth_request = i + 1;
      }

      if (io_submit(ctx, NUM_EVENTS, iocbps) != NUM_EVENTS) {
            perror("io_submit");
            return 6;
      }

      epfd = epoll_create(1);
      if (epfd == -1) {
            perror("epoll_create");
            return 7;
      }

      epevent.events = EPOLLIN | EPOLLET;
      epevent.data.ptr = NULL;
      if (epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent)) {
            perror("epoll_ctl");
            return 8;
      }

      i = 0;
      while (i < NUM_EVENTS) {
            uint64_t finished_aio;

            if (epoll_wait(epfd, &epevent, 1, -1) != 1) {
                  perror("epoll_wait");
                  return 9;
            }

            if (read(efd, &finished_aio, sizeof(finished_aio)) != sizeof(finished_aio)) {
                  perror("read");
                  return 10;
            }

            printf("finished io number: %"PRIu64"\n", finished_aio);
      
            while (finished_aio > 0) {
                  tms.tv_sec = 0;
                  tms.tv_nsec = 0;
                  r = io_getevents(ctx, 1, NUM_EVENTS, events, &tms);
                  if (r > 0) {
                        for (j = 0; j < r; ++j) {
                              ((io_callback_t)(events[j].data))(ctx, events[j].obj, events[j].res, events[j].res2);
                        }
                        i += r;
                        finished_aio -= r;
                  }
            }
      }
      
      close(epfd);
      free(buf);
      io_destroy(ctx);
      close(fd);
      close(efd);
      remove(TEST_FILE);

      return 0;
}

说明:
1. 在centos 6.2 (libaio-devel 0.3.107-10) 上运行通过
2. struct io_event中的res字段表示读到的字节数或者一个负数错误码。在后一种情况下,-res表示对应的
     errno。res2字段为0表示成功,否则失败
3. iocb在aio请求执行过程中必须是valid的
4. 在上面的程序中,通过扩展iocb结构来保存额外的信息(nth_request),并使用iocb.data
     来保存回调函数的地址。如果回调函数是固定的,那么也可以使用iocb.data来保存额外信息。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值