Asynchronous io_getevents两次返回完成事件

Asynchronous io_getevents两次返回完成事件,asynchronous,io,linux-kernel,Asynchronous,Io,Linux Kernel,我有一个更大的应用程序,它通过IO_submit()和IO_getevents()使用Linux的异步IO。偶尔,io_getevents似乎会两次返回其中一个IOs。这在返回事件的“events”数组中显示为一个加倍的条目,或者显示为一个与先前调用io_getevents()返回的条目重复的条目 IOCB一次发布一个到io_submit() 我使用io_getevents的返回值来限制对“事件”的访问。即 struct io_event event[EVENT_COUNT]; // .. s

我有一个更大的应用程序,它通过IO_submit()和IO_getevents()使用Linux的异步IO。偶尔,io_getevents似乎会两次返回其中一个IOs。这在返回事件的“events”数组中显示为一个加倍的条目,或者显示为一个与先前调用io_getevents()返回的条目重复的条目

  • IOCB一次发布一个到io_submit()
  • 我使用io_getevents的返回值来限制对“事件”的访问。即

    struct io_event event[EVENT_COUNT];
    // .. skip a bit
    reaped = io_getevents(_m_aio_context, count, EVENT_COUNT, event, &timeout);
    if(reaped < 0) {
      if(errno == EINTR) {
        continue;
      }
    
      perror("reap error:");
      assert(0);
    }
    
    assert(reaped <= (int)EVENT_COUNT);
    for(i = 0; i < reaped; i++) {
      struct my_iocb *my_iocb = (struct my_iocb *)event[i].obj;
      ...
      // The symptom is that my_iocb is the same pointer as event[i-1].obj,
      // or that my_iocb was recently returned by a previous call to
      // io_getevents() and was not re-submitted since then.
      ...
    
    struct io_event事件[事件计数];
    // .. 略过
    收获=io_getevents(_m_aio_上下文、计数、事件计数、事件和超时);
    如果(收获<0){
    如果(errno==EINTR){
    持续
    }
    佩罗尔(“收获错误:”);
    断言(0);
    }
    
    assert(reaped在io_submit中,您应该将struct iocb的aio_数据字段设置为上下文结构的值

    处理完成事件时,应使用事件[i].data查找上下文指针;不要使用事件[i].obj

    我还编写了一个测试,检查是否收到了两次通知:它通过在请求中设置一个魔术值来检查,通知检查并重置这个魔术值;这个测试运行良好

    编辑它 gcc-std=c++0x-gaio.cpp-lstdc++-lpthread-oaio

    测试:

    #include <stdio.h>      /* for perror() */
    #include <unistd.h>     /* for syscall() */
    #include <sys/syscall.h>    /* for __NR_* definitions */
    #include <linux/aio_abi.h>  /* for AIO types and constants */
    #include <fcntl.h>      /* O_RDWR */
    #include <string.h>     /* memset() */
    #include <inttypes.h>   /* uint64_t */
    
    #include <atomic>
    #include <pthread.h>
    
    #define MAX_EVENTS 1000
    
    #define BLOCK_SIZE 4096
    #define FILE_SIZE (BLOCK_SIZE * 10000)
    
    #define MAGIC_VALUE 0xff0001DDEEFFAABB
    #define MAGIC_SIZE  8
    
    std::atomic<uint64_t> request_cnt;
    
    int fd;
    aio_context_t ctx;
    
    
    #if 1
    
    // no header on my system that has these - says that libaio does it;
    
    inline int io_setup(unsigned nr, aio_context_t *ctxp)
    {
        return syscall(__NR_io_setup, nr, ctxp);
    }
    
    inline int io_destroy(aio_context_t ctx) 
    {
        return syscall(__NR_io_destroy, ctx);
    }
    
    inline int io_submit(aio_context_t ctx, long nr,  struct iocb **iocbpp) 
    {
        return syscall(__NR_io_submit, ctx, nr, iocbpp);
    }
    
    inline int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
            struct io_event *events, struct timespec *timeout)
    {
        return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
    }
    
    #endif
    
    
    
    
    
    void *notification_th(void *)
    {
        struct io_event events[MAX_EVENTS];
        int ret, i;
    
        while(true)
        {
    
            /* get the reply */
            ret = io_getevents(ctx, 1, MAX_EVENTS, events, NULL);
            for(i=0; i < ret; i++)
            {
                char *data = (char *) events[i].data;
    
                if (* ((uint64_t *) (data + BLOCK_SIZE)) != MAGIC_VALUE)
                {
                    fprintf(stderr, "notification received twice\n");
                }
                * ((uint64_t *) (data + BLOCK_SIZE)) = 0;
    
                //fprintf(stderr,"notify %p\n",data);
    
                delete [] data;
            }
        }
    
        return NULL;
    }
    
    void *sender_th(void *)
    {
        char *data ;
        struct iocb cb;
        struct iocb *cbs[1];
        int ret;
        uint64_t cnt;
    
    
        while( true )
        {
            cnt = request_cnt.fetch_add( 1 );
    
    
            data = new char [ BLOCK_SIZE + MAGIC_SIZE ];
            memset( data, (char) cnt , BLOCK_SIZE );
    
            * ((uint64_t *) (data + BLOCK_SIZE)) = MAGIC_VALUE;
    
            /* setup I/O control block */
            memset(&cb, 0, sizeof(cb));
            cb.aio_fildes = fd;
            cb.aio_lio_opcode = IOCB_CMD_PWRITE;
    
            /* command-specific options */
            cb.aio_buf = (uint64_t)data;
            cb.aio_offset = (BLOCK_SIZE * cnt ) % FILE_SIZE;
            cb.aio_nbytes = BLOCK_SIZE;
            cb.aio_data = (uint64_t) data;
    
            cbs[0] = &cb;
    
            //fprintf(stderr,"submit %lu %p\n",cnt,data);
    
            ret = io_submit(ctx, 1, cbs);
            if (ret != 1) {
                 if (ret < 0) {
                //fprintf(stderr,"error %lu %p\n",cnt,data);
                perror("io_submit error");
                 } else
                fprintf(stderr, "could not sumbit IOs");
                return  NULL;
            }
        }
        return NULL;
    }   
    
    int main()
    {
        int i;
        int ret;
    
        request_cnt = 0;
    
        fd = open("/tmp/testfile", O_RDWR | O_CREAT);
        if (fd < 0) {
            perror("open error");
            return -1;
        }
    
        ctx = 0;
    
        ret = io_setup(10000, &ctx);
        if (ret < 0) {
            perror("io_setup error");
            return -1;
        }
    
        pthread_t th;
        pthread_create(&th,NULL,notification_th,NULL);
    
        for(i = 0; i < 10; i++ )
        {
            pthread_t th;
            pthread_create(&th,NULL,notification_th,NULL);
        }
    
        for(i = 0; i < 10; i++ )
        {
            pthread_t th;
            pthread_create(&th,NULL,sender_th,NULL);
        }
    
    
        void *value;
        pthread_join(th,&value);
    
    
        ret = io_destroy(ctx);
        if (ret < 0) {
            perror("io_destroy error");
            return -1;
        }
    
    
    return 0;
    }
    
    #包括/*用于perror()*/
    #包括/*for syscall()*/
    #包含/*用于_un r_*定义*/
    #包括/*用于AIO类型和常量*/
    #包括/*O_RDWR*/
    #include/*memset()*/
    #包括/*uint64\u t*/
    #包括
    #包括
    #定义最大事件数1000
    #定义块大小4096
    #定义文件大小(块大小*10000)
    #定义幻方值0xff0001DDEEFFAABB
    #定义魔术_大小8
    std::原子请求;
    int-fd;
    aio_context_t ctx;
    #如果1
    //在我的系统中,没有一个标题包含这些内容——说是libaio做的;
    内联int io_设置(未签名的nr、aio_上下文*ctxp)
    {
    返回系统调用(\uuuunr\uIO\uSetup,NR,ctxp);
    }
    内联输入输出销毁(aio上下文ctx)
    {
    返回系统调用(uuu NR_uio_udestroy,ctx);
    }
    内联输入io提交(aio\U上下文ctx,长nr,结构iocb**iocbpp)
    {
    返回系统调用(提交、ctx、NR、iocbpp);
    }
    内联int io_getevents(aio_上下文ctx、长最小值、长最大值、,
    结构io_事件*事件,结构timespec*超时)
    {
    返回系统调用(事件、ctx、最小值、最大值、事件、超时);
    }
    #恩迪夫
    无效*通知(无效*)
    {
    结构io_事件事件[最大事件];
    int ret,i;
    while(true)
    {
    /*得到答复*/
    ret=io_getevents(ctx,1,MAX_EVENTS,EVENTS,NULL);
    对于(i=0;i
    #include <stdio.h>      /* for perror() */
    #include <unistd.h>     /* for syscall() */
    #include <sys/syscall.h>    /* for __NR_* definitions */
    #include <linux/aio_abi.h>  /* for AIO types and constants */
    #include <fcntl.h>      /* O_RDWR */
    #include <string.h>     /* memset() */
    #include <inttypes.h>   /* uint64_t */
    
    #include <atomic>
    #include <pthread.h>
    
    #define MAX_EVENTS 1000
    
    #define BLOCK_SIZE 4096
    #define FILE_SIZE (BLOCK_SIZE * 10000)
    
    #define MAGIC_VALUE 0xff0001DDEEFFAABB
    #define MAGIC_SIZE  8
    
    std::atomic<uint64_t> request_cnt;
    
    int fd;
    aio_context_t ctx;
    
    
    #if 1
    
    // no header on my system that has these - says that libaio does it;
    
    inline int io_setup(unsigned nr, aio_context_t *ctxp)
    {
        return syscall(__NR_io_setup, nr, ctxp);
    }
    
    inline int io_destroy(aio_context_t ctx) 
    {
        return syscall(__NR_io_destroy, ctx);
    }
    
    inline int io_submit(aio_context_t ctx, long nr,  struct iocb **iocbpp) 
    {
        return syscall(__NR_io_submit, ctx, nr, iocbpp);
    }
    
    inline int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
            struct io_event *events, struct timespec *timeout)
    {
        return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
    }
    
    #endif
    
    
    
    
    
    void *notification_th(void *)
    {
        struct io_event events[MAX_EVENTS];
        int ret, i;
    
        while(true)
        {
    
            /* get the reply */
            ret = io_getevents(ctx, 1, MAX_EVENTS, events, NULL);
            for(i=0; i < ret; i++)
            {
                char *data = (char *) events[i].data;
    
                if (* ((uint64_t *) (data + BLOCK_SIZE)) != MAGIC_VALUE)
                {
                    fprintf(stderr, "notification received twice\n");
                }
                * ((uint64_t *) (data + BLOCK_SIZE)) = 0;
    
                //fprintf(stderr,"notify %p\n",data);
    
                delete [] data;
            }
        }
    
        return NULL;
    }
    
    void *sender_th(void *)
    {
        char *data ;
        struct iocb cb;
        struct iocb *cbs[1];
        int ret;
        uint64_t cnt;
    
    
        while( true )
        {
            cnt = request_cnt.fetch_add( 1 );
    
    
            data = new char [ BLOCK_SIZE + MAGIC_SIZE ];
            memset( data, (char) cnt , BLOCK_SIZE );
    
            * ((uint64_t *) (data + BLOCK_SIZE)) = MAGIC_VALUE;
    
            /* setup I/O control block */
            memset(&cb, 0, sizeof(cb));
            cb.aio_fildes = fd;
            cb.aio_lio_opcode = IOCB_CMD_PWRITE;
    
            /* command-specific options */
            cb.aio_buf = (uint64_t)data;
            cb.aio_offset = (BLOCK_SIZE * cnt ) % FILE_SIZE;
            cb.aio_nbytes = BLOCK_SIZE;
            cb.aio_data = (uint64_t) data;
    
            cbs[0] = &cb;
    
            //fprintf(stderr,"submit %lu %p\n",cnt,data);
    
            ret = io_submit(ctx, 1, cbs);
            if (ret != 1) {
                 if (ret < 0) {
                //fprintf(stderr,"error %lu %p\n",cnt,data);
                perror("io_submit error");
                 } else
                fprintf(stderr, "could not sumbit IOs");
                return  NULL;
            }
        }
        return NULL;
    }   
    
    int main()
    {
        int i;
        int ret;
    
        request_cnt = 0;
    
        fd = open("/tmp/testfile", O_RDWR | O_CREAT);
        if (fd < 0) {
            perror("open error");
            return -1;
        }
    
        ctx = 0;
    
        ret = io_setup(10000, &ctx);
        if (ret < 0) {
            perror("io_setup error");
            return -1;
        }
    
        pthread_t th;
        pthread_create(&th,NULL,notification_th,NULL);
    
        for(i = 0; i < 10; i++ )
        {
            pthread_t th;
            pthread_create(&th,NULL,notification_th,NULL);
        }
    
        for(i = 0; i < 10; i++ )
        {
            pthread_t th;
            pthread_create(&th,NULL,sender_th,NULL);
        }
    
    
        void *value;
        pthread_join(th,&value);
    
    
        ret = io_destroy(ctx);
        if (ret < 0) {
            perror("io_destroy error");
            return -1;
        }
    
    
    return 0;
    }