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. */
35struct 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
45static struct ptunit_result efix_init(struct evq_fixture *efix)
46{
47	pt_evq_init(&efix->evq);
48
49	return ptu_passed();
50}
51
52static 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
67static 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
77static 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
89static 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
99static 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
109static 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
120static 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
134static 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
148static 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
164static 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
191static 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
210static 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
237static 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
247static 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
260static 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
270static 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
280static 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
291static 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
303static 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
328static 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
350static 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
365static 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
387int 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