Search code examples
c++linuxeventscallbackaio

linux c++: libaio callback function never called?


I'm on ubuntu 16.10 with g++ 6.2, testing libaio feature:

1. I was trying to test io_set_callback() function
2. I was using main thread and a child thread to talk by a pipe
3. child thread writes periodically (by alarm timer, signal), and main thread reads

I hope to use "callback" function to receive notifications. It didn't work as expected: callback function "read_done" is never called

My questions:

1. I expected my program should call "read_done" function, but actually not.
2. Why the output prints 2 "Enter while" each time? 
I hope it only print together with "thread write msg:..."
3. I tried to comment out "io_getevents" line, same result.

I'm not sure if callback mode still need io_getevents? So how to fix my program so it work as I expected? Thanks.


Solution

  • You need to integrate io_queue_run(3) and io_queue_init(3) into your program. Though these aren't new functions, they don't seem to be in the manpages for a bunch of currently shipping distros. Here's a couple of the manpages:

    http://manpages.ubuntu.com/manpages/precise/en/man3/io_queue_run.3.html http://manpages.ubuntu.com/manpages/precise/en/man3/io_queue_init.3.html

    And, of course, the manpages don't actually say it, but io_queue_run is what calls the callbacks that you set in io_set_callback.

    UPDATED: Ugh. Here's the source for io_queue_run from libaio-0.3.109 on Centos/RHEL (LGPL license, Copyright 2002 Red Hat, Inc.)

    int io_queue_run(io_context_t ctx)
    {
        static struct timespec timeout = { 0, 0 };
        struct io_event event;
        int ret;
    
        /* FIXME: batch requests? */
        while (1 == (ret = io_getevents(ctx, 0, 1, &event, &timeout))) {
            io_callback_t cb = (io_callback_t)event.data;
            struct iocb *iocb = event.obj;
    
            cb(ctx, iocb, event.res, event.res2);
        }
    
        return ret;
    }
    

    You'd never want to actually call this without the io_queue_wait call. And, the io_queue_wait call is commented out in the header included with both Centos/RHEL 6 and 7. I don't think you should call this function.

    Instead, I think you should incorporate this source into your own code, then modify it to do what you want. You could pretty trivially add a timeout argument to this io_queue_run and just replace your call to io_getevents with it, instead of bothering with io_queue_wait. There's even a patch here that makes io_queue_run MUCH better: https://lwn.net/Articles/39285/).