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