mirror of
https://github.com/openharmony/third_party_liburing.git
synced 2026-07-20 22:58:41 -04:00
Merge branch 'cancel-fd-all'
* cancel-fd-all: test/poll-cancel-all: add async read test case test/poll-cancel-all: test IORING_ASYNC_CANCEL_ANY io_uring.h: add IORING_ASYNC_CANCEL_ANY test/poll-cancel-all: abort test if cancel flags not supported test/poll-cancel-all: add test case canceling a subset of pending test/poll-cancel-all: test issuing CANCEL_ALL | CANCEL_FD liburing.h: add io_uring_prep_cancel_fd() io_uring: add new cancel flags
This commit is contained in:
@@ -511,6 +511,13 @@ static inline void io_uring_prep_cancel(struct io_uring_sqe *sqe,
|
||||
sqe->cancel_flags = (__u32) flags;
|
||||
}
|
||||
|
||||
static inline void io_uring_prep_cancel_fd(struct io_uring_sqe *sqe, int fd,
|
||||
unsigned int flags)
|
||||
{
|
||||
io_uring_prep_rw(IORING_OP_ASYNC_CANCEL, sqe, fd, NULL, 0, 0);
|
||||
sqe->cancel_flags = (__u32) flags | IORING_ASYNC_CANCEL_FD;
|
||||
}
|
||||
|
||||
static inline void io_uring_prep_link_timeout(struct io_uring_sqe *sqe,
|
||||
struct __kernel_timespec *ts,
|
||||
unsigned flags)
|
||||
|
||||
@@ -191,6 +191,18 @@ enum {
|
||||
#define IORING_POLL_UPDATE_EVENTS (1U << 1)
|
||||
#define IORING_POLL_UPDATE_USER_DATA (1U << 2)
|
||||
|
||||
/*
|
||||
* ASYNC_CANCEL flags.
|
||||
*
|
||||
* IORING_ASYNC_CANCEL_ALL Cancel all requests that match the given key
|
||||
* IORING_ASYNC_CANCEL_FD Key off 'fd' for cancelation rather than the
|
||||
* request 'user_data'
|
||||
* IORING_ASYNC_CANCEL_ANY Match any request
|
||||
*/
|
||||
#define IORING_ASYNC_CANCEL_ALL (1U << 0)
|
||||
#define IORING_ASYNC_CANCEL_FD (1U << 1)
|
||||
#define IORING_ASYNC_CANCEL_ANY (1U << 2)
|
||||
|
||||
/*
|
||||
* IO completion data structure (Completion Queue Entry)
|
||||
*/
|
||||
|
||||
@@ -109,6 +109,7 @@ test_srcs := \
|
||||
pipe-reuse.c \
|
||||
poll.c \
|
||||
poll-cancel.c \
|
||||
poll-cancel-all.c \
|
||||
poll-cancel-ton.c \
|
||||
poll-link.c \
|
||||
poll-many.c \
|
||||
|
||||
@@ -0,0 +1,472 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Description: Test IORING_ASYNC_CANCEL_{ALL,FD}
|
||||
*
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "liburing.h"
|
||||
|
||||
static int no_cancel_flags;
|
||||
|
||||
static int test1(struct io_uring *ring, int *fd)
|
||||
{
|
||||
struct io_uring_sqe *sqe;
|
||||
struct io_uring_cqe *cqe;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
io_uring_prep_poll_add(sqe, fd[0], POLLIN);
|
||||
sqe->user_data = i + 1;
|
||||
}
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 8) {
|
||||
fprintf(stderr, "sqe submit failed: %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark CANCEL_ALL to cancel all matching the key, and use
|
||||
* CANCEL_FD to cancel requests matching the specified fd.
|
||||
* This should cancel all the pending poll requests on the pipe
|
||||
* input.
|
||||
*/
|
||||
io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
|
||||
sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
|
||||
sqe->fd = fd[0];
|
||||
sqe->user_data = 100;
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 1) {
|
||||
fprintf(stderr, "child: sqe submit failed: %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
if (no_cancel_flags)
|
||||
break;
|
||||
ret = io_uring_wait_cqe(ring, &cqe);
|
||||
if (ret) {
|
||||
fprintf(stderr, "wait=%d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
switch (cqe->user_data) {
|
||||
case 100:
|
||||
if (cqe->res == -EINVAL) {
|
||||
no_cancel_flags = 1;
|
||||
break;
|
||||
}
|
||||
if (cqe->res != 8) {
|
||||
fprintf(stderr, "canceled %d\n", cqe->res);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 1 ... 8:
|
||||
if (cqe->res != -ECANCELED) {
|
||||
fprintf(stderr, "poll res %d\n", cqe->res);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid user_data %lu\n",
|
||||
(unsigned long) cqe->user_data);
|
||||
return 1;
|
||||
}
|
||||
io_uring_cqe_seen(ring, cqe);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test2(struct io_uring *ring, int *fd)
|
||||
{
|
||||
struct io_uring_sqe *sqe;
|
||||
struct io_uring_cqe *cqe;
|
||||
int ret, i, fd2[2];
|
||||
|
||||
if (pipe(fd2) < 0) {
|
||||
perror("pipe");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(i & 1))
|
||||
io_uring_prep_poll_add(sqe, fd[0], POLLIN);
|
||||
else
|
||||
io_uring_prep_poll_add(sqe, fd2[0], POLLIN);
|
||||
sqe->user_data = i & 1;
|
||||
}
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 8) {
|
||||
fprintf(stderr, "sqe submit failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark CANCEL_ALL to cancel all matching the key, and use
|
||||
* CANCEL_FD to cancel requests matching the specified fd.
|
||||
* This should cancel all the pending poll requests on the pipe
|
||||
* input.
|
||||
*/
|
||||
io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
|
||||
sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
|
||||
sqe->fd = fd[0];
|
||||
sqe->user_data = 100;
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 1) {
|
||||
fprintf(stderr, "sqe submit failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
ret = io_uring_wait_cqe(ring, &cqe);
|
||||
if (ret) {
|
||||
fprintf(stderr, "wait=%d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
switch (cqe->user_data) {
|
||||
case 100:
|
||||
if (cqe->res != 4) {
|
||||
fprintf(stderr, "canceled %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
if (cqe->res != -ECANCELED) {
|
||||
fprintf(stderr, "poll res %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid user_data %lu\n",
|
||||
(unsigned long) cqe->user_data);
|
||||
goto err;
|
||||
}
|
||||
io_uring_cqe_seen(ring, cqe);
|
||||
}
|
||||
|
||||
usleep(1000);
|
||||
|
||||
/*
|
||||
* Should not have any pending CQEs now
|
||||
*/
|
||||
ret = io_uring_peek_cqe(ring, &cqe);
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Unexpected extra cancel cqe\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark CANCEL_ALL to cancel all matching the key, and use
|
||||
* CANCEL_FD to cancel requests matching the specified fd.
|
||||
* This should cancel all the pending poll requests on the pipe
|
||||
* input.
|
||||
*/
|
||||
io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
|
||||
sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
|
||||
sqe->fd = fd2[0];
|
||||
sqe->user_data = 100;
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 1) {
|
||||
fprintf(stderr, "sqe submit failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
ret = io_uring_wait_cqe(ring, &cqe);
|
||||
if (ret) {
|
||||
fprintf(stderr, "wait=%d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
switch (cqe->user_data) {
|
||||
case 100:
|
||||
if (cqe->res != 4) {
|
||||
fprintf(stderr, "canceled %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (cqe->res != -ECANCELED) {
|
||||
fprintf(stderr, "poll res %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid user_data %lu\n",
|
||||
(unsigned long) cqe->user_data);
|
||||
goto err;
|
||||
}
|
||||
io_uring_cqe_seen(ring, cqe);
|
||||
}
|
||||
|
||||
close(fd2[0]);
|
||||
close(fd2[1]);
|
||||
return 0;
|
||||
err:
|
||||
close(fd2[0]);
|
||||
close(fd2[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test3(struct io_uring *ring, int *fd)
|
||||
{
|
||||
struct io_uring_sqe *sqe;
|
||||
struct io_uring_cqe *cqe;
|
||||
int ret, i, fd2[2];
|
||||
|
||||
if (pipe(fd2) < 0) {
|
||||
perror("pipe");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(i & 1)) {
|
||||
io_uring_prep_poll_add(sqe, fd[0], POLLIN);
|
||||
sqe->flags |= IOSQE_ASYNC;
|
||||
} else
|
||||
io_uring_prep_poll_add(sqe, fd2[0], POLLIN);
|
||||
sqe->user_data = i & 1;
|
||||
}
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 8) {
|
||||
fprintf(stderr, "child: sqe submit failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
usleep(10000);
|
||||
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark CANCEL_ALL to cancel all matching the key, and use
|
||||
* CANCEL_FD to cancel requests matching the specified fd.
|
||||
* This should cancel all the pending poll requests on the pipe
|
||||
* input.
|
||||
*/
|
||||
io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
|
||||
sqe->cancel_flags |= IORING_ASYNC_CANCEL_ANY;
|
||||
sqe->fd = 0;
|
||||
sqe->user_data = 100;
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 1) {
|
||||
fprintf(stderr, "child: sqe submit failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
ret = io_uring_wait_cqe(ring, &cqe);
|
||||
if (ret) {
|
||||
fprintf(stderr, "wait=%d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
switch (cqe->user_data) {
|
||||
case 100:
|
||||
if (cqe->res != 8) {
|
||||
fprintf(stderr, "canceled %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
if (cqe->res != -ECANCELED) {
|
||||
fprintf(stderr, "poll res %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid user_data %lu\n",
|
||||
(unsigned long) cqe->user_data);
|
||||
goto err;
|
||||
}
|
||||
io_uring_cqe_seen(ring, cqe);
|
||||
}
|
||||
|
||||
close(fd2[0]);
|
||||
close(fd2[1]);
|
||||
return 0;
|
||||
err:
|
||||
close(fd2[0]);
|
||||
close(fd2[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test4(struct io_uring *ring, int *fd)
|
||||
{
|
||||
struct io_uring_sqe *sqe;
|
||||
struct io_uring_cqe *cqe;
|
||||
char buffer[32];
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
io_uring_prep_read(sqe, fd[0], &buffer, sizeof(buffer), 0);
|
||||
sqe->flags |= IOSQE_ASYNC;
|
||||
sqe->user_data = i + 1;
|
||||
}
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 8) {
|
||||
fprintf(stderr, "child: sqe submit failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
usleep(10000);
|
||||
|
||||
sqe = io_uring_get_sqe(ring);
|
||||
if (!sqe) {
|
||||
fprintf(stderr, "get sqe failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark CANCEL_ALL to cancel all matching the key, and use
|
||||
* CANCEL_FD to cancel requests matching the specified fd.
|
||||
* This should cancel all the pending poll requests on the pipe
|
||||
* input.
|
||||
*/
|
||||
io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
|
||||
sqe->cancel_flags |= IORING_ASYNC_CANCEL_ANY;
|
||||
sqe->fd = 0;
|
||||
sqe->user_data = 100;
|
||||
|
||||
ret = io_uring_submit(ring);
|
||||
if (ret < 1) {
|
||||
fprintf(stderr, "child: sqe submit failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
ret = io_uring_wait_cqe(ring, &cqe);
|
||||
if (ret) {
|
||||
fprintf(stderr, "wait=%d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
switch (cqe->user_data) {
|
||||
case 100:
|
||||
if (cqe->res != 8) {
|
||||
fprintf(stderr, "canceled %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case 1 ... 8:
|
||||
if (cqe->res != -ECANCELED) {
|
||||
fprintf(stderr, "poll res %d\n", cqe->res);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid user_data %lu\n",
|
||||
(unsigned long) cqe->user_data);
|
||||
goto err;
|
||||
}
|
||||
io_uring_cqe_seen(ring, cqe);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct io_uring ring;
|
||||
int ret, fd[2];
|
||||
|
||||
if (argc > 1)
|
||||
return 0;
|
||||
|
||||
if (pipe(fd) < 0) {
|
||||
perror("pipe");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = io_uring_queue_init(8, &ring, 0);
|
||||
if (ret) {
|
||||
fprintf(stderr, "ring setup failed: %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = test1(&ring, fd);
|
||||
if (ret) {
|
||||
fprintf(stderr, "test1 failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (no_cancel_flags)
|
||||
return 0;
|
||||
|
||||
ret = test2(&ring, fd);
|
||||
if (ret) {
|
||||
fprintf(stderr, "test2 failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = test3(&ring, fd);
|
||||
if (ret) {
|
||||
fprintf(stderr, "test3 failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = test4(&ring, fd);
|
||||
if (ret) {
|
||||
fprintf(stderr, "test4 failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user