aio_kqueue_test.c revision 154668
1/*- 2 * Copyright (C) 2005 IronPort Systems, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD: head/tools/regression/aio/kqueue/aio_kqueue.c 154668 2006-01-22 03:46:03Z davidxu $ 26 */ 27 28/* 29 * Note: it is a good idea to run this against a physical drive to 30 * exercise the physio fast path (ie. aio_kqueue /dev/<something safe>) 31 */ 32 33#include <aio.h> 34#include <fcntl.h> 35#include <stdlib.h> 36#include <stdio.h> 37#include <errno.h> 38#include <sys/types.h> 39#include <sys/event.h> 40#include <sys/time.h> 41#include <unistd.h> 42 43#define PATH_TEMPLATE "/tmp/aio.XXXXXXXXXX" 44 45#define MAX 128 46#define MAX_RUNS 300 47/* #define DEBUG */ 48 49main(int argc, char *argv[]){ 50 int fd; 51 struct aiocb *iocb[MAX], *kq_iocb; 52 int i, result, run, error, j; 53 char buffer[32768]; 54 int kq = kqueue(); 55 struct kevent ke, kq_returned; 56 struct timespec ts; 57 int cancel, pending, tmp_file = 0, failed = 0; 58 char *file, pathname[sizeof(PATH_TEMPLATE)-1]; 59 60 if (kq < 0) { 61 perror("No kqeueue\n"); 62 exit(1); 63 } 64 65 if (argc == 1) { 66 strcpy(pathname, PATH_TEMPLATE); 67 fd = mkstemp(pathname); 68 file = pathname; 69 tmp_file = 1; 70 } else { 71 file = argv[1]; 72 fd = open(file, O_RDWR|O_CREAT, 0666); 73 } 74 if (fd < 0){ 75 fprintf(stderr, "Can't open %s\n", file); 76 perror(""); 77 exit(1); 78 } 79 80 for (run = 0; run < MAX_RUNS; run++){ 81#ifdef DEBUG 82 printf("Run %d\n", run); 83#endif 84 for(i = 0; i < MAX; i++) { 85 iocb[i] = (struct aiocb *)malloc(sizeof(struct aiocb)); 86 bzero(iocb[i], sizeof(struct aiocb)); 87 } 88 89 pending = 0; 90 for(i = 0; i < MAX; i++) { 91 pending++; 92 iocb[i]->aio_nbytes = sizeof(buffer); 93 iocb[i]->aio_buf = buffer; 94 iocb[i]->aio_fildes = fd; 95 iocb[i]->aio_offset = iocb[i]->aio_nbytes * i * run; 96 97 iocb[i]->aio_sigevent.sigev_notify_kqueue = kq; 98 iocb[i]->aio_sigevent.sigev_value.sival_ptr = iocb[i]; 99 iocb[i]->aio_sigevent.sigev_notify = SIGEV_KEVENT; 100 101 result = aio_write(iocb[i]); 102 if (result != 0) { 103 perror("aio_write"); 104 printf("Result %d iteration %d\n",result, i); 105 exit(1); 106 } 107#ifdef DEBUG 108 printf("WRITE %d is at %p\n", i, iocb[i]); 109#endif 110 result = rand(); 111 if (result < RAND_MAX/32) { 112 if (result > RAND_MAX/64) { 113 result = aio_cancel(fd, iocb[i]); 114#ifdef DEBUG 115 printf("Cancel %d %p result %d\n", i, iocb[i], result); 116#endif 117 if (result == AIO_CANCELED) { 118 aio_return(iocb[i]); 119 iocb[i]=NULL; 120 pending--; 121 } 122 } 123 } 124 } 125 cancel = MAX - pending; 126 127 i = 0; 128 while(pending) { 129 for(;;) { 130 bzero(&ke, sizeof(ke)); 131 bzero(&kq_returned, sizeof(ke)); 132 ts.tv_sec = 0; 133 ts.tv_nsec = 1; 134 result = kevent(kq, NULL, 0, 135 &kq_returned, 1, &ts); 136 error = errno; 137 if (result < 0) { 138 perror("kevent error: "); 139 } 140 kq_iocb = kq_returned.udata; 141#ifdef DEBUG 142 printf("kevent %d %d errno %d return.ident %p " 143 "return.data %p return.udata %p %p\n", 144 i, result, error, 145 kq_returned.ident, kq_returned.data, 146 kq_returned.udata, 147 kq_iocb); 148#endif 149 150 if(kq_iocb) 151 break; 152#ifdef DEBUG 153 printf("Try again left %d out of %d %d\n",pending, MAX, cancel); 154#endif 155 } 156 157 for(j = 0; j < MAX; j++) { 158 if (iocb[j] == kq_iocb) { 159 break; 160 } 161 } 162#ifdef DEBUG 163 printf("kq_iocb %p\n", kq_iocb); 164 165 printf("Error Result for %d is %d pending %d\n", j, result, pending); 166#endif 167 result = aio_return(kq_iocb); 168#ifdef DEBUG 169 printf("Return Result for %d is %d\n", j, result); 170 printf("\n"); 171#endif 172 if (result != sizeof(buffer)) { 173 printf("FAIL: run %d, operation %d, result %d (errno=%d) should be %d\n", run, pending, result, errno, sizeof(buffer)); 174 failed = 1; 175 } else { 176 printf("PASS: run %d, left %d\n", run, pending - 1); 177 } 178 179 free(kq_iocb); 180 iocb[j] = NULL; 181 pending--; 182 i++; 183 } 184 } 185 186 if (tmp_file) { 187 unlink(pathname); 188 } 189 190 if (failed) { 191 printf("FAIL: Atleast one\n"); 192 exit(1); 193 } else { 194 printf("PASS: All\n"); 195 exit(0); 196 } 197} 198