Search code examples
casynchronousioposixaio

Simple example for aio_write()


I'm searching for a simple example for the POSIX aio_write function.

What I tried so far

The below is not too important. Just jump to answer

The code below creates a file, but does not write anything to it. aio_error returns 22 (= quota exceeded, but there is enough space and r/w-permission on the drive).

#include <aio.h>
#include <stdio.h>


char CONTENT[] = "asdf;";
const int LENGTH = 5;

struct aiocb createIoRequest(int fd,  
                            off_t offset, 
                            volatile void * content, 
                            size_t length){
    struct aiocb ret; // <-- not initialized. Will lead to an error ( see answer) 
    {
        ret.aio_fildes = fd;
        ret.aio_offset = offset;
        ret.aio_buf = content;
        ret.aio_nbytes = length;            
    }
    return ret;
}


int main(){

    FILE * file = fopen("outfile.txt","w");
    int fd = fileno(file);
    {    
        struct aiocb op  = createIoRequest(fd,0,CONTENT,LENGTH);        

        // schedule write
        // for valgrind mem leak output see comments from answer in
        //   https://stackoverflow.com/questions/4248720/aio-h-aio-read-and-write-memory-leak
        int ret = aio_write(&op);
        printf("aio_write 1: %d\n",ret);

        // wait until everything is done
        {
            const struct aiocb * aiolist[1];
            aiolist[0] = &op;

            int ret = aio_suspend(aiolist,1,NULL);
            printf("aio_suspend: %d\n",ret);

            // report possible errors
            {
                ret = aio_error(&op);
                printf("errno 1: %d\n",ret);
            }
        }
    }
    fclose(file);


    return 0;
}

Solution

  • Checking you code with valgrind reports Conditional jump or move depends on uninitialised value(s)

    Problem with your code

    The aiocb is not initialized.

    Examples

    The examples below do not contain any "success"-checks (e.g. file != NULL, etc). This for the sake of readability. In productive code you should check the return values.

    Example1

    The program below writed asdf; to outfile.txt. The aiocb struct is initialized inside createIoRequest()

    #include <aio.h>
    #include <stdio.h>
    
    
    char CONTENT[] = "asdf;";
    const int LENGTH = 5;
    
    struct aiocb createIoRequest(int fd,  
                                off_t offset, 
                                volatile void * content, 
                                size_t length){
        // create and initialize the aiocb structure.
        // If we don't init to 0, we have undefined behavior.
        // E.g. through sigevent op.aio_sigevent there could be 
        //      a callback function being set, that the program
        //      tries to call - which will then fail.
        struct aiocb ret = {0};
        {
            ret.aio_fildes = fd;
            ret.aio_offset = offset;
            ret.aio_buf = content;
            ret.aio_nbytes = length;            
        }
        return ret;
    }
    
    
    int main(){
    
        FILE * file = fopen("outfile.txt","w");
        int fd = fileno(file);
        {    
            struct aiocb op  = createIoRequest(fd,0,CONTENT,LENGTH);        
    
            // schedule write
            // for valgrind mem leak output see comments from answer in
            //   https://stackoverflow.com/questions/4248720/aio-h-aio-read-and-write-memory-leak
            int ret = aio_write(&op);
            printf("aio_write 1: %d\n",ret);
    
            // wait until everything is done
            {
                const struct aiocb * aiolist[1];
                aiolist[0] = &op;
    
                int ret = aio_suspend(aiolist,1,NULL);
                printf("aio_suspend: %d\n",ret);
    
                // report possible errors
                {
                    ret = aio_error(&op);
                    printf("errno 1: %d\n",ret);
                }
            }
        }
        fclose(file);
    
    
        return 0;
    }
    

    Example2

    The program below simply extends the one above to have two async writes to the file

    #include <aio.h>
    #include <stdio.h>
    
    
    char CONTENT[] = "asdf;";
    const int LENGTH = 5;
    
    struct aiocb createIoRequest(int fd,  
                                off_t offset, 
                                volatile void * content, 
                                size_t length){
        // create and initialize the aiocb structure.
        // If we don't init to 0, we have undefined behavior.
        // E.g. through sigevent op.aio_sigevent there could be 
        //      a callback function being set, that the program
        //      tries to call - which will then fail.
        struct aiocb ret = {0};
        {
            ret.aio_fildes = fd;
            ret.aio_offset = offset;
            ret.aio_buf = content;
            ret.aio_nbytes = length;            
        }
        return ret;
    }
    
    
    int main(){
    
        FILE * file = fopen("outfile.txt","w");
        int fd = fileno(file);
        {    
            struct aiocb op  = createIoRequest(fd,0,CONTENT,LENGTH);
            struct aiocb op2 = createIoRequest(fd,LENGTH,CONTENT,LENGTH);
    
            // schedule write
            // for valgrind mem leak output see comments from answer in
            //   https://stackoverflow.com/questions/4248720/aio-h-aio-read-and-write-memory-leak
            int ret = aio_write(&op);
            printf("aio_write 1: %d\n",ret);
            ret = aio_write(&op2);
            printf("aio_write 2: %d\n",ret);        
    
            // wait until everything is done
            {
                const int OPs = 2;
                const struct aiocb * aiolist[OPs];
                aiolist[0] = &op;
                aiolist[1] = &op2;
    
                int ret = aio_suspend(aiolist,OPs,NULL);
                printf("aio_suspend: %d\n",ret);
    
                // report possible errors
                {
                    ret = aio_error(&op);
                    printf("errno 1: %d\n",ret);
                    ret = aio_error(&op2);
                    printf("errno 2: %d\n",ret);
                    // error codes can be checked in <errno.h>
                }
            }
        }
        fclose(file);
    
    
        return 0;
    }