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