1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd
4 * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
5 *
6 * Authors:
7 * Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
8 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
9 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
10 */
11
12 #include <errno.h>
13 #include <limits.h>
14
15 static int fd, fd_root, fd_nonblock, fd_maxint = INT_MAX - 1, fd_invalid = -1;
16
17 #include "mq_timed.h"
18
19 static struct tst_ts ts;
20 static void *bad_addr;
21
22 static struct test_case tcase[] = {
23 {
24 .fd = &fd,
25 .len = 0,
26 .ret = 0,
27 .err = 0,
28 },
29 {
30 .fd = &fd,
31 .len = 1,
32 .ret = 0,
33 .err = 0,
34 },
35 {
36 .fd = &fd,
37 .len = MAX_MSGSIZE,
38 .ret = 0,
39 .err = 0,
40 },
41 {
42 .fd = &fd,
43 .len = 1,
44 .prio = MQ_PRIO_MAX - 1,
45 .ret = 0,
46 .err = 0,
47 },
48 {
49 .fd = &fd,
50 .len = MAX_MSGSIZE + 1,
51 .ret = -1,
52 .err = EMSGSIZE,
53 },
54 {
55 .fd = &fd_invalid,
56 .len = 0,
57 .ret = -1,
58 .err = EBADF,
59 },
60 {
61 .fd = &fd_maxint,
62 .len = 0,
63 .ret = -1,
64 .err = EBADF,
65 },
66 {
67 .fd = &fd_root,
68 .len = 0,
69 .ret = -1,
70 .err = EBADF,
71 },
72 {
73 .fd = &fd_nonblock,
74 .len = 16,
75 .ret = -1,
76 .err = EAGAIN,
77 },
78 {
79 .fd = &fd,
80 .len = 1,
81 .prio = MQ_PRIO_MAX,
82 .ret = -1,
83 .err = EINVAL,
84 },
85 {
86 .fd = &fd,
87 .len = 16,
88 .tv_sec = -1,
89 .tv_nsec = 0,
90 .rq = &ts,
91 .send = 1,
92 .ret = -1,
93 .err = EINVAL,
94 },
95 {
96 .fd = &fd,
97 .len = 16,
98 .tv_sec = 0,
99 .tv_nsec = -1,
100 .rq = &ts,
101 .send = 1,
102 .ret = -1,
103 .err = EINVAL,
104 },
105 {
106 .fd = &fd,
107 .len = 16,
108 .tv_sec = 0,
109 .tv_nsec = 1000000000,
110 .rq = &ts,
111 .send = 1,
112 .ret = -1,
113 .err = EINVAL,
114 },
115 {
116 .fd = &fd,
117 .len = 16,
118 .rq = &ts,
119 .send = 1,
120 .timeout = 1,
121 .ret = -1,
122 .err = ETIMEDOUT,
123 },
124 {
125 .fd = &fd,
126 .len = 16,
127 .send = 1,
128 .signal = 1,
129 .rq = &ts,
130 .ret = -1,
131 .err = EINTR,
132 },
133 {
134 .fd = &fd,
135 .len = 16,
136 .bad_msg_addr = 1,
137 .ret = -1,
138 .err = EFAULT,
139 },
140 {
141 .fd = &fd,
142 .len = 16,
143 .bad_ts_addr = 1,
144 .ret = -1,
145 .err = EFAULT,
146 }
147 };
148
setup(void)149 static void setup(void)
150 {
151 struct time64_variants *tv = &variants[tst_variant];
152
153 tst_res(TINFO, "Testing variant: %s", tv->desc);
154 ts.type = tv->ts_type;
155
156 bad_addr = tst_get_bad_addr(cleanup_common);
157
158 setup_common();
159 }
160
do_test(unsigned int i)161 static void do_test(unsigned int i)
162 {
163 struct time64_variants *tv = &variants[tst_variant];
164 const struct test_case *tc = &tcase[i];
165 unsigned int j;
166 unsigned int prio;
167 size_t len = MAX_MSGSIZE;
168 char rmsg[len];
169 pid_t pid = -1;
170 void *msg_ptr, *abs_timeout;
171
172 tst_ts_set_sec(&ts, tc->tv_sec);
173 tst_ts_set_nsec(&ts, tc->tv_nsec);
174
175 if (tc->signal)
176 pid = set_sig(tc->rq, tv->clock_gettime);
177
178 if (tc->timeout)
179 set_timeout(tc->rq, tv->clock_gettime);
180
181 if (tc->send) {
182 for (j = 0; j < MSG_LENGTH; j++)
183 if (tv->mqt_send(*tc->fd, smsg, tc->len, tc->prio, NULL) < 0) {
184 tst_res(TFAIL | TTERRNO, "mq_timedsend() failed");
185 return;
186 }
187 }
188
189 if (tc->bad_msg_addr)
190 msg_ptr = bad_addr;
191 else
192 msg_ptr = smsg;
193
194 if (tc->bad_ts_addr)
195 abs_timeout = bad_addr;
196 else
197 abs_timeout = tst_ts_get(tc->rq);
198
199 TEST(tv->mqt_send(*tc->fd, msg_ptr, tc->len, tc->prio, abs_timeout));
200
201 if (pid > 0)
202 kill_pid(pid);
203
204 if (TST_RET < 0) {
205 if (tc->err != TST_ERR)
206 tst_res(TFAIL | TTERRNO,
207 "mq_timedsend() failed unexpectedly, expected %s",
208 tst_strerrno(tc->err));
209 else
210 tst_res(TPASS | TTERRNO, "mq_timedsend() failed expectedly");
211
212 if (*tc->fd == fd)
213 cleanup_queue(fd);
214
215 return;
216 }
217
218 TEST(tv->mqt_receive(*tc->fd, rmsg, len, &prio, tst_ts_get(tc->rq)));
219
220 if (*tc->fd == fd)
221 cleanup_queue(fd);
222
223 if (TST_RET < 0) {
224 if (tc->err != TST_ERR) {
225 tst_res(TFAIL | TTERRNO,
226 "mq_timedreceive() failed unexpectedly, expected %s",
227 tst_strerrno(tc->err));
228 return;
229 }
230
231 if (tc->ret >= 0) {
232 tst_res(TFAIL | TTERRNO, "mq_timedreceive() returned %ld, expected %d",
233 TST_RET, tc->ret);
234 return;
235 }
236 }
237
238 if (tc->len != TST_RET) {
239 tst_res(TFAIL, "mq_timedreceive() wrong length %ld, expected %u",
240 TST_RET, tc->len);
241 return;
242 }
243
244 if (tc->prio != prio) {
245 tst_res(TFAIL, "mq_timedreceive() wrong prio %d, expected %d",
246 prio, tc->prio);
247 return;
248 }
249
250 for (j = 0; j < tc->len; j++) {
251 if (rmsg[j] != smsg[j]) {
252 tst_res(TFAIL,
253 "mq_timedreceive() wrong data %d in %u, expected %d",
254 rmsg[j], i, smsg[j]);
255 return;
256 }
257 }
258
259 tst_res(TPASS, "mq_timedreceive() returned %ld, priority %u, length: %zu",
260 TST_RET, prio, len);
261 }
262
263 static struct tst_test test = {
264 .tcnt = ARRAY_SIZE(tcase),
265 .test = do_test,
266 .test_variants = ARRAY_SIZE(variants),
267 .setup = setup,
268 .cleanup = cleanup_common,
269 .forks_child = 1,
270 };
271