[LTP] [PATCH 2/2] aio_cancel_6-1: Rewrite test
Martin Doucha
mdoucha@suse.cz
Tue Apr 28 15:32:12 CEST 2026
The test schedules multiple async writes into a file and then hopes that
at least one will block long enough that aio_cancel() will cancel it.
Use a socket pair instead of a file to force async writes to block
indefinitely, then cancel one of the blocked writes. This fixes a race
condition where aio_cancel() could be called after the target write
has already finished. Also improve result checks to verify that
non-canceled writes are still pending.
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
.../conformance/interfaces/aio_cancel/6-1.c | 135 +++++++-----------
1 file changed, 48 insertions(+), 87 deletions(-)
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/6-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/6-1.c
index 2e3d64742..0282677a8 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/6-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/6-1.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, Bull SA. All rights reserved.
+ * Copyright (c) 2026 SUSE LLC
* Created by: Laurent.Vivier@bull.net
* This file is licensed under the GPL license. For the full content
* of this license, see the COPYING file at the top level of this
@@ -14,128 +15,88 @@
*
* method:
*
- * queue a lot of aio_write() to a given fildes.
- * try to cancel the last one submited
- * if aio_error() is ECANCELED and aio_cancel() is AIO_CANCELED
- * test is passed
- * if aio_error() is ECANCELED and aio_cancel() is NOT AIO_CANCELED
- * test is failed
- * if there is no aio_error() with ECANCELED and
- * aio_cancel() is AIO_CANCELED
- * test is failed
- * otherwise test is unresolved
+ * queue multiple aio_write()s to a given socket
+ * try to cancel a task which hasn't been started yet
+ * if aio_cancel() return value is not AIO_CANCELED, the test failed
+ * for blocked tasks, aio_error() must be:
+ * - ECANCELED if aio_cancel() was called on it
+ * - EINPROGRESS otherwise
+ * if all aio_error() values match, the test passed, otherwise it failed
*
*/
-#include <stdio.h>
-#include <sys/types.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <aio.h>
#include "posixtest.h"
-#include "tempfile.h"
+#include "aio_test.h"
#define TNAME "aio_cancel/6-1.c"
-#define BUF_NB 128
-#define BUF_SIZE 1024
+#define WRITE_COUNT 8
+#define MAX_COMPLETE 3
+#define CANCELED_TASK 5
+
+static int fds[2];
+static struct aiocb aiocb[WRITE_COUNT];
int test_main(int argc PTS_ATTRIBUTE_UNUSED, char **argv PTS_ATTRIBUTE_UNUSED)
{
- char tmpfname[PATH_MAX];
- int fd;
- struct aiocb *aiocb[BUF_NB];
int i;
- int in_progress;
int gret;
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
return PTS_UNSUPPORTED;
- PTS_GET_TMP_FILENAME(tmpfname, "pts_aio_cancel_6_1");
- unlink(tmpfname);
- fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
- if (fd == -1) {
- printf(TNAME " Error at open(): %s\n", strerror(errno));
+ if (setup_aio(TNAME, fds, aiocb, WRITE_COUNT))
return PTS_UNRESOLVED;
- }
-
- unlink(tmpfname);
/* create AIO req */
-
- for (i = 0; i < BUF_NB; i++) {
- aiocb[i] = calloc(1, sizeof(struct aiocb));
- if (aiocb[i] == NULL) {
- printf(TNAME " Error at malloc(): %s\n",
- strerror(errno));
- return PTS_UNRESOLVED;
- }
- aiocb[i]->aio_fildes = fd;
- aiocb[i]->aio_buf = malloc(BUF_SIZE);
- if (aiocb[i]->aio_buf == NULL) {
- printf(TNAME " Error at malloc(): %s\n",
- strerror(errno));
- return PTS_UNRESOLVED;
- }
- aiocb[i]->aio_nbytes = BUF_SIZE;
- aiocb[i]->aio_offset = 0;
- aiocb[i]->aio_sigevent.sigev_notify = SIGEV_NONE;
-
- if (aio_write(aiocb[i]) == -1) {
+ for (i = 0; i < WRITE_COUNT; i++) {
+ if (aio_write(&aiocb[i]) == -1) {
printf(TNAME " loop %d: Error at aio_write(): %s\n",
- i, strerror(errno));
+ i, strerror(errno));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
return PTS_FAIL;
}
}
/* try to cancel the last one queued */
-
- gret = aio_cancel(fd, aiocb[i - 1]);
+ gret = aio_cancel(fds[0], &aiocb[CANCELED_TASK]);
if (gret == -1) {
printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
return PTS_FAIL;
}
- close(fd);
-
- do {
- in_progress = 0;
- for (i = 0; i < BUF_NB; i++) {
- int ret;
-
- ret = (aio_error(aiocb[i]));
-
- if (ret == -1) {
- printf(TNAME " Error at aio_error(): %s\n",
- strerror(errno));
- return PTS_FAIL;
- } else if (ret == EINPROGRESS)
- in_progress = 1;
- else if (ret == ECANCELED) {
- if (gret == AIO_CANCELED) {
- printf("Test PASSED\n");
- return PTS_PASS;
- }
-
- printf(TNAME
- " aio_cancel() is not AIO_CANCELED\n");
- return PTS_FAIL;
- }
+ if (gret != AIO_CANCELED) {
+ printf(TNAME " Unexpected aio_cancel() return value: %s\n",
+ strerror(gret));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
+ return PTS_FAIL;
+ }
+
+ for (i = MAX_COMPLETE; i < WRITE_COUNT; i++) {
+ int exp_ret = (i == CANCELED_TASK) ? ECANCELED : EINPROGRESS;
+ int ret = aio_error(&aiocb[i]);
+
+ if (ret == -1) {
+ printf(TNAME " Error at aio_error(): %s\n",
+ strerror(errno));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
+ return PTS_FAIL;
}
- } while (in_progress);
- if (gret == AIO_CANCELED) {
- printf(TNAME
- " aio_cancel() is AIO_CANCELED without ECANCELED\n");
- return PTS_FAIL;
+ if (ret != exp_ret) {
+ printf(TNAME " Bad task #%d result %s",
+ i, strerror(ret));
+ printf(" (expected: %s)\n", strerror(exp_ret));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
+ return PTS_FAIL;
+ }
}
- return PTS_UNRESOLVED;
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
+ printf("Test PASSED\n");
+ return PTS_PASS;
}
--
2.53.0
More information about the ltp
mailing list