Skip to content

Commit ece56e4

Browse files
mdouchapevik
authored andcommitted
aio_cancel_3-1: Rewrite test
The test schedules multiple async writes into a file and then hopes that at least one will block long enough that it can be canceled before completion. Use a socket pair instead of a file to force async writes to block indefinitely and make sure at least one can be canceled. Then cancel all requests on the input socket and check that all signals have been delivered and the expected number of requests has been canceled. This fixes a race condition where aio_cancel() could be delayed until after all writes have already completed, making the test unreliable. Link: https://lore.kernel.org/ltp/20260224162726.28933-1-mdoucha@suse.cz/ Acked-by: Andrea Cervesato <andrea.cervesato@suse.com> Reviewed-by: Petr Vorel <pvorel@suse.cz> Signed-off-by: Martin Doucha <mdoucha@suse.cz>
1 parent 4575292 commit ece56e4

File tree

1 file changed

+48
-77
lines changed
  • testcases/open_posix_testsuite/conformance/interfaces/aio_cancel

1 file changed

+48
-77
lines changed

testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/3-1.c

Lines changed: 48 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2004, Bull SA. All rights reserved.
3+
* Copyright (c) 2026 SUSE LLC
34
* Created by: Laurent.Vivier@bull.net
45
* This file is licensed under the GPL license. For the full content
56
* of this license, see the COPYING file at the top level of this
@@ -14,143 +15,113 @@
1415
*
1516
* method:
1617
*
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
2725
*
2826
*/
2927

30-
#include <stdio.h>
3128
#include <sys/types.h>
3229
#include <unistd.h>
3330
#include <sys/stat.h>
3431
#include <fcntl.h>
35-
#include <string.h>
36-
#include <errno.h>
3732
#include <signal.h>
38-
#include <stdlib.h>
39-
#include <aio.h>
4033
#include <time.h>
4134

4235
#include "posixtest.h"
43-
#include "tempfile.h"
36+
#include "aio_test.h"
4437

4538
#define TNAME "aio_cancel/3-1.c"
4639

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
4943

50-
static volatile int countdown = BUF_NB;
44+
static volatile int countdown = WRITE_COUNT;
5145
static volatile int canceled;
46+
static int fds[2];
47+
static struct aiocb aiocb[WRITE_COUNT];
5248

5349
static void sig_handler(int signum PTS_ATTRIBUTE_UNUSED, siginfo_t *info,
54-
void *context PTS_ATTRIBUTE_UNUSED)
50+
void *context PTS_ATTRIBUTE_UNUSED)
5551
{
5652
struct aiocb *a = info->si_value.sival_ptr;
5753

5854
if (aio_error(a) == ECANCELED)
5955
canceled++;
6056

6157
aio_return(a); /* free entry */
62-
6358
countdown--;
6459
}
6560

6661
int main(void)
6762
{
68-
char tmpfname[PATH_MAX];
69-
int fd;
70-
struct aiocb *aiocb_list[BUF_NB];
71-
struct aiocb *aiocb;
7263
struct sigaction action;
7364
struct timespec processing_completion_ts = {0, 10000000};
7465
int i;
7566

7667
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));
7870
return PTS_UNSUPPORTED;
7971
}
8072

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-
9173
/* install signal handler */
92-
9374
action.sa_sigaction = sig_handler;
9475
sigemptyset(&action.sa_mask);
9576
action.sa_flags = SA_SIGINFO | SA_RESTART;
77+
9678
if (sigaction(SIGRTMIN + 1, &action, NULL)) {
9779
printf(TNAME " Error at sigaction(): %s\n", strerror(errno));
98-
return PTS_FAIL;
80+
return PTS_UNRESOLVED;
9981
}
10082

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;
12685

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;
12992

130-
for (i = 0; i < BUF_NB; i++) {
131-
if (aio_write(aiocb_list[i]) == -1) {
93+
if (aio_write(&aiocb[i]) == -1) {
13294
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);
13497
return PTS_FAIL;
13598
}
13699
}
137100

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) {
143103
printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
104+
cleanup_aio(fds, aiocb, WRITE_COUNT);
144105
return PTS_FAIL;
145106
}
146107

147-
close(fd);
108+
cleanup_aio(fds, aiocb, WRITE_COUNT);
148109

149-
while (countdown)
110+
/* wait for signal delivery */
111+
for (i = 0; countdown && i < MAX_WAIT_RETRIES; i++)
150112
nanosleep(&processing_completion_ts, NULL);
151113

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+
}
154125

155126
printf("Test PASSED\n");
156127
return PTS_PASS;

0 commit comments

Comments
 (0)