#include <linux/aio_abi.h> /* Defines needed types */
int io_setup(unsigned nr_events, io_context_t *ctx_idp);
int io_submit(io_context_t ctx_id, long nr, struct iocb **iocbpp);
int io_getevents(io_context_t ctx_id, long min_nr, long nr,
struct io_event *events, struct timespec *timeout);
Question 1:
If I use io_setup(32, ctx_idp)
, can I submit 100 times? Or I can only submit 32 times and use io_getevents to handle the data first, then do the submit again?
io_submit(ctx_id, 100, iocbpp);
or
for(I = 0; I<100; I++) {
io_submit(ctx_id, 1, iocbpp);
}
Question 2:
Is long min_nr, long nr
in io_getevents decided by nr_events in io_setup?
1 <= min_nr <= 32 and 1 <= nr <= 32?
Or decided by nr
in io_submit? so
1 <= min_nr <= 100 and 1 <= nr <= 100?
Answer to question 1:
Yes you can create a context to process 32 concurrent requests with io_setup
and run io_submit
for 100 requests with something similar to io_submit(ctx_id, 100, iocbpp);
. I have tested successfully this on CentOS 7 (without libaio
using adapted code from here).
Answer to question 2:
io_getevents
parameters are related to number of requests submitted with io_submit
(I have also successfully tested this).
Here is the code that I have used.
It takes 2 parameters and allows to to write to a single file but at different offsets to that you can check what io_submit
is writing.
/*
* taio.c
*
* test AIO on Linux
*
* taio <number of operations for io_setup> <number of control blocks for io_submit>
*
*
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <linux/aio_abi.h>
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);
}
/*
* size must match
*/
#define IO_SIZE 10
int main(int argc, char *argv[]) {
aio_context_t ctx;
struct iocb *tcb;
struct iocb **lcb;
char *data;
char **tdata;
struct io_event *events;
int ret;
int fd;
int i,j;
long int nr_iosetup;
long int nr_iosubmit;
int current_offset;
if (argc != 1 && argc != 3)
{
printf("taio: usage <number of operations for io_setup> <number of control blocks for io_submit>");
return 1;
}
nr_iosetup = 1;
nr_iosubmit = 1;
for(i=0; i < argc; i++)
{
if (i == 1)
nr_iosetup = atoi(argv[1]);
if (i == 2)
nr_iosubmit = atoi(argv[2]);
}
tdata = malloc(nr_iosubmit * sizeof(char *));
if (tdata == NULL)
{
perror("malloc tdata");
return 1;
}
tcb = malloc(nr_iosubmit * sizeof(struct iocb));
if (tcb == NULL)
{
perror("malloc tcb");
return 1;
}
lcb = malloc(nr_iosubmit * sizeof(struct iocb *));
if (lcb == NULL)
{
perror("malloc lcb");
return 1;
}
for (j=0; j < nr_iosubmit; j++)
{
data = malloc(IO_SIZE);
if (data == NULL)
{
perror("malloc data");
return 1;
}
tdata[j] = data;
sprintf(data, "%d\n", j);
}
events = malloc(nr_iosubmit * sizeof(struct io_event));
if (events == NULL)
{
perror("malloc events");
return 1;
}
ret = unlink("/tmp/taio.dat");
/* ignore error */
fd = open("/tmp/taio.dat", O_RDWR | O_CREAT | O_EXCL, S_IRWXU);
if (fd < 0) {
perror("open");
return -1;
}
printf("open\t\t=> fd=%d\n", fd);
ctx = (aio_context_t)0;
ret = io_setup(nr_iosetup, &ctx);
if (ret < 0) {
perror("io_setup");
return -1;
}
printf("io_setup\t=> nr_iosetup=%ld ret=%d\n", nr_iosetup, ret);
/* command-specific options */
for (j=0, current_offset=0; j < nr_iosubmit; j++)
{
/* setup I/O control block */
memset(&tcb[j], 0, sizeof(struct iocb));
tcb[j].aio_fildes = fd;
tcb[j].aio_lio_opcode = IOCB_CMD_PWRITE;
tcb[j].aio_buf = (uint64_t)tdata[j];
tcb[j].aio_offset = current_offset;
tcb[j].aio_nbytes = IO_SIZE;
lcb[j] = &tcb[j];
current_offset += IO_SIZE;
}
ret = io_submit(ctx, nr_iosubmit, lcb);
if (ret < 0)
{
perror("io_submit");
return 1;
}
printf("io_submit\t=> nr_iosubmit=%ld ret=%d\n", nr_iosubmit, ret);
ret = io_getevents(ctx, nr_iosubmit, nr_iosubmit, events, NULL);
printf("io_getevents\t=> ret=%d\n", ret);
ret = io_destroy(ctx);
if (ret < 0) {
perror("io_destroy");
return -1;
}
printf("io_destroy\t=> ret=%d\n", ret);
return 0;
}
Execution:
./taio 32 100
open => fd=3
io_setup => nr_iosetup=32 ret=0
io_submit => nr_iosubmit=100 ret=100
io_getevents => ret=100
io_destroy => ret=0