1 /* 2 * Copyright (c) 2004, Bull SA. All rights reserved. 3 * Created by: Laurent.Vivier (at) bull.net 4 * Copyright (c) 2013 Cyril Hrubis <chrubis (at) suse.cz> 5 * 6 * This file is licensed under the GPL license. For the full content 7 * of this license, see the COPYING file at the top level of this 8 * source tree. 9 */ 10 11 /* 12 * assertion: 13 * 14 * aio_suspend() shall fail if: 15 * [EAGAIN] No AIO indicated in the list completed before timeout 16 * 17 * method: 18 * 19 * - write to a file 20 * - submit a list of read requests 21 * - check that the selected request has not completed 22 * - suspend on selected request 23 * - check that the suspend timed out and returned EAGAIN 24 * 25 */ 26 27 #define _XOPEN_SOURCE 600 28 #include <sys/stat.h> 29 #include <aio.h> 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <signal.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include "posixtest.h" 39 40 #define WAIT_FOR_AIOCB 6 41 42 static sig_atomic_t received_all; 43 44 static void sigrt1_handler() 45 { 46 received_all = 1; 47 } 48 49 static int do_test(int num_aiocbs, size_t buf_size) 50 { 51 char tmpfname[256]; 52 int fd; 53 struct aiocb *aiocbs[num_aiocbs]; 54 struct aiocb *plist[2]; 55 char *bufs; 56 struct sigaction action; 57 struct sigevent event; 58 struct timespec ts = {0, 1000000}; /* 1 ms */ 59 int ret, ret2; 60 int err = PTS_UNRESOLVED; 61 int i; 62 63 snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_aio_suspend_9_1_%d", 64 getpid()); 65 unlink(tmpfname); 66 67 fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); 68 69 if (fd == -1) { 70 printf("Error at open(): %s\n", strerror(errno)); 71 goto err0; 72 } 73 74 unlink(tmpfname); 75 76 int file_size = num_aiocbs * buf_size; 77 78 bufs = malloc(file_size); 79 80 if (bufs == NULL) { 81 printf("Error at malloc(): %s\n", strerror(errno)); 82 goto err1; 83 } 84 85 ret = write(fd, bufs, file_size); 86 if (ret != file_size) { 87 88 if (ret < 0) 89 printf("Error at write(): %s\n", strerror(errno)); 90 else 91 printf("Error at write(): %i of %i written\n", 92 ret, file_size); 93 94 goto err2; 95 } 96 97 /* Queue up a bunch of aio reads */ 98 for (i = 0; i < num_aiocbs; i++) { 99 aiocbs[i] = malloc(sizeof(struct aiocb)); 100 memset(aiocbs[i], 0, sizeof(struct aiocb)); 101 102 aiocbs[i]->aio_fildes = fd; 103 aiocbs[i]->aio_offset = i * buf_size; 104 aiocbs[i]->aio_buf = &bufs[i * buf_size]; 105 aiocbs[i]->aio_nbytes = buf_size; 106 aiocbs[i]->aio_lio_opcode = LIO_READ; 107 } 108 109 /* reset the completion flag */ 110 received_all = 0; 111 112 /* Use SIGRTMIN+1 for list completion */ 113 event.sigev_notify = SIGEV_SIGNAL; 114 event.sigev_signo = SIGRTMIN + 1; 115 event.sigev_value.sival_ptr = NULL; 116 117 action.sa_sigaction = sigrt1_handler; 118 sigemptyset(&action.sa_mask); 119 action.sa_flags = SA_SIGINFO | SA_RESTART; 120 sigaction(SIGRTMIN + 1, &action, NULL); 121 122 /* Setup suspend list */ 123 plist[0] = NULL; 124 plist[1] = aiocbs[WAIT_FOR_AIOCB]; 125 126 /* Submit request list */ 127 ret = lio_listio(LIO_NOWAIT, aiocbs, num_aiocbs, &event); 128 129 if (ret) { 130 printf(" Error at lio_listio() %d: %s\n", 131 errno, strerror(errno)); 132 goto err3; 133 } 134 135 /* Suspend on selected request */ 136 ret = aio_suspend((const struct aiocb **)plist, 2, &ts); 137 138 /* Check selected request has not completed yet */ 139 ret2 = aio_error(aiocbs[WAIT_FOR_AIOCB]); 140 if (ret2 != EINPROGRESS) { 141 /* 142 * The operation was too fast, wait for completion 143 * and redo it with larger buffers. 144 */ 145 err = -1; 146 goto err4; 147 } 148 149 /* timed out aio_suspend should return -1 and set errno to EAGAIN */ 150 if (ret != -1) { 151 printf("aio_suspend() should return -1\n"); 152 err = PTS_FAIL; 153 goto err4; 154 } 155 if (errno != EAGAIN) { 156 printf("aio_suspend() should set errno to EAGAIN: %d (%s)\n", 157 errno, strerror(errno)); 158 err = PTS_FAIL; 159 goto err4; 160 } 161 162 /* Wait for list processing completion */ 163 while (!received_all) 164 usleep(10000); 165 166 /* Check return values and errors */ 167 err = PTS_PASS; 168 169 for (i = 0; i < num_aiocbs; i++) { 170 err = aio_error(aiocbs[i]); 171 ret = aio_return(aiocbs[i]); 172 173 if ((err != 0) && ((size_t)ret != buf_size)) { 174 printf("req %d: error = %d - return = %d\n", 175 i, err, ret); 176 err = PTS_FAIL; 177 } 178 } 179 180 err4: 181 while (!received_all) 182 usleep(10000); 183 err3: 184 for (i = 0; i < num_aiocbs; i++) 185 free(aiocbs[i]); 186 err2: 187 free(bufs); 188 err1: 189 close(fd); 190 err0: 191 return err; 192 } 193 194 int main(void) 195 { 196 int aio_cbs = 10; 197 int buf_size = 1024 * 64; 198 int ret; 199 200 if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L) 201 return PTS_UNSUPPORTED; 202 203 /* Repeat the test with increasing buffer size */ 204 do { 205 ret = do_test(aio_cbs, buf_size); 206 buf_size += buf_size / 4; 207 } while (ret == -1); 208 209 if (ret != 0) 210 return ret; 211 212 printf("(buf_size = %i)\nTest PASSED\n", buf_size); 213 return PTS_PASS; 214 } 215