Imported Upstream version 0.3.113
[platform/upstream/libaio.git] / harness / cases / 17.t
1 /*
2  * Copyright (C) 2014, Dan Aloni, Kernelim Ltd.
3  * Copyright (C) 2014, Benjamin LaHaise <bcrl@kvack.org>.
4  * Copyright (C) 2014, Red Hat, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  */
15 /*
16  * Description:
17  *   This regression test ensures that submitting more events than can
18  *   fit in the completion ring will not result in a hung task.
19  */
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE 1
22 #endif
23 #include <assert.h>
24 #include <errno.h>
25 #include <libaio.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/uio.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <sys/mman.h>
38 #include <sys/wait.h>
39
40 const int max_events = 32;
41 const int io_size = 0x1000;
42 struct iocb *io;
43 struct iocb **iops;
44 struct iovec *iovecs;
45 struct io_event *events;
46 char *data;
47
48 long submitted = 0;
49 long completed = 0;
50 long pending = 0;
51
52 #define SYS_IO_GETEVENTS 0
53 #define USER_GETEVENTS 1
54
55 static volatile sig_atomic_t done = 0;
56
57 struct aio_ring {
58         unsigned        id;     /* kernel internal index number */
59         unsigned        nr;     /* number of io_events */
60         volatile unsigned       head;
61         volatile unsigned       tail;
62
63         unsigned        magic;
64         unsigned        compat_features;
65         unsigned        incompat_features;
66         unsigned        header_length;  /* size of aio_ring */
67
68         struct io_event io_events[0];
69 };
70
71 int get_ring_size(int nr_events)
72 {
73         io_context_t ctx;
74         int ret, ring_size;
75         struct aio_ring *ring;
76
77         memset(&ctx, 0, sizeof(ctx));
78         ret = io_setup(nr_events, &ctx);
79         assert(!ret);
80
81         ring = (void *)ctx;
82         ring_size = ring->nr;
83
84         ret = io_destroy(ctx);
85         assert(!ret);
86
87         return ring_size;
88 }
89
90 int user_getevents(io_context_t ctx, int nr_events, struct io_event *event)
91 {
92         struct aio_ring *ring = (void *)ctx;
93         int completed = 0;
94         while ((completed < nr_events) && (ring->head != ring->tail)) {
95                 unsigned new_head = ring->head;
96                 *event = ring->io_events[new_head];
97                 new_head += 1;
98                 new_head %= ring->nr;
99                 ring->head = new_head;
100                 completed++;
101         }
102         return completed;
103 }
104
105 void prune(io_context_t io_ctx, int max_ios, int getevents_type)
106 {
107         int ret;
108
109         if (getevents_type == USER_GETEVENTS)
110                 ret = user_getevents(io_ctx, max_ios, events);
111         else
112                 ret = io_getevents(io_ctx, pending, max_ios, events, NULL);
113         if (ret > 0) {
114                 printf("Completed: %d\n", ret);
115                 completed += ret;
116                 pending -= ret;
117         }
118 }
119
120 void run_test(int max_ios, int getevents_type)
121 {
122         int fd, ret, flags;
123         long i, to_submit;
124         struct iocb **iocb_sub;
125         io_context_t io_ctx;
126         const char *filename = "testfile";
127
128         printf("MAX_IOS: %d, %s\n", max_ios, getevents_type == USER_GETEVENTS ?
129                "USER_GETEVENTS" : "IO_GETEVENTS");
130         memset(&io_ctx, 0, sizeof(io_ctx));
131         ret = io_setup(max_events, &io_ctx);
132         assert(!ret);
133
134         io = calloc(max_ios, sizeof(*io));
135         iops = calloc(max_ios, sizeof(*iops));
136         iovecs = calloc(max_ios, sizeof(*iovecs));
137         events = calloc(max_ios, sizeof(*events));
138
139         unlink(filename);
140         fd = open(filename, O_CREAT | O_RDWR, 0644);
141         assert(fd >= 0);
142
143         /*
144          * Use O_DIRECT if it's available.  If it's not, the test code
145          * will still operate correctly, just potentially slower.
146          */
147         flags = fcntl(fd, F_GETFL, 0);
148         fcntl(fd, F_SETFL, flags | O_DIRECT);
149
150         ret = ftruncate(fd, max_ios * io_size);
151         assert(!ret);
152
153         data = mmap(NULL, io_size * max_ios, PROT_READ | PROT_WRITE,
154                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
155         assert(data != MAP_FAILED);
156
157         for (i = 0; i < max_ios; i++) {
158                 iops[i] = &io[i];
159                 io[i].data = io;
160                 iovecs[i].iov_base = &data[io_size * i];
161                 iovecs[i].iov_len = io_size;
162                 io_prep_preadv(&io[i], fd, &iovecs[i], 1, 0);
163         }
164
165         submitted = completed = pending = 0;
166
167         to_submit = max_ios;
168         iocb_sub = iops;
169
170         while (submitted < max_ios) {
171                 printf("Submitting: %ld\n", to_submit);
172
173                 ret = io_submit(io_ctx, to_submit, iocb_sub);
174                 if (ret >= 0) {
175                         printf("Submitted: %d\n", ret);
176                         submitted += ret;
177                         iocb_sub += ret;
178                         pending += ret;
179                         to_submit -= ret;
180                 } else {
181                         if (ret == -EAGAIN) {
182                                 printf("Submitted too much, that's okay\n");
183                                 prune(io_ctx, max_ios, getevents_type);
184                         }
185                 }
186         }
187
188         prune(io_ctx, max_ios, getevents_type);
189         io_destroy(io_ctx);
190         close(fd);
191         ret = munmap(data, io_size * max_ios);
192         assert(!ret);
193
194         printf("Verifying...\n");
195
196         assert(completed == submitted);
197
198         printf("OK\n");
199 }
200
201 void run_child(void)
202 {
203         int ring_size;
204
205         ring_size = get_ring_size(max_events);
206
207         printf("aio ring size: %d\n", ring_size);
208
209         run_test(ring_size-1, SYS_IO_GETEVENTS);
210         run_test(ring_size, SYS_IO_GETEVENTS);
211         run_test(ring_size+1, SYS_IO_GETEVENTS);
212         run_test(ring_size*2, SYS_IO_GETEVENTS);
213         run_test(ring_size*4, SYS_IO_GETEVENTS);
214
215         run_test(ring_size-1, USER_GETEVENTS);
216         run_test(ring_size, USER_GETEVENTS);
217         run_test(ring_size+1, USER_GETEVENTS);
218         run_test(ring_size*2, USER_GETEVENTS);
219         run_test(ring_size*4, USER_GETEVENTS);
220
221         exit(0);
222 }
223
224 void sighandler(int signo)
225 {
226         assert(signo == SIGCHLD);
227         done = 1;
228 }
229
230 int test_main(void)
231 {
232         unsigned int ret;
233         sighandler_t oldhandler;
234         pid_t child;
235
236         switch (child = fork()) {
237         case 0: /* child */
238                 run_child();
239                 break;
240         case -1:
241                 perror("fork");
242                 exit(1);
243         default:
244                 oldhandler = signal(SIGCHLD, sighandler);
245                 assert(oldhandler != SIG_ERR);
246                 break;
247         }
248
249         ret = sleep(10);
250         if (ret != 0) {
251                 pid_t pid;
252                 int status;
253
254                 assert(done);
255
256                 pid = wait(&status);
257                 if (pid != child) {
258                         perror("wait");
259                         exit(1);
260                 }
261
262                 return WEXITSTATUS(status);
263         }
264
265         return 1; /* failed */
266 }
267 /*
268  * Local Variables:
269  *  mode: c
270  *  c-basic-offset: 8
271  * End:
272  */