Correct handling of context data in libaio callbacks?

I am working with asynchronous I / O at the kernel level (i.e. libaio.h

). Before dispatching struct iocb

with, io_submit

I set up a using callback io_set_callback

that binds the function pointer in iocb->data

. Finally, I get the completed events with the help io_getevents

and fire each callback.

I would like to be able to use some context information in the callback (like a view label). The only method I can think of with this is to continue using io_getevents

but iocb->data

point to a structure with context and a callback.

Are there any other methods to accomplish something like this, and iocb->data

guaranteed to remain intact when used io_getevents

? I understand that there is another way that libaio

will automatically trigger callbacks, which would be a problem if I iocb->data

didn't point to a function.

Any clarification here would be nice. The documentation libaio

seems to be really missing.


source to share

1 answer

One solution, which I believe is typical, is to "output" from iocb and then discard the pointer you return from io_getevents()

into your structure. Something like that:

struct my_iocb {
    iocb cb;
    void* userdata;
    // ... anything else


When you do your jobs, whether you are doing it one at a time or in a batch, you provide an array of pointers to iocb

structs, which means they can also point to my_iocb


When you return notifications from io_getevents()

, you just cast a pointer io_event::obj

to your type:

io_event events[512];
int num_events = io_getevents(ioctx, 1, 512, events, NULL);
for (int i = 0; i < num_events; ++i) {
   my_iocb* job = (my_iocb*)events[i].obj;
   // .. do stuff with job


If you don't want to block in io_getevents

, but are instead notified via a file descriptor (so you can block in select()

or epoll()

, which may be more convenient), then I would recommend using the (undocumented) integration eventfd


You can bind aiocb

to the eventfd file descriptor with io_set_eventfd(iocb* cb, int fd)

. Whenever the job completes, it increments the eventfd value by one.

Note that if you are using this mechanism, it is very important to never read more jobs from the io (c io_getevents()

) context than the eventfd counter indicates, otherwise you introduce a race condition when you read eventfd and use jobs.



All Articles