1 /*
2  * Copyright (c) 2014-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "ptunit.h"
30 
31 #include "pt_event_queue.h"
32 
33 
34 /* A test fixture providing an initialized event queue. */
35 struct evq_fixture {
36 	/* The event queue. */
37 	struct pt_event_queue evq;
38 
39 	/* The test fixture initialization and finalization functions. */
40 	struct ptunit_result (*init)(struct evq_fixture *);
41 	struct ptunit_result (*fini)(struct evq_fixture *);
42 };
43 
44 
45 static struct ptunit_result efix_init(struct evq_fixture *efix)
46 {
47 	pt_evq_init(&efix->evq);
48 
49 	return ptu_passed();
50 }
51 
52 static struct ptunit_result efix_init_pending(struct evq_fixture *efix)
53 {
54 	struct pt_event *ev;
55 	int evb;
56 
57 	pt_evq_init(&efix->evq);
58 
59 	for (evb = 0; evb < evb_max; ++evb) {
60 		ev = pt_evq_enqueue(&efix->evq, (enum pt_event_binding) evb);
61 		ptu_ptr(ev);
62 	}
63 
64 	return ptu_passed();
65 }
66 
67 static struct ptunit_result standalone_null(void)
68 {
69 	struct pt_event *ev;
70 
71 	ev = pt_evq_standalone(NULL);
72 	ptu_null(ev);
73 
74 	return ptu_passed();
75 }
76 
77 static struct ptunit_result standalone(struct evq_fixture *efix)
78 {
79 	struct pt_event *ev;
80 
81 	ev = pt_evq_standalone(&efix->evq);
82 	ptu_ptr(ev);
83 	ptu_uint_eq(ev->ip_suppressed, 0ul);
84 	ptu_uint_eq(ev->status_update, 0ul);
85 
86 	return ptu_passed();
87 }
88 
89 static struct ptunit_result enqueue_null(enum pt_event_binding evb)
90 {
91 	struct pt_event *ev;
92 
93 	ev = pt_evq_enqueue(NULL, evb);
94 	ptu_null(ev);
95 
96 	return ptu_passed();
97 }
98 
99 static struct ptunit_result dequeue_null(enum pt_event_binding evb)
100 {
101 	struct pt_event *ev;
102 
103 	ev = pt_evq_dequeue(NULL, evb);
104 	ptu_null(ev);
105 
106 	return ptu_passed();
107 }
108 
109 static struct ptunit_result dequeue_empty(struct evq_fixture *efix,
110 					  enum pt_event_binding evb)
111 {
112 	struct pt_event *ev;
113 
114 	ev = pt_evq_dequeue(&efix->evq, evb);
115 	ptu_null(ev);
116 
117 	return ptu_passed();
118 }
119 
120 static struct ptunit_result evq_empty(struct evq_fixture *efix,
121 				      enum pt_event_binding evb)
122 {
123 	int status;
124 
125 	status = pt_evq_empty(&efix->evq, evb);
126 	ptu_int_gt(status, 0);
127 
128 	status = pt_evq_pending(&efix->evq, evb);
129 	ptu_int_eq(status, 0);
130 
131 	return ptu_passed();
132 }
133 
134 static struct ptunit_result evq_pending(struct evq_fixture *efix,
135 					enum pt_event_binding evb)
136 {
137 	int status;
138 
139 	status = pt_evq_empty(&efix->evq, evb);
140 	ptu_int_eq(status, 0);
141 
142 	status = pt_evq_pending(&efix->evq, evb);
143 	ptu_int_gt(status, 0);
144 
145 	return ptu_passed();
146 }
147 
148 static struct ptunit_result evq_others_empty(struct evq_fixture *efix,
149 					     enum pt_event_binding evb)
150 {
151 	int other;
152 
153 	for (other = 0; other < evb_max; ++other) {
154 		enum pt_event_binding ob;
155 
156 		ob = (enum pt_event_binding) other;
157 		if (ob != evb)
158 			ptu_test(evq_empty, efix, ob);
159 	}
160 
161 	return ptu_passed();
162 }
163 
164 static struct ptunit_result enqueue_all_dequeue(struct evq_fixture *efix,
165 						enum pt_event_binding evb,
166 						size_t num)
167 {
168 	struct pt_event *in[evq_max], *out[evq_max];
169 	size_t idx;
170 
171 	ptu_uint_le(num, evq_max - 2);
172 
173 	for (idx = 0; idx < num; ++idx) {
174 		in[idx] = pt_evq_enqueue(&efix->evq, evb);
175 		ptu_ptr(in[idx]);
176 	}
177 
178 	ptu_test(evq_pending, efix, evb);
179 	ptu_test(evq_others_empty, efix, evb);
180 
181 	for (idx = 0; idx < num; ++idx) {
182 		out[idx] = pt_evq_dequeue(&efix->evq, evb);
183 		ptu_ptr_eq(out[idx], in[idx]);
184 	}
185 
186 	ptu_test(evq_empty, efix, evb);
187 
188 	return ptu_passed();
189 }
190 
191 static struct ptunit_result enqueue_one_dequeue(struct evq_fixture *efix,
192 						enum pt_event_binding evb,
193 						size_t num)
194 {
195 	size_t idx;
196 
197 	for (idx = 0; idx < num; ++idx) {
198 		struct pt_event *in, *out;
199 
200 		in = pt_evq_enqueue(&efix->evq, evb);
201 		ptu_ptr(in);
202 
203 		out = pt_evq_dequeue(&efix->evq, evb);
204 		ptu_ptr_eq(out, in);
205 	}
206 
207 	return ptu_passed();
208 }
209 
210 static struct ptunit_result overflow(struct evq_fixture *efix,
211 				     enum pt_event_binding evb,
212 				     size_t num)
213 {
214 	struct pt_event *in[evq_max], *out[evq_max], *ev;
215 	size_t idx;
216 
217 	ptu_uint_le(num, evq_max - 2);
218 
219 	for (idx = 0; idx < (evq_max - 2); ++idx) {
220 		in[idx] = pt_evq_enqueue(&efix->evq, evb);
221 		ptu_ptr(in[idx]);
222 	}
223 
224 	for (idx = 0; idx < num; ++idx) {
225 		ev = pt_evq_enqueue(&efix->evq, evb);
226 		ptu_null(ev);
227 	}
228 
229 	for (idx = 0; idx < num; ++idx) {
230 		out[idx] = pt_evq_dequeue(&efix->evq, evb);
231 		ptu_ptr_eq(out[idx], in[idx]);
232 	}
233 
234 	return ptu_passed();
235 }
236 
237 static struct ptunit_result clear_null(enum pt_event_binding evb)
238 {
239 	int errcode;
240 
241 	errcode = pt_evq_clear(NULL, evb);
242 	ptu_int_eq(errcode, -pte_internal);
243 
244 	return ptu_passed();
245 }
246 
247 static struct ptunit_result clear(struct evq_fixture *efix,
248 				  enum pt_event_binding evb)
249 {
250 	int errcode;
251 
252 	errcode = pt_evq_clear(&efix->evq, evb);
253 	ptu_int_eq(errcode, 0);
254 
255 	ptu_test(evq_empty, efix, evb);
256 
257 	return ptu_passed();
258 }
259 
260 static struct ptunit_result empty_null(enum pt_event_binding evb)
261 {
262 	int errcode;
263 
264 	errcode = pt_evq_empty(NULL, evb);
265 	ptu_int_eq(errcode, -pte_internal);
266 
267 	return ptu_passed();
268 }
269 
270 static struct ptunit_result pending_null(enum pt_event_binding evb)
271 {
272 	int errcode;
273 
274 	errcode = pt_evq_pending(NULL, evb);
275 	ptu_int_eq(errcode, -pte_internal);
276 
277 	return ptu_passed();
278 }
279 
280 static struct ptunit_result find_null(enum pt_event_binding evb,
281 				      enum pt_event_type evt)
282 {
283 	struct pt_event *ev;
284 
285 	ev = pt_evq_find(NULL, evb, evt);
286 	ptu_null(ev);
287 
288 	return ptu_passed();
289 }
290 
291 static struct ptunit_result find_empty(struct evq_fixture *efix,
292 				       enum pt_event_binding evb,
293 				       enum pt_event_type evt)
294 {
295 	struct pt_event *ev;
296 
297 	ev = pt_evq_find(&efix->evq, evb, evt);
298 	ptu_null(ev);
299 
300 	return ptu_passed();
301 }
302 
303 static struct ptunit_result find_none_evb(struct evq_fixture *efix,
304 					  enum pt_event_binding evb,
305 					  enum pt_event_type evt)
306 {
307 	struct pt_event *ev;
308 	size_t other;
309 
310 	for (other = 0; other < evb_max; ++other) {
311 		enum pt_event_binding ob;
312 
313 		ob = (enum pt_event_binding) other;
314 		if (ob != evb) {
315 			ev = pt_evq_enqueue(&efix->evq, ob);
316 			ptu_ptr(ev);
317 
318 			ev->type = evt;
319 		}
320 	}
321 
322 	ev = pt_evq_find(&efix->evq, evb, evt);
323 	ptu_null(ev);
324 
325 	return ptu_passed();
326 }
327 
328 static struct ptunit_result evq_enqueue_other(struct evq_fixture *efix,
329 					      enum pt_event_binding evb,
330 					      enum pt_event_type evt,
331 					      size_t num)
332 {
333 	enum pt_event_type ot;
334 	struct pt_event *ev;
335 	size_t other;
336 
337 	for (other = 0; other < num; ++other) {
338 		ot = (enum pt_event_type) other;
339 		if (ot != evt) {
340 			ev = pt_evq_enqueue(&efix->evq, evb);
341 			ptu_ptr(ev);
342 
343 			ev->type = ot;
344 		}
345 	}
346 
347 	return ptu_passed();
348 }
349 
350 static struct ptunit_result find_none_evt(struct evq_fixture *efix,
351 					  enum pt_event_binding evb,
352 					  enum pt_event_type evt,
353 					  size_t num)
354 {
355 	struct pt_event *ev;
356 
357 	ptu_test(evq_enqueue_other, efix, evb, evt, num);
358 
359 	ev = pt_evq_find(&efix->evq, evb, evt);
360 	ptu_null(ev);
361 
362 	return ptu_passed();
363 }
364 
365 static struct ptunit_result find(struct evq_fixture *efix,
366 				 enum pt_event_binding evb,
367 				 enum pt_event_type evt,
368 				 size_t before, size_t after)
369 {
370 	struct pt_event *in, *out;
371 
372 	ptu_test(evq_enqueue_other, efix, evb, evt, before);
373 
374 	in = pt_evq_enqueue(&efix->evq, evb);
375 	ptu_ptr(in);
376 
377 	in->type = evt;
378 
379 	ptu_test(evq_enqueue_other, efix, evb, evt, after);
380 
381 	out = pt_evq_find(&efix->evq, evb, evt);
382 	ptu_ptr_eq(out, in);
383 
384 	return ptu_passed();
385 }
386 
387 int main(int argc, char **argv)
388 {
389 	struct evq_fixture efix, pfix;
390 	struct ptunit_suite suite;
391 
392 	efix.init = efix_init;
393 	efix.fini = NULL;
394 
395 	pfix.init = efix_init_pending;
396 	pfix.fini = NULL;
397 
398 	suite = ptunit_mk_suite(argc, argv);
399 
400 	ptu_run(suite, standalone_null);
401 	ptu_run_f(suite, standalone, efix);
402 
403 	ptu_run_p(suite, enqueue_null, evb_psbend);
404 	ptu_run_p(suite, enqueue_null, evb_tip);
405 	ptu_run_p(suite, enqueue_null, evb_fup);
406 
407 	ptu_run_p(suite, dequeue_null, evb_psbend);
408 	ptu_run_p(suite, dequeue_null, evb_tip);
409 	ptu_run_p(suite, dequeue_null, evb_fup);
410 
411 	ptu_run_fp(suite, dequeue_empty, efix, evb_psbend);
412 	ptu_run_fp(suite, dequeue_empty, efix, evb_tip);
413 	ptu_run_fp(suite, dequeue_empty, efix, evb_fup);
414 
415 	ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_psbend, 1);
416 	ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_psbend, 2);
417 	ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_tip, 1);
418 	ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_tip, 3);
419 	ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_fup, 1);
420 	ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_fup, 4);
421 
422 	ptu_run_fp(suite, enqueue_one_dequeue, efix, evb_psbend, evb_max * 2);
423 	ptu_run_fp(suite, enqueue_one_dequeue, efix, evb_tip, evb_max * 2);
424 	ptu_run_fp(suite, enqueue_one_dequeue, efix, evb_fup, evb_max * 2);
425 
426 	ptu_run_fp(suite, overflow, efix, evb_psbend, 1);
427 	ptu_run_fp(suite, overflow, efix, evb_tip, 2);
428 	ptu_run_fp(suite, overflow, efix, evb_fup, 3);
429 
430 	ptu_run_p(suite, clear_null, evb_psbend);
431 	ptu_run_p(suite, clear_null, evb_tip);
432 	ptu_run_p(suite, clear_null, evb_fup);
433 
434 	ptu_run_fp(suite, clear, efix, evb_psbend);
435 	ptu_run_fp(suite, clear, pfix, evb_psbend);
436 	ptu_run_fp(suite, clear, efix, evb_tip);
437 	ptu_run_fp(suite, clear, pfix, evb_tip);
438 	ptu_run_fp(suite, clear, efix, evb_fup);
439 	ptu_run_fp(suite, clear, pfix, evb_fup);
440 
441 	ptu_run_p(suite, empty_null, evb_psbend);
442 	ptu_run_p(suite, empty_null, evb_tip);
443 	ptu_run_p(suite, empty_null, evb_fup);
444 
445 	ptu_run_p(suite, pending_null, evb_psbend);
446 	ptu_run_p(suite, pending_null, evb_tip);
447 	ptu_run_p(suite, pending_null, evb_fup);
448 
449 	ptu_run_p(suite, find_null, evb_psbend, ptev_enabled);
450 	ptu_run_p(suite, find_null, evb_tip, ptev_disabled);
451 	ptu_run_p(suite, find_null, evb_fup, ptev_paging);
452 
453 	ptu_run_fp(suite, find_empty, efix, evb_psbend, ptev_enabled);
454 	ptu_run_fp(suite, find_empty, efix, evb_tip, ptev_disabled);
455 	ptu_run_fp(suite, find_empty, efix, evb_fup, ptev_paging);
456 
457 	ptu_run_fp(suite, find_none_evb, efix, evb_psbend, ptev_enabled);
458 	ptu_run_fp(suite, find_none_evb, efix, evb_tip, ptev_disabled);
459 	ptu_run_fp(suite, find_none_evb, efix, evb_fup, ptev_paging);
460 
461 	ptu_run_fp(suite, find_none_evt, efix, evb_psbend, ptev_enabled, 3);
462 	ptu_run_fp(suite, find_none_evt, efix, evb_tip, ptev_disabled, 4);
463 	ptu_run_fp(suite, find_none_evt, efix, evb_fup, ptev_paging, 2);
464 
465 	ptu_run_fp(suite, find, efix, evb_psbend, ptev_enabled, 0, 3);
466 	ptu_run_fp(suite, find, efix, evb_tip, ptev_disabled, 2, 0);
467 	ptu_run_fp(suite, find, efix, evb_fup, ptev_paging, 1, 4);
468 
469 	return ptunit_report(&suite);
470 }
471