1 /*
2  * Copyright (c) 2013-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 "pt_event_queue.h"
30 
31 #include <string.h>
32 
33 
pt_evq_inc(uint8_t idx)34 static inline uint8_t pt_evq_inc(uint8_t idx)
35 {
36 	idx += 1;
37 	idx %= evq_max;
38 
39 	return idx;
40 }
41 
pt_event_init(struct pt_event * event)42 static struct pt_event *pt_event_init(struct pt_event *event)
43 {
44 	if (event)
45 		memset(event, 0, sizeof(*event));
46 
47 	return event;
48 }
49 
pt_evq_init(struct pt_event_queue * evq)50 void pt_evq_init(struct pt_event_queue *evq)
51 {
52 	if (!evq)
53 		return;
54 
55 	memset(evq, 0, sizeof(*evq));
56 }
57 
pt_evq_standalone(struct pt_event_queue * evq)58 struct pt_event *pt_evq_standalone(struct pt_event_queue *evq)
59 {
60 	if (!evq)
61 		return NULL;
62 
63 	return pt_event_init(&evq->standalone);
64 }
65 
pt_evq_enqueue(struct pt_event_queue * evq,enum pt_event_binding evb)66 struct pt_event *pt_evq_enqueue(struct pt_event_queue *evq,
67 				enum pt_event_binding evb)
68 {
69 	uint8_t begin, end, gap, idx;
70 
71 	if (!evq)
72 		return NULL;
73 
74 	if (evb_max <= evb)
75 		return NULL;
76 
77 	begin = evq->begin[evb];
78 	idx = evq->end[evb];
79 
80 	if (evq_max <= begin)
81 		return NULL;
82 
83 	if (evq_max <= idx)
84 		return NULL;
85 
86 	end = pt_evq_inc(idx);
87 	gap = pt_evq_inc(end);
88 
89 	/* Leave a gap so we don't overwrite the last dequeued event. */
90 	if (begin == gap)
91 		return NULL;
92 
93 	evq->end[evb] = end;
94 
95 	return pt_event_init(&evq->queue[evb][idx]);
96 }
97 
pt_evq_dequeue(struct pt_event_queue * evq,enum pt_event_binding evb)98 struct pt_event *pt_evq_dequeue(struct pt_event_queue *evq,
99 				enum pt_event_binding evb)
100 {
101 	uint8_t begin, end;
102 
103 	if (!evq)
104 		return NULL;
105 
106 	if (evb_max <= evb)
107 		return NULL;
108 
109 	begin = evq->begin[evb];
110 	end = evq->end[evb];
111 
112 	if (evq_max <= begin)
113 		return NULL;
114 
115 	if (evq_max <= end)
116 		return NULL;
117 
118 	if (begin == end)
119 		return NULL;
120 
121 	evq->begin[evb] = pt_evq_inc(begin);
122 
123 	return &evq->queue[evb][begin];
124 }
125 
pt_evq_clear(struct pt_event_queue * evq,enum pt_event_binding evb)126 int pt_evq_clear(struct pt_event_queue *evq, enum pt_event_binding evb)
127 {
128 	if (!evq)
129 		return -pte_internal;
130 
131 	if (evb_max <= evb)
132 		return -pte_internal;
133 
134 	evq->begin[evb] = 0;
135 	evq->end[evb] = 0;
136 
137 	return 0;
138 }
139 
pt_evq_empty(const struct pt_event_queue * evq,enum pt_event_binding evb)140 int pt_evq_empty(const struct pt_event_queue *evq, enum pt_event_binding evb)
141 {
142 	uint8_t begin, end;
143 
144 	if (!evq)
145 		return -pte_internal;
146 
147 	if (evb_max <= evb)
148 		return -pte_internal;
149 
150 	begin = evq->begin[evb];
151 	end = evq->end[evb];
152 
153 	if (evq_max <= begin)
154 		return -pte_internal;
155 
156 	if (evq_max <= end)
157 		return -pte_internal;
158 
159 	return begin == end;
160 }
161 
pt_evq_pending(const struct pt_event_queue * evq,enum pt_event_binding evb)162 int pt_evq_pending(const struct pt_event_queue *evq, enum pt_event_binding evb)
163 {
164 	int errcode;
165 
166 	errcode = pt_evq_empty(evq, evb);
167 	if (errcode < 0)
168 		return errcode;
169 
170 	return !errcode;
171 }
172 
pt_evq_find(struct pt_event_queue * evq,enum pt_event_binding evb,enum pt_event_type evt)173 struct pt_event *pt_evq_find(struct pt_event_queue *evq,
174 			     enum pt_event_binding evb,
175 			     enum pt_event_type evt)
176 {
177 	uint8_t begin, end;
178 
179 	if (!evq)
180 		return NULL;
181 
182 	if (evb_max <= evb)
183 		return NULL;
184 
185 	begin = evq->begin[evb];
186 	end = evq->end[evb];
187 
188 	if (evq_max <= begin)
189 		return NULL;
190 
191 	if (evq_max <= end)
192 		return NULL;
193 
194 	for (; begin != end; begin = pt_evq_inc(begin)) {
195 		struct pt_event *ev;
196 
197 		ev = &evq->queue[evb][begin];
198 		if (ev->type == evt)
199 			return ev;
200 	}
201 
202 	return NULL;
203 }
204