//return eventfd int AIORead(std::string path,void *buf,int epfd=-1) { m_filefd = openFile(path); if (-1 == m_filefd) { return -1; } m_ctx = 0; if (io_setup(8192, &m_ctx)) { perror("io_setup"); return -1; } 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; } }
static int aio_submit(struct iothread *t, http_conn_t h) { struct iocb *iocb; size_t data_len; off_t data_off; int ret, fd; data_len = http_conn_data(h, &fd, &data_off); assert(data_len); iocb = hgang_alloc(aio_iocbs); if ( NULL == iocb ) return 0; io_prep_sendfile(iocb, fd, data_len, data_off, http_conn_socket(h)); iocb->data = h; io_set_eventfd(iocb, efd->fd); ret = io_submit(aio_ctx, 1, &iocb); if ( ret <= 0 ) { errno = -ret; fprintf(stderr, "io_submit: %s\n", os_err()); return 0; } dprintf("io_submit: sendfile: %zu bytes\n", data_len); in_flight++; return 1; }
int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, off_t offset, int ev, void *param) { struct iocb *ios[1] = { iocb }; io_prep_preadv(iocb, fd, iov, iovcnt, offset); io_set_eventfd(iocb, ev); iocb->data = param; return io_submit(ctx, 1, ios); }
int aio_read(int fd, void *buffer, size_t length, off_t offset, aio_callback_t cb){ struct iocb iocb; struct iocb *piocb = &iocb; int resp; io_prep_pread(&iocb, fd, buffer, length, offset); iocb.data = cb; io_set_eventfd(&iocb, aio_fd); resp = io_submit(aio_ctx,1, &piocb); return resp; }
void AsyncIO::submit(Op* op) { CHECK_EQ(op->state(), Op::State::INITIALIZED); CHECK_LT(pending_, capacity_) << "too many pending requests"; initializeContext(); // on demand iocb* cb = &op->iocb_; cb->data = nullptr; // unused if (pollFd_ != -1) { io_set_eventfd(cb, pollFd_); } int rc = io_submit(ctx_, 1, &cb); checkKernelError(rc, "AsyncIO: io_submit failed"); DCHECK_EQ(rc, 1); op->start(); ++pending_; }
/* * Test whether counter overflow is detected and handled correctly. * * It is not possible to directly overflow the counter using the * write() syscall. Overflows occur when the counter is incremented * from kernel space, in an irq context, when it is not possible to * block the calling thread of execution. * * The AIO subsystem internally uses eventfd mechanism for * notification of completion of read or write requests. In this test * we trigger a counter overflow, by setting the counter value to the * max possible value initially. When the AIO subsystem notifies * through the eventfd counter, the counter overflows. * * NOTE: If the the counter starts from an initial value of 0, it will * take decades for an overflow to occur. But since we set the initial * value to the max possible counter value, we are able to cause it to * overflow with a single increment. * * When the counter overflows, the following are tested * 1. Check whether POLLERR event occurs in poll() for the eventfd. * 2. Check whether readfd_set/writefd_set is set in select() for the eventfd. * 3. The counter value is UINT64_MAX. */ static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx) { int ret; struct iocb iocb; struct iocb *iocbap[1]; static char buf[4 * 1024]; *ctx = 0; ret = io_setup(16, ctx); if (ret < 0) { errno = -ret; tst_resm(TINFO | TERRNO, "io_setup error"); return -1; } *fd = open("testfile", O_RDWR | O_CREAT, 0644); if (*fd == -1) { tst_resm(TINFO | TERRNO, "open(testfile) failed"); goto err_io_destroy; } ret = set_counter(evfd, UINT64_MAX - 1); if (ret == -1) { tst_resm(TINFO, "error setting counter to UINT64_MAX-1"); goto err_close_file; } io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0); io_set_eventfd(&iocb, evfd); iocbap[0] = &iocb; ret = io_submit(*ctx, 1, iocbap); if (ret < 0) { errno = -ret; tst_resm(TINFO | TERRNO, "error submitting iocb"); goto err_close_file; } return 0; err_close_file: close(*fd); err_io_destroy: io_destroy(*ctx); return -1; }
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque, int type) { struct qemu_laio_state *s = aio_ctx; struct qemu_laiocb *laiocb; struct iocb *iocbs; off_t offset = sector_num * 512; laiocb = qemu_aio_get(&laio_pool, bs, cb, opaque); if (!laiocb) return NULL; laiocb->nbytes = nb_sectors * 512; laiocb->ctx = s; laiocb->ret = -EINPROGRESS; laiocb->is_read = (type == QEMU_AIO_READ); laiocb->qiov = qiov; iocbs = &laiocb->iocb; switch (type) { case QEMU_AIO_WRITE: io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset); break; case QEMU_AIO_READ: io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset); break; /* Currently Linux kernel does not support other operations */ default: fprintf(stderr, "%s: invalid AIO request type 0x%x.\n", __func__, type); goto out_free_aiocb; } io_set_eventfd(&laiocb->iocb, s->efd); s->count++; if (io_submit(s->ctx, 1, &iocbs) < 0) goto out_dec_count; return &laiocb->common; out_dec_count: s->count--; out_free_aiocb: qemu_aio_release(laiocb); return NULL; }
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockCompletionFunc *cb, void *opaque, int type) { struct qemu_laio_state *s = aio_ctx; struct qemu_laiocb *laiocb; struct iocb *iocbs; off_t offset = sector_num * 512; laiocb = qemu_aio_get(&laio_aiocb_info, bs, cb, opaque); laiocb->nbytes = nb_sectors * 512; laiocb->ctx = s; laiocb->ret = -EINPROGRESS; laiocb->is_read = (type == QEMU_AIO_READ); laiocb->qiov = qiov; iocbs = &laiocb->iocb; switch (type) { case QEMU_AIO_WRITE: io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset); break; case QEMU_AIO_READ: io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset); break; /* Currently Linux kernel does not support other operations */ default: fprintf(stderr, "%s: invalid AIO request type 0x%x.\n", __func__, type); goto out_free_aiocb; } io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e)); if (!s->io_q.plugged) { if (io_submit(s->ctx, 1, &iocbs) < 0) { goto out_free_aiocb; } } else { ioq_enqueue(s, iocbs); } return &laiocb->common; out_free_aiocb: qemu_aio_unref(laiocb); return NULL; }
int aioperf_libaio_read(aioperf_io_task_t *io_task) { struct iocb *libaio_req = NULL; aioperf_repository_t *repository = NULL; aioperf_conf_info_t *conf_info = NULL; unsigned long left_size = 0; unsigned int count = 0; repository = io_task->repository; conf_info = repository->conf_info; left_size = io_task->file_size - io_task->offset; if (!(libaio_req = (struct iocb *)aioperf_memory_pool_alloc(repository->pool, sizeof(struct iocb)))) { printf("alloc error\n"); return AIOPERF_ERROR; } if (!(io_task->buf = (char *)aioperf_memory_memalign(512, conf_info->buf_size))) { printf("memory memalign error\n"); } io_task->data = libaio_req; if (left_size > conf_info->buf_size) { count = conf_info->buf_size; } else { count = left_size; } io_prep_pread(libaio_req, io_task->fd, io_task->buf, count, io_task->offset); libaio_req->data = io_task; io_set_eventfd(libaio_req, io_task->repository->signal_fd); if (io_submit(*(io_context_t *)repository->mgr->data, 1, &libaio_req) < 0) { printf("io_submit error\n"); } return AIOPERF_OK; }
static void do_io_async(void) { size_t n_files = sizeof(files) / sizeof(files[0]); size_t i; io_context_t ctx = 0; struct iocb *iocb; struct iocb **piocb; int n_aio_ops, rc; /* TODO 1 - allocate iocb and piocb */ iocb = (struct iocb *) malloc(n_files * sizeof(*iocb)); DIE(iocb == NULL, "malloc"); piocb = (struct iocb **) malloc(n_files * sizeof(*piocb)); DIE(piocb == NULL, "malloc"); /* TODO 1 - initialiaze iocb and piocb */ for (i = 0; i < n_files; i++) { io_prep_pwrite(&iocb[i], fds[i], g_buffer, BUFSIZ, 0); piocb[i] = &iocb[i]; #ifdef USE_EVENTFD /* TODO 2 - set up eventfd notification */ io_set_eventfd(&iocb[i], efd); #endif } /* TODO 1 - setup aio context */ rc = io_setup(n_files, &ctx); DIE(rc < 0, "io_setup"); /* TODO 1 - submit aio */ n_aio_ops = io_submit(ctx, n_files, piocb); DIE(n_aio_ops < 0, "io_submit"); /* wait for completion*/ wait_aio(ctx, n_files); /* TODO 1 - destroy aio context */ io_destroy(ctx); }
void AsyncIO::submit(Op* op) { CHECK_EQ(op->state(), Op::State::INITIALIZED); initializeContext(); // on demand // We can increment past capacity, but we'll clean up after ourselves. auto p = pending_.fetch_add(1, std::memory_order_acq_rel); if (p >= capacity_) { decrementPending(); throw std::range_error("AsyncIO: too many pending requests"); } iocb* cb = &op->iocb_; cb->data = nullptr; // unused if (pollFd_ != -1) { io_set_eventfd(cb, pollFd_); } int rc = io_submit(ctx_, 1, &cb); if (rc < 0) { decrementPending(); throwSystemErrorExplicit(-rc, "AsyncIO: io_submit failed"); } submitted_++; DCHECK_EQ(rc, 1); op->start(); }
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; // TODO:Used to record event? efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (efd == -1) { perror("eventfd"); return 2; } // File Open Operation fd = open(TEST_FILE, O_RDWR | O_CREAT | O_DIRECT, 0644); if (fd == -1) { perror("open"); return 3; } // Init the file size first. ftruncate(fd, TEST_FILE_SIZE); ctx = 0; // 1. io_setup: Create an asynchronous I/O context capable of receiving // at least nr_events. // 2. 8192: It could receive at least 8192 events?? if (io_setup(8192, &ctx)) { perror("io_setup"); return 4; } // Allocate RD_WR_SIZE bytes, and places the address of the allocated memory // in *buf. The address of the allocated memory will be a multiple of ALIGN_SIZE, 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; // An inline convenience function designed to facilitate the initialization of the iocb for // an asynchronous read operation. When the function finished, the iocbp->iocb will be: // iocb->u.c.nbytes= RD_WR_SIZE // iocb->aio_fildes = fd // iocb->u.c.buf = buf // iocb->u.c.offset = i * RD_WR_SIZE io_prep_pread(&iocbp->iocb, fd, buf, RD_WR_SIZE, i * RD_WR_SIZE); io_set_eventfd(&iocbp->iocb, efd); // Set up io completion callback function. io_set_callback(&iocbp->iocb, aio_callback); iocbp->nth_request = i + 1; } // Submit asynchronous I/O blocks for processing. It will queue NUM_EVENTS // I/O request blocks for processing in the AIO context ctx. // iocbps is an array of nr AIO control blocks, which will be submitted to context ctx. if (io_submit(ctx, NUM_EVENTS, iocbps) != NUM_EVENTS) { perror("io_submit"); return 6; } // Open an epoll file descriptor ( epoll is I/O event notification facility). // It will returns a file descriptor referring to the new epoll instance. epfd = epoll_create(1); if (epfd == -1) { perror("epoll_create"); return 7; } epevent.events = EPOLLIN | EPOLLET; epevent.data.ptr = NULL; // epoll_ctl: Control interface for an epoll descriptor. // EPOLL_CTL_ADD: the operation that will be performanced // efd: The target file descriptor that the operation will be performed for. // epevent: describle the object linked to the fle descriptor efd. if (epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent)) { perror("epoll_ctl"); return 8; } i = 0; while (i < NUM_EVENTS) { uint64_t finished_aio; // epoll_wait: wait for an I/O event on an epoll file descriptor // epfd: the file descriptor that the epoll instance refer to. // epevent: points to the events that will be available for the caller. // 1: at most 1 are returned by the function // -1: specifies the minimum number of milliseconds that epoll_wait() will block. // -1 causes epoll_wait to block indefinitely. 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; // read asynchronous I/O events from the completion queue. 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); // destroy an asynchronous I/O context io_destroy(ctx); close(fd); close(efd); remove(TEST_FILE); return 0; }
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; }