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 .send = 1,
27 .ret = 0,
28 .err = 0,
29 },
30 {
31 .fd = &fd,
32 .len = 1,
33 .send = 1,
34 .ret = 0,
35 .err = 0,
36 },
37 {
38 .fd = &fd,
39 .len = MAX_MSGSIZE,
40 .send = 1,
41 .ret = 0,
42 .err = 0,
43 },
44 {
45 .fd = &fd,
46 .len = 1,
47 .send = 1,
48 .prio = MQ_PRIO_MAX - 1,
49 .ret = 0,
50 .err = 0,
51 },
52 {
53 .fd = &fd,
54 .invalid_msg = 1,
55 .len = 0,
56 .send = 1,
57 .ret = -1,
58 .err = EMSGSIZE,
59 },
60 {
61 .fd = &fd_invalid,
62 .len = 0,
63 .ret = -1,
64 .err = EBADF,
65 },
66 {
67 .fd = &fd_maxint,
68 .len = 0,
69 .ret = -1,
70 .err = EBADF,
71 },
72 {
73 .fd = &fd_root,
74 .len = 0,
75 .ret = -1,
76 .err = EBADF,
77 },
78 {
79 .fd = &fd_nonblock,
80 .len = 16,
81 .ret = -1,
82 .err = EAGAIN,
83 },
84 {
85 .fd = &fd,
86 .len = 16,
87 .tv_sec = -1,
88 .tv_nsec = 0,
89 .rq = &ts,
90 .ret = -1,
91 .err = EINVAL,
92 },
93 {
94 .fd = &fd,
95 .len = 16,
96 .tv_sec = 0,
97 .tv_nsec = -1,
98 .rq = &ts,
99 .ret = -1,
100 .err = EINVAL,
101 },
102 {
103 .fd = &fd,
104 .len = 16,
105 .tv_sec = 0,
106 .tv_nsec = 1000000000,
107 .rq = &ts,
108 .ret = -1,
109 .err = EINVAL,
110 },
111 {
112 .fd = &fd,
113 .len = 16,
114 .timeout = 1,
115 .ret = -1,
116 .rq = &ts,
117 .err = ETIMEDOUT,
118 },
119 {
120 .fd = &fd,
121 .len = 16,
122 .signal = 1,
123 .rq = &ts,
124 .ret = -1,
125 .err = EINTR,
126 },
127 {
128 .fd = &fd,
129 .len = 16,
130 .bad_ts_addr = 1,
131 .ret = -1,
132 .err = EFAULT,
133 }
134 };
135
setup(void)136 static void setup(void)
137 {
138 struct time64_variants *tv = &variants[tst_variant];
139
140 tst_res(TINFO, "Testing variant: %s", tv->desc);
141 ts.type = tv->ts_type;
142
143 bad_addr = tst_get_bad_addr(NULL);
144
145 setup_common();
146 }
147
do_test(unsigned int i)148 static void do_test(unsigned int i)
149 {
150 struct time64_variants *tv = &variants[tst_variant];
151 const struct test_case *tc = &tcase[i];
152 unsigned int j;
153 unsigned int prio;
154 size_t len = MAX_MSGSIZE;
155 char rmsg[len];
156 pid_t pid = -1;
157 void *abs_timeout;
158
159 tst_ts_set_sec(&ts, tc->tv_sec);
160 tst_ts_set_nsec(&ts, tc->tv_nsec);
161
162 if (tc->signal)
163 pid = set_sig(tc->rq, tv->clock_gettime);
164
165 if (tc->timeout)
166 set_timeout(tc->rq, tv->clock_gettime);
167
168 if (tc->send) {
169 if (tv->mqt_send(*tc->fd, smsg, tc->len, tc->prio, NULL) < 0) {
170 tst_res(TFAIL | TTERRNO, "mq_timedsend() failed");
171 return;
172 }
173 }
174
175 if (tc->invalid_msg)
176 len -= 1;
177
178 if (tc->bad_ts_addr)
179 abs_timeout = bad_addr;
180 else
181 abs_timeout = tst_ts_get(tc->rq);
182
183 TEST(tv->mqt_receive(*tc->fd, rmsg, len, &prio, abs_timeout));
184
185 if (pid > 0)
186 kill_pid(pid);
187
188 if (*tc->fd == fd)
189 cleanup_queue(fd);
190
191 if (TST_RET < 0) {
192 if (tc->err != TST_ERR)
193 tst_res(TFAIL | TTERRNO,
194 "mq_timedreceive() failed unexpectedly, expected %s",
195 tst_strerrno(tc->err));
196 else
197 tst_res(TPASS | TTERRNO, "mq_timedreceive() failed expectedly");
198
199 return;
200 }
201
202 if (tc->len != TST_RET) {
203 tst_res(TFAIL, "mq_timedreceive() wrong length %ld, expected %u",
204 TST_RET, tc->len);
205 return;
206 }
207
208 if (tc->prio != prio) {
209 tst_res(TFAIL, "mq_timedreceive() wrong prio %d, expected %d",
210 prio, tc->prio);
211 return;
212 }
213
214 for (j = 0; j < tc->len; j++) {
215 if (rmsg[j] != smsg[j]) {
216 tst_res(TFAIL,
217 "mq_timedreceive() wrong data %d in %u, expected %d",
218 rmsg[j], i, smsg[j]);
219 return;
220 }
221 }
222
223 tst_res(TPASS, "mq_timedreceive() returned %ld, priority %u, length: %zu",
224 TST_RET, prio, len);
225 }
226
227 static struct tst_test test = {
228 .tcnt = ARRAY_SIZE(tcase),
229 .test = do_test,
230 .test_variants = ARRAY_SIZE(variants),
231 .setup = setup,
232 .cleanup = cleanup_common,
233 .forks_child = 1,
234 };
235