I'm trying to learn POSIX
asynchronous I/O. Below is an edit I have made to someone else's illustration code. I am trying to understand a few things.
First, I have a busy-wait loop near the end that keys off of the int
read_complete
. Is that an "acceptable" (safe, whatever, ....) alternative to keying off of the return value of aio_error()
? Also, I was thinking as an alternative to the busy-wait loop, there would be a way to put the main thread to sleep and have the callback function send some kind of signal that would wake it up. But I can't figure out how to do that, if it can be done.
Finally, I'm trying to figure out how to get more info into the callback function i_am_done
. For instance, let's say I wanted to shove the input data into a buffer, or split it up between buffers, that the main thread could use later, and the buffers might be different with each call if I had multiple reads to do. How could I let i_am_done
know what the buffers are?
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <aio.h>
//#include <bits/stdc++.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
const int BUFSIZE = 1024;
int read_complete = 0;
void i_am_done(sigval_t sigval)
{
struct aiocb *req;
req = (struct aiocb *)sigval.sival_ptr; //Pay attention here.
/*Check again if the asynchrony is complete?*/
if (aio_error(req) == 0)
{
read_complete = 1;
}
close(req->aio_fildes);
}
int main(void)
{
struct aiocb my_aiocb;
struct timeval t0, t1;
int fd = open("file.txt", O_RDONLY);
if (fd < 0)
perror("open");
bzero((char *)&my_aiocb, sizeof(my_aiocb));
my_aiocb.aio_buf = malloc(BUFSIZE);
if (!my_aiocb.aio_buf)
perror("my_aiocb.aio_buf");
my_aiocb.aio_fildes = fd;
my_aiocb.aio_nbytes = BUFSIZE;
my_aiocb.aio_offset = 0;
//Fill in callback information
/*
Using SIGEV_THREAD to request a thread callback function as a notification method
*/
my_aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
my_aiocb.aio_sigevent.sigev_notify_function = i_am_done;
my_aiocb.aio_sigevent.sigev_notify_attributes = NULL;
my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
int ret = aio_read(&my_aiocb);
if (ret < 0)
perror("aio_read");
//The calling process continues to execute
while (read_complete != 1) {}
printf("main thread %s\n", (char*)my_aiocb.aio_buf);
return 0;
}
Answering question #2, simply define a data structure into which you store the additional data you need, and set sival_ptr
to that. For example:
struct my_data {
struct aiocb cb;
// For demonstration's sake:
int foo;
char *bar;
size_t quux;
}
// ...
struct my_data data;
data.cb.aio_sigevent.sigev_value.sival_ptr = &data;
// Setup the rest of the struct and execute the read.
In the callback, you have access to the my_data struct now.