|
1 | 1 | /* |
2 | 2 | * Copyright (c) 2004, Bull SA. All rights reserved. |
| 3 | + * Copyright (c) 2026 SUSE LLC |
3 | 4 | * Created by: Laurent.Vivier@bull.net |
4 | 5 | * This file is licensed under the GPL license. For the full content |
5 | 6 | * of this license, see the COPYING file at the top level of this |
|
14 | 15 | * |
15 | 16 | * method: |
16 | 17 | * |
17 | | - * we queue a lot of aio_write() with a valid sigevent to a file descriptor |
18 | | - * next we try to cancel all operations on this file descriptor |
19 | | - * we guess some have been finished, other are in progress, |
20 | | - * other are waiting |
21 | | - * we guess we can cancel all operations waiting |
22 | | - * then we analyze aio_error() in the event handler |
23 | | - * if aio_error() is ECANCELED, the test is passed |
24 | | - * otherwise, we don't know (perhaps we haven't cancel any operation ?) |
25 | | - * if number of sig event is not equal to number of aio_write() |
26 | | - * the test fails (in fact it hangs). |
| 18 | + * open a pair of sockets and queue writes to them with aio_write() |
| 19 | + * execute aio_cancel() on the socket |
| 20 | + * then analyze aio_error() in the event handler |
| 21 | + * if number of sig events is not equal to number of write requests, |
| 22 | + * the test fails |
| 23 | + * if aio_error() returns ECANCELED for the expected requests, |
| 24 | + * the test passes |
27 | 25 | * |
28 | 26 | */ |
29 | 27 |
|
30 | | -#include <stdio.h> |
31 | 28 | #include <sys/types.h> |
32 | 29 | #include <unistd.h> |
33 | 30 | #include <sys/stat.h> |
34 | 31 | #include <fcntl.h> |
35 | | -#include <string.h> |
36 | | -#include <errno.h> |
37 | 32 | #include <signal.h> |
38 | | -#include <stdlib.h> |
39 | | -#include <aio.h> |
40 | 33 | #include <time.h> |
41 | 34 |
|
42 | 35 | #include "posixtest.h" |
43 | | -#include "tempfile.h" |
| 36 | +#include "aio_test.h" |
44 | 37 |
|
45 | 38 | #define TNAME "aio_cancel/3-1.c" |
46 | 39 |
|
47 | | -#define BUF_NB 128 |
48 | | -#define BUF_SIZE (1024 * 1024) |
| 40 | +#define WRITE_COUNT 8 |
| 41 | +#define MAX_COMPLETE 3 |
| 42 | +#define MAX_WAIT_RETRIES 100 |
49 | 43 |
|
50 | | -static volatile int countdown = BUF_NB; |
| 44 | +static volatile int countdown = WRITE_COUNT; |
51 | 45 | static volatile int canceled; |
| 46 | +static int fds[2]; |
| 47 | +static struct aiocb aiocb[WRITE_COUNT]; |
52 | 48 |
|
53 | 49 | static void sig_handler(int signum PTS_ATTRIBUTE_UNUSED, siginfo_t *info, |
54 | | - void *context PTS_ATTRIBUTE_UNUSED) |
| 50 | + void *context PTS_ATTRIBUTE_UNUSED) |
55 | 51 | { |
56 | 52 | struct aiocb *a = info->si_value.sival_ptr; |
57 | 53 |
|
58 | 54 | if (aio_error(a) == ECANCELED) |
59 | 55 | canceled++; |
60 | 56 |
|
61 | 57 | aio_return(a); /* free entry */ |
62 | | - |
63 | 58 | countdown--; |
64 | 59 | } |
65 | 60 |
|
66 | 61 | int main(void) |
67 | 62 | { |
68 | | - char tmpfname[PATH_MAX]; |
69 | | - int fd; |
70 | | - struct aiocb *aiocb_list[BUF_NB]; |
71 | | - struct aiocb *aiocb; |
72 | 63 | struct sigaction action; |
73 | 64 | struct timespec processing_completion_ts = {0, 10000000}; |
74 | 65 | int i; |
75 | 66 |
|
76 | 67 | if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L) { |
77 | | - printf(TNAME " %ld\n", sysconf(_SC_ASYNCHRONOUS_IO)); |
| 68 | + printf(TNAME " Unsupported AIO version: %ld\n", |
| 69 | + sysconf(_SC_ASYNCHRONOUS_IO)); |
78 | 70 | return PTS_UNSUPPORTED; |
79 | 71 | } |
80 | 72 |
|
81 | | - PTS_GET_TMP_FILENAME(tmpfname, "pts_aio_cancel_3_1"); |
82 | | - unlink(tmpfname); |
83 | | - fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); |
84 | | - if (fd == -1) { |
85 | | - printf(TNAME " Error at open(): %s\n", strerror(errno)); |
86 | | - return PTS_UNRESOLVED; |
87 | | - } |
88 | | - |
89 | | - unlink(tmpfname); |
90 | | - |
91 | 73 | /* install signal handler */ |
92 | | - |
93 | 74 | action.sa_sigaction = sig_handler; |
94 | 75 | sigemptyset(&action.sa_mask); |
95 | 76 | action.sa_flags = SA_SIGINFO | SA_RESTART; |
| 77 | + |
96 | 78 | if (sigaction(SIGRTMIN + 1, &action, NULL)) { |
97 | 79 | printf(TNAME " Error at sigaction(): %s\n", strerror(errno)); |
98 | | - return PTS_FAIL; |
| 80 | + return PTS_UNRESOLVED; |
99 | 81 | } |
100 | 82 |
|
101 | | - /* create AIO req */ |
102 | | - |
103 | | - for (i = 0; i < BUF_NB; i++) { |
104 | | - aiocb = malloc(sizeof(struct aiocb)); |
105 | | - if (aiocb == NULL) { |
106 | | - printf(TNAME " Error at malloc(): %s\n", |
107 | | - strerror(errno)); |
108 | | - return PTS_FAIL; |
109 | | - } |
110 | | - |
111 | | - aiocb->aio_fildes = fd; |
112 | | - aiocb->aio_buf = malloc(BUF_SIZE); |
113 | | - if (aiocb->aio_buf == NULL) { |
114 | | - printf(TNAME " Error at malloc(): %s\n", |
115 | | - strerror(errno)); |
116 | | - return PTS_FAIL; |
117 | | - } |
118 | | - |
119 | | - aiocb->aio_nbytes = BUF_SIZE; |
120 | | - aiocb->aio_offset = 0; |
121 | | - |
122 | | - aiocb->aio_sigevent.sigev_notify = SIGEV_SIGNAL; |
123 | | - aiocb->aio_sigevent.sigev_signo = SIGRTMIN + 1; |
124 | | - aiocb->aio_sigevent.sigev_value.sival_ptr = aiocb; |
125 | | - aiocb->aio_reqprio = 0; |
| 83 | + if (setup_aio(TNAME, fds, aiocb, WRITE_COUNT)) |
| 84 | + return PTS_UNRESOLVED; |
126 | 85 |
|
127 | | - aiocb_list[i] = aiocb; |
128 | | - } |
| 86 | + /* submit AIO req */ |
| 87 | + for (i = 0; i < WRITE_COUNT; i++) { |
| 88 | + aiocb[i].aio_sigevent.sigev_notify = SIGEV_SIGNAL; |
| 89 | + aiocb[i].aio_sigevent.sigev_signo = SIGRTMIN + 1; |
| 90 | + aiocb[i].aio_sigevent.sigev_value.sival_ptr = &aiocb[i]; |
| 91 | + aiocb[i].aio_reqprio = 0; |
129 | 92 |
|
130 | | - for (i = 0; i < BUF_NB; i++) { |
131 | | - if (aio_write(aiocb_list[i]) == -1) { |
| 93 | + if (aio_write(&aiocb[i]) == -1) { |
132 | 94 | printf(TNAME " loop %d: Error at aio_write(): %s\n", |
133 | | - i, strerror(errno)); |
| 95 | + i, strerror(errno)); |
| 96 | + cleanup_aio(fds, aiocb, WRITE_COUNT); |
134 | 97 | return PTS_FAIL; |
135 | 98 | } |
136 | 99 | } |
137 | 100 |
|
138 | | - /* try to cancel all |
139 | | - * we hope to have enough time to cancel at least one |
140 | | - */ |
141 | | - |
142 | | - if (aio_cancel(fd, NULL) == -1) { |
| 101 | + /* cancel all requests */ |
| 102 | + if (aio_cancel(fds[0], NULL) == -1) { |
143 | 103 | printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno)); |
| 104 | + cleanup_aio(fds, aiocb, WRITE_COUNT); |
144 | 105 | return PTS_FAIL; |
145 | 106 | } |
146 | 107 |
|
147 | | - close(fd); |
| 108 | + cleanup_aio(fds, aiocb, WRITE_COUNT); |
148 | 109 |
|
149 | | - while (countdown) |
| 110 | + /* wait for signal delivery */ |
| 111 | + for (i = 0; countdown && i < MAX_WAIT_RETRIES; i++) |
150 | 112 | nanosleep(&processing_completion_ts, NULL); |
151 | 113 |
|
152 | | - if (!canceled) |
153 | | - return PTS_UNRESOLVED; |
| 114 | + if (countdown) { |
| 115 | + printf(TNAME " %d task completion signals were not delivered", |
| 116 | + countdown); |
| 117 | + return PTS_FAIL; |
| 118 | + } |
| 119 | + |
| 120 | + if (canceled < WRITE_COUNT - MAX_COMPLETE) { |
| 121 | + printf(TNAME " %d AIO requests got canceled, expected %d", |
| 122 | + canceled, WRITE_COUNT - MAX_COMPLETE); |
| 123 | + return PTS_FAIL; |
| 124 | + } |
154 | 125 |
|
155 | 126 | printf("Test PASSED\n"); |
156 | 127 | return PTS_PASS; |
|
0 commit comments