t_aio_suspend.c revision 1.1 1 /* $NetBSD: t_aio_suspend.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */
2
3 /*
4 * Copyright (c) 2025 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <atf-c.h>
31
32 #include <aio.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <signal.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <time.h>
43 #include <unistd.h>
44
45 static int mktemp_file(char *, size_t);
46 static void fill_pattern(uint8_t *, size_t, uint8_t);
47 static void wait_cb(struct aiocb *);
48
49 static int
50 mktemp_file(char *path, size_t pathlen)
51 {
52 int fd, n;
53
54 n = snprintf(path, pathlen, "t_aio_suspend.XXXXXX");
55 ATF_REQUIRE(n > 0 && (size_t)n < pathlen);
56
57 fd = mkstemp(path);
58 ATF_REQUIRE(fd >= 0);
59
60 return fd;
61 }
62
63 static void
64 fill_pattern(uint8_t *buf, size_t len, uint8_t seed)
65 {
66 size_t i;
67
68 for (i = 0; i < len; i++) {
69 buf[i] = (uint8_t)(seed + (i & 0xff));
70 }
71 }
72
73 static void
74 wait_cb(struct aiocb *cb)
75 {
76 const struct aiocb *one[1];
77 int rv;
78
79 one[0] = cb;
80 while (aio_error(cb) == EINPROGRESS) {
81 rv = aio_suspend(one, 1, NULL);
82 ATF_REQUIRE_EQ(0, rv);
83 }
84 if (aio_error(cb) == 0) {
85 aio_return(cb);
86 }
87 }
88
89 ATF_TC_WITHOUT_HEAD(suspend_any);
90 ATF_TC_BODY(suspend_any, tc)
91 {
92 char path[64];
93 int fd, rv;
94 const size_t blksz = 4096;
95 uint8_t *buf0, *buf1;
96 struct aiocb cb0, cb1;
97 const struct aiocb *list[2];
98 int done;
99
100 fd = mktemp_file(path, sizeof(path));
101
102 buf0 = malloc(blksz);
103 buf1 = malloc(blksz);
104 ATF_REQUIRE(buf0 != NULL && buf1 != NULL);
105 fill_pattern(buf0, blksz, 0x20);
106 fill_pattern(buf1, blksz, 0x40);
107
108 memset(&cb0, 0, sizeof(cb0));
109 cb0.aio_fildes = fd;
110 cb0.aio_buf = buf0;
111 cb0.aio_nbytes = blksz;
112 cb0.aio_offset = 0;
113
114 memset(&cb1, 0, sizeof(cb1));
115 cb1.aio_fildes = fd;
116 cb1.aio_buf = buf1;
117 cb1.aio_nbytes = blksz;
118 cb1.aio_offset = blksz;
119
120 ATF_REQUIRE_EQ(0, aio_write(&cb0));
121 ATF_REQUIRE_EQ(0, aio_write(&cb1));
122
123 list[0] = &cb0;
124 list[1] = &cb1;
125
126 rv = aio_suspend(list, 2, NULL);
127 ATF_REQUIRE_EQ(0, rv);
128
129 done = 0;
130 if (aio_error(&cb0) != EINPROGRESS) {
131 done++;
132 if (aio_error(&cb0) == 0) {
133 ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb0));
134 } else {
135 ATF_REQUIRE_EQ(ECANCELED, aio_error(&cb0));
136 ATF_REQUIRE_EQ(-1, aio_return(&cb0));
137 }
138 }
139 if (aio_error(&cb1) != EINPROGRESS) {
140 done++;
141 if (aio_error(&cb1) == 0) {
142 ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb1));
143 } else {
144 ATF_REQUIRE_EQ(ECANCELED, aio_error(&cb1));
145 ATF_REQUIRE_EQ(-1, aio_return(&cb1));
146 }
147 }
148 ATF_REQUIRE(done >= 1);
149
150 if (aio_error(&cb0) == EINPROGRESS) {
151 wait_cb(&cb0);
152 }
153 if (aio_error(&cb1) == EINPROGRESS) {
154 wait_cb(&cb1);
155 }
156
157 rv = close(fd);
158 ATF_REQUIRE_EQ(0, rv);
159 rv = unlink(path);
160 ATF_REQUIRE_EQ(0, rv);
161
162 free(buf0);
163 free(buf1);
164 }
165
166 ATF_TP_ADD_TCS(tp)
167 {
168 ATF_TP_ADD_TC(tp, suspend_any);
169 return atf_no_error();
170 }
171