
/* asyncread.c - randomly perform asynchronous reads */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/asynch.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>

#define NUM_RESULT      MAXASYNCHIO
#define BUFFERSIZE      4096

#define RESULT_OK       0
#define RESULT_IN_USE   1

#define TRUE    1
#define FALSE   0

typedef struct result_t {
         aio_result_t    result;
         int             status;
         char            buf[BUFFERSIZE];
} result_t;

result_t        results[NUM_RESULT];
int             num_outstanding = 0;
int             filesize;
int             numfileblock;
int             numread = 0;
int             totnumread;
int             blksize;

void init_results() {

         int i;
         for (i = 0; i < MAXASYNCHIO; i++)
                 results[i].status = RESULT_OK;
} /* init_results */

result_t *nextresult() {
         static int idx = -1;

         while (TRUE) {
                 idx = ++idx % NUM_RESULT;
                 if (results[idx].status == RESULT_OK) {
                         results[idx].status = RESULT_IN_USE;
                         return( &(results[idx]) );
                 }
         }

} /* nextresult */

void aio_read_many(int fd, int num_readahead) {
         result_t *rp;
         int i;
         int offset;
         long r;

         for (i=0; i< num_readahead; i++) {
                 if (numread >= totnumread)
                         return;
                 offset = ((r=lrand48()) % numfileblock) * blksize;
                 if (offset > filesize) {
                         fprintf(stderr, "#### fatal erorr: offset > filesize.\n");
                         break;
                 }
                 rp = nextresult();
                 if (aioread(fd, rp->buf, blksize, offset, SEEK_SET, &(rp->result)) ==-1) {
                         perror("aioread error");
                 }
                 else {
                         numread++;
                         num_outstanding++;
                 }
         }

         return;

} /* aio_read_many */

main(int argc, char ** argv)
{
         int fd;
         aio_result_t *rp;
         int num_readahead;
         int threshold;
         struct stat statbuf;
		 struct stat st;
		 time_t start, end;

         if (argc != 6) {
	     fprintf(stderr, "Usage: %s <file name> <buffer size> <total # of read> 
                <# of read ahead> <threshold>\n", argv[0]);
            exit(1);
         }

		 if (stat(argv[1], &st) == -1) {
			printf("Stat error on file %s!\n", argv[1]);
			printf("Failed to get size!\n");
			exit(2);
		 }
        
		 blksize = atoi(argv[2]);
         filesize = st.st_size;	/*atoi(argv[3]);*/
         totnumread = atoi(argv[3]);
         num_readahead = atoi(argv[4]);
         threshold = atoi(argv[5]);

         srand48(11);
         init_results();

         if ((fd = open(argv[1], O_RDWR)) == -1) {
                 perror("open");
                 exit(1);
         }

         if (filesize <= 0) {
                 fstat(fd, &statbuf);
                 filesize = statbuf.st_size;
         }
        
	 numfileblock = filesize / blksize;
         if (filesize % blksize)
                 numfileblock++;
         if (totnumread <= 0) {
                 totnumread = numfileblock;
         }

         printf("\nblock size=%d filesize= %d numfileblock= %d\n",
                 blksize, filesize, numfileblock);
         printf("total_#_of_read = %d read_ahead = %d threshold = %d\n",
                 totnumread, num_readahead, threshold);

         aio_read_many(fd, num_readahead);

	 
	 printf("Peforming %i random aio read(s)...\n", totnumread);
	 start = time(NULL);
         while( (rp=aiowait(NULL)) != (aio_result_t *)-1) {
			 /* wait for aio to complete */
             if (--num_outstanding < threshold) {
                     aio_read_many(fd, num_readahead);
             }       
             if (rp->aio_return <= 0) {
             /* ignore EOF and IO errors */
                     continue;
             }

             ((result_t *) rp)->status = RESULT_OK;
         }
	 
	 end = time(NULL);
         printf("AIO: total numread = %d, completed in %.2f seconds.\n\n", numread, 
			 difftime(end, start));
         exit(0);

}  /* main */
