* [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket
@ 2025-08-22 13:57 Martin Doucha
2025-08-25 3:07 ` Li Wang via ltp
2025-08-28 10:26 ` Cyril Hrubis
0 siblings, 2 replies; 8+ messages in thread
From: Martin Doucha @ 2025-08-22 13:57 UTC (permalink / raw)
To: ltp
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.
Also add another case to the final result check because the aio_cancel()
call may happen between one write finishing and another write starting.
Then the cancel will be successful and all non-zero task results will be
ECANCELED.
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
Changes since v1: Rebased to current master.
Changes since v2:
- Changed argsize from unsigned int to socklen_t
- Improved test cleanup using a helper function
.../conformance/interfaces/aio_cancel/7-1.c | 85 +++++++++++++------
1 file changed, 57 insertions(+), 28 deletions(-)
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
index 34b263245..9ab72da87 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
@@ -29,71 +29,90 @@
#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 <sys/socket.h>
#include "posixtest.h"
-#include "tempfile.h"
#define TNAME "aio_cancel/7-1.c"
-#define BUF_NB 128
-#define BUF_SIZE 1024
+#define BUF_NB 8
+
+static int fds[2];
+static struct aiocb *aiocb[BUF_NB];
+
+static void cleanup(void)
+{
+ int i;
+
+ close(fds[1]);
+ close(fds[0]);
+
+ for (i = 0; i < BUF_NB; i++)
+ free((void *)aiocb[i]->aio_buf);
+}
int main(void)
{
- char tmpfname[PATH_MAX];
- int fd;
- struct aiocb *aiocb[BUF_NB];
int i;
int in_progress;
int gret;
+ int bufsize;
+ socklen_t argsize = sizeof(bufsize);
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
return PTS_UNSUPPORTED;
- PTS_GET_TMP_FILENAME(tmpfname, "pts_aio_cancel_7_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));
+ gret = socketpair(AF_UNIX, SOCK_DGRAM, 0, fds);
+ if (gret == -1) {
+ printf(TNAME " Error creating sockets(): %s\n",
+ strerror(errno));
+ return PTS_UNRESOLVED;
+ }
+
+ gret = getsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &bufsize, &argsize);
+ if (gret == -1) {
+ printf(TNAME " Error reading socket buffer size: %s\n",
+ strerror(errno));
+ cleanup();
return PTS_UNRESOLVED;
}
- unlink(tmpfname);
+ /* Socket buffer size is twice the maximum message size */
+ bufsize /= 2;
/* 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",
+ printf(TNAME " Error at calloc(): %s\n",
strerror(errno));
- close(fd);
+ cleanup();
return PTS_UNRESOLVED;
}
- aiocb[i]->aio_fildes = fd;
- aiocb[i]->aio_buf = malloc(BUF_SIZE);
+ aiocb[i]->aio_fildes = fds[0];
+ aiocb[i]->aio_buf = malloc(bufsize);
if (aiocb[i]->aio_buf == NULL) {
printf(TNAME " Error at malloc(): %s\n",
strerror(errno));
- close(fd);
+ cleanup();
return PTS_UNRESOLVED;
}
- aiocb[i]->aio_nbytes = BUF_SIZE;
+ aiocb[i]->aio_nbytes = bufsize;
aiocb[i]->aio_offset = 0;
aiocb[i]->aio_sigevent.sigev_notify = SIGEV_NONE;
if (aio_write(aiocb[i]) == -1) {
printf(TNAME " loop %d: Error at aio_write(): %s\n",
i, strerror(errno));
- close(fd);
+ cleanup();
return PTS_FAIL;
}
}
@@ -101,10 +120,10 @@ int main(void)
/* try to cancel all
* we hope to have enough time to cancel at least one
*/
- gret = aio_cancel(fd, NULL);
+ gret = aio_cancel(fds[0], NULL);
if (gret == -1) {
printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
- close(fd);
+ cleanup();
return PTS_FAIL;
}
@@ -117,9 +136,8 @@ int main(void)
case -1:
printf(TNAME " Error at aio_error(): %s\n",
strerror(errno));
- close(fd);
+ cleanup();
return PTS_FAIL;
- break;
case EINPROGRESS:
/* at this point, all operations should be:
* canceled
@@ -130,12 +148,24 @@ int main(void)
printf(TNAME
" Error at aio_error(): %s\n",
strerror(errno));
- close(fd);
+ cleanup();
return PTS_FAIL;
}
in_progress = 1;
break;
+ case ECANCELED:
+ /* aio_cancel() happened between one
+ * write finishing and another starting.
+ * aio_cancel() returned AIO_CANCELED
+ * and the first non-zero result is ECANCELED.
+ */
+ if (gret == AIO_CANCELED) {
+ printf("Test PASSED\n");
+ cleanup();
+ return PTS_PASS;
+ }
+ break;
case 0:
/* we seek one not canceled and check why.
* (perhaps) it has not been canceled
@@ -144,7 +174,7 @@ int main(void)
*/
if (gret == AIO_NOTCANCELED) {
printf("Test PASSED\n");
- close(fd);
+ cleanup();
return PTS_PASS;
}
break;
@@ -152,7 +182,6 @@ int main(void)
}
} while (in_progress);
- close(fd);
-
+ cleanup();
return PTS_UNRESOLVED;
}
--
2.50.1
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket
2025-08-22 13:57 [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket Martin Doucha
@ 2025-08-25 3:07 ` Li Wang via ltp
2025-09-01 16:19 ` Martin Doucha
2025-08-28 10:26 ` Cyril Hrubis
1 sibling, 1 reply; 8+ messages in thread
From: Li Wang via ltp @ 2025-08-25 3:07 UTC (permalink / raw)
To: Martin Doucha; +Cc: ltp
On Fri, Aug 22, 2025 at 9:57 PM Martin Doucha <mdoucha@suse.cz> wrote:
> 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.
>
> Also add another case to the final result check because the aio_cancel()
> call may happen between one write finishing and another write starting.
> Then the cancel will be successful and all non-zero task results will be
> ECANCELED.
>
> Signed-off-by: Martin Doucha <mdoucha@suse.cz>
> ---
>
> Changes since v1: Rebased to current master.
>
> Changes since v2:
> - Changed argsize from unsigned int to socklen_t
> - Improved test cleanup using a helper function
>
> .../conformance/interfaces/aio_cancel/7-1.c | 85 +++++++++++++------
> 1 file changed, 57 insertions(+), 28 deletions(-)
>
> diff --git
> a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
> b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
> index 34b263245..9ab72da87 100644
> ---
> a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
> +++
> b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
>
We need to update the code comments as well:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2004, Bull SA. All rights reserved.
* Copyright (c) Linux Test Project, 2025
*/
/*
* Assertion:
* aio_cancel() shall return AIO_NOTCANCELED if at least one requested
* operation cannot be canceled because it is already in progress.
*
* Method:
* 1. Queue multiple aio_write() requests to a given file descriptor.
* 2. Call aio_cancel() to attempt canceling all operations.
* 3. Check each operation's result using aio_error():
* - If aio_error() returns EINPROGRESS but aio_cancel() did not
return
* AIO_NOTCANCELED, the test FAILS.
* - If aio_error() returns 0 (success) and aio_cancel() returned
* AIO_NOTCANCELED, the test PASSES.
* - Otherwise, the test result is UNRESOLVED.
*/
> @@ -29,71 +29,90 @@
> #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 <sys/socket.h>
>
> #include "posixtest.h"
> -#include "tempfile.h"
>
> #define TNAME "aio_cancel/7-1.c"
>
> -#define BUF_NB 128
> -#define BUF_SIZE 1024
> +#define BUF_NB 8
> +
> +static int fds[2];
> +static struct aiocb *aiocb[BUF_NB];
> +
> +static void cleanup(void)
> +{
> + int i;
> +
> + close(fds[1]);
> + close(fds[0]);
> +
> + for (i = 0; i < BUF_NB; i++)
> + free((void *)aiocb[i]->aio_buf);
>
Agree, and maybe do something further:
for (i = 0; i < BUF_NB; i++) {
if (aiocb[i]) {
if (aiocb[i]->aio_buf)
free((void *)aiocb[i]->aio_buf);
free(aiocb[i]);
aiocb[i] = NULL;
}
}
> +}
>
> int main(void)
> {
> - char tmpfname[PATH_MAX];
> - int fd;
> - struct aiocb *aiocb[BUF_NB];
> int i;
> int in_progress;
> int gret;
> + int bufsize;
> + socklen_t argsize = sizeof(bufsize);
>
> if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
> return PTS_UNSUPPORTED;
>
> - PTS_GET_TMP_FILENAME(tmpfname, "pts_aio_cancel_7_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));
> + gret = socketpair(AF_UNIX, SOCK_DGRAM, 0, fds);
> + if (gret == -1) {
> + printf(TNAME " Error creating sockets(): %s\n",
> + strerror(errno));
> + return PTS_UNRESOLVED;
> + }
> +
> + gret = getsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &bufsize,
> &argsize);
> + if (gret == -1) {
> + printf(TNAME " Error reading socket buffer size: %s\n",
> + strerror(errno));
> + cleanup();
> return PTS_UNRESOLVED;
> }
>
> - unlink(tmpfname);
> + /* Socket buffer size is twice the maximum message size */
> + bufsize /= 2;
>
> /* 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",
> + printf(TNAME " Error at calloc(): %s\n",
> strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_UNRESOLVED;
> }
>
> - aiocb[i]->aio_fildes = fd;
> - aiocb[i]->aio_buf = malloc(BUF_SIZE);
> + aiocb[i]->aio_fildes = fds[0];
> + aiocb[i]->aio_buf = malloc(bufsize);
>
> if (aiocb[i]->aio_buf == NULL) {
> printf(TNAME " Error at malloc(): %s\n",
> strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_UNRESOLVED;
> }
>
> - aiocb[i]->aio_nbytes = BUF_SIZE;
> + aiocb[i]->aio_nbytes = bufsize;
> aiocb[i]->aio_offset = 0;
> aiocb[i]->aio_sigevent.sigev_notify = SIGEV_NONE;
>
> if (aio_write(aiocb[i]) == -1) {
> printf(TNAME " loop %d: Error at aio_write():
> %s\n",
> i, strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_FAIL;
> }
> }
> @@ -101,10 +120,10 @@ int main(void)
> /* try to cancel all
> * we hope to have enough time to cancel at least one
> */
> - gret = aio_cancel(fd, NULL);
> + gret = aio_cancel(fds[0], NULL);
> if (gret == -1) {
> printf(TNAME " Error at aio_cancel(): %s\n",
> strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_FAIL;
> }
>
> @@ -117,9 +136,8 @@ int main(void)
> case -1:
> printf(TNAME " Error at aio_error(): %s\n",
> strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_FAIL;
> - break;
> case EINPROGRESS:
> /* at this point, all operations should be:
> * canceled
> @@ -130,12 +148,24 @@ int main(void)
> printf(TNAME
> " Error at aio_error():
> %s\n",
> strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_FAIL;
> }
>
> in_progress = 1;
> break;
> + case ECANCELED:
> + /* aio_cancel() happened between one
> + * write finishing and another starting.
> + * aio_cancel() returned AIO_CANCELED
> + * and the first non-zero result is
> ECANCELED.
> + */
> + if (gret == AIO_CANCELED) {
> + printf("Test PASSED\n");
> + cleanup();
> + return PTS_PASS;
> + }
> + break;
> case 0:
> /* we seek one not canceled and check why.
> * (perhaps) it has not been canceled
> @@ -144,7 +174,7 @@ int main(void)
> */
> if (gret == AIO_NOTCANCELED) {
> printf("Test PASSED\n");
> - close(fd);
> + cleanup();
> return PTS_PASS;
> }
> break;
> @@ -152,7 +182,6 @@ int main(void)
> }
> } while (in_progress);
>
> - close(fd);
> -
> + cleanup();
> return PTS_UNRESOLVED;
> }
> --
> 2.50.1
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
>
--
Regards,
Li Wang
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket
2025-08-25 3:07 ` Li Wang via ltp
@ 2025-09-01 16:19 ` Martin Doucha
2025-09-10 9:22 ` Cyril Hrubis
0 siblings, 1 reply; 8+ messages in thread
From: Martin Doucha @ 2025-09-01 16:19 UTC (permalink / raw)
To: Li Wang; +Cc: ltp
On 25. 08. 25 5:07, Li Wang wrote:
> We need to update the code comments as well:
>
> // SPDX-License-Identifier: GPL-2.0-or-later
> /*
> * Copyright (c) 2004, Bull SA. All rights reserved.
> * Copyright (c) Linux Test Project, 2025
> */
>
> /*
> * Assertion:
> * aio_cancel() shall return AIO_NOTCANCELED if at least one requested
> * operation cannot be canceled because it is already in progress.
> *
> * Method:
> * 1. Queue multiple aio_write() requests to a given file descriptor.
> * 2. Call aio_cancel() to attempt canceling all operations.
> * 3. Check each operation's result using aio_error():
> * - If aio_error() returns EINPROGRESS but aio_cancel() did not
> return
> * AIO_NOTCANCELED, the test FAILS.
> * - If aio_error() returns 0 (success) and aio_cancel() returned
> * AIO_NOTCANCELED, the test PASSES.
> * - Otherwise, the test result is UNRESOLVED.
> */
Hmm, yes. But now that I read the test description again, I notice that
the additional check for aio_error() == ECANCELED does not fit the
intended scenario. The test should wait until aiocb[2] enters the
EINPROGRESS state before before calling aio_cancel(). I'll rewrite that
and send v4.
> +static void cleanup(void)
> +{
> + int i;
> +
> + close(fds[1]);
> + close(fds[0]);
> +
> + for (i = 0; i < BUF_NB; i++)
> + free((void *)aiocb[i]->aio_buf);
>
>
> Agree, and maybe do something further:
>
> for (i = 0; i < BUF_NB; i++) {
> if (aiocb[i]) {
> if (aiocb[i]->aio_buf)
> free((void *)aiocb[i]->aio_buf);
> free(aiocb[i]);
> aiocb[i] = NULL;
> }
> }
>
I forgot about the the aiocbs being dynamically allocated as well while
writing the cleanup() function. But the better solution would be to
remove the calloc()s entirely and have the aiocb array statically allocated.
--
Martin Doucha mdoucha@suse.cz
SW Quality Engineer
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket
2025-08-22 13:57 [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket Martin Doucha
2025-08-25 3:07 ` Li Wang via ltp
@ 2025-08-28 10:26 ` Cyril Hrubis
2025-09-01 14:49 ` Martin Doucha
1 sibling, 1 reply; 8+ messages in thread
From: Cyril Hrubis @ 2025-08-28 10:26 UTC (permalink / raw)
To: Martin Doucha; +Cc: ltp
Hi!
> - unlink(tmpfname);
> + /* Socket buffer size is twice the maximum message size */
> + bufsize /= 2;
>
> /* 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",
> + printf(TNAME " Error at calloc(): %s\n",
> strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_UNRESOLVED;
> }
>
> - aiocb[i]->aio_fildes = fd;
> - aiocb[i]->aio_buf = malloc(BUF_SIZE);
> + aiocb[i]->aio_fildes = fds[0];
> + aiocb[i]->aio_buf = malloc(bufsize);
>
> if (aiocb[i]->aio_buf == NULL) {
> printf(TNAME " Error at malloc(): %s\n",
> strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_UNRESOLVED;
> }
>
> - aiocb[i]->aio_nbytes = BUF_SIZE;
> + aiocb[i]->aio_nbytes = bufsize;
> aiocb[i]->aio_offset = 0;
> aiocb[i]->aio_sigevent.sigev_notify = SIGEV_NONE;
>
> if (aio_write(aiocb[i]) == -1) {
> printf(TNAME " loop %d: Error at aio_write(): %s\n",
> i, strerror(errno));
> - close(fd);
> + cleanup();
> return PTS_FAIL;
> }
> }
Do I get it right that we queue eight aio writes and four of them finish
before the socket buffer is full and then the writing gets stuck with
the fift one?
So in the end we have four finished writes, one in progress and three
canceled?
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket
2025-08-28 10:26 ` Cyril Hrubis
@ 2025-09-01 14:49 ` Martin Doucha
0 siblings, 0 replies; 8+ messages in thread
From: Martin Doucha @ 2025-09-01 14:49 UTC (permalink / raw)
To: Cyril Hrubis; +Cc: ltp
On 28. 08. 25 12:26, Cyril Hrubis wrote:
> Hi!
>
> Do I get it right that we queue eight aio writes and four of them finish
> before the socket buffer is full and then the writing gets stuck with
> the fift one?
>
> So in the end we have four finished writes, one in progress and three
> canceled?
Yes, that's roughly what the test expects to happen, both before and
after this patch. Except the file scenario didn't get stuck at all and
the socket version will get stuck on the third write since the socket
buffer is big enough for exactly 2 writes.
But there was a bunch of valid corner cases that would result in the
test failing without this patch:
- aio_cancel() was called before the first write started
- aio_cancel() was called after all writes finished
- aio_cancel was called between one write finishing and another starting
In all three cases, none of the passing combinations aio_cancel() and
aio_error() return values would match.
--
Martin Doucha mdoucha@suse.cz
SW Quality Engineer
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-09-15 14:52 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-22 13:57 [LTP] [PATCH v3] aio_cancel_7-1: Write into a socket Martin Doucha
2025-08-25 3:07 ` Li Wang via ltp
2025-09-01 16:19 ` Martin Doucha
2025-09-10 9:22 ` Cyril Hrubis
2025-09-10 9:23 ` Martin Doucha
2025-09-15 14:51 ` Martin Doucha
2025-08-28 10:26 ` Cyril Hrubis
2025-09-01 14:49 ` Martin Doucha
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.