xref: /dpdk/app/test/test_alarm.c (revision a5d7a3f77ddc3c3ae18bce04d7555b458360cc65)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stdio.h>
35 #include <stdint.h>
36 
37 #include <rte_common.h>
38 #include <rte_cycles.h>
39 #include <rte_interrupts.h>
40 #include <rte_common.h>
41 #include <rte_atomic.h>
42 #include <rte_alarm.h>
43 
44 #include "test.h"
45 
46 #define US_PER_MS 1000
47 
48 #define RTE_TEST_ALARM_TIMEOUT 10 /* ms */
49 #define RTE_TEST_CHECK_PERIOD   3 /* ms */
50 
51 static volatile int flag;
52 
53 static void
54 test_alarm_callback(void *cb_arg)
55 {
56 	flag = 1;
57 	printf("Callback setting flag - OK. [cb_arg = %p]\n", cb_arg);
58 }
59 
60 static rte_atomic32_t cb_count;
61 
62 static void
63 test_multi_cb(void *arg)
64 {
65 	rte_atomic32_inc(&cb_count);
66 	printf("In %s - arg = %p\n", __func__, arg);
67 }
68 
69 static volatile int recursive_error = 0;
70 
71 static void
72 test_remove_in_callback(void *arg)
73 {
74 	printf("In %s - arg = %p\n", __func__, arg);
75 	if (rte_eal_alarm_cancel(test_remove_in_callback, arg) ||
76 			rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1)) {
77 		printf("Error - cancelling callback from within function succeeded!\n");
78 		recursive_error = 1;
79 	}
80 	flag = (int)((uintptr_t)arg);
81 }
82 
83 static volatile int flag_2;
84 
85 static void
86 test_remove_in_callback_2(void *arg)
87 {
88 	if (rte_eal_alarm_cancel(test_remove_in_callback_2, arg) || rte_eal_alarm_cancel(test_remove_in_callback_2, (void *)-1)) {
89 		printf("Error - cancelling callback of test_remove_in_callback_2\n");
90 		return;
91 	}
92 	flag_2 = 1;
93 }
94 
95 static int
96 test_multi_alarms(void)
97 {
98 	int rm_count = 0;
99 	cb_count.cnt = 0;
100 
101 	printf("Expect 6 callbacks in order...\n");
102 	/* add two alarms in order */
103 	rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)1);
104 	rte_eal_alarm_set(20 * US_PER_MS, test_multi_cb, (void *)2);
105 
106 	/* now add in reverse order */
107 	rte_eal_alarm_set(60 * US_PER_MS, test_multi_cb, (void *)6);
108 	rte_eal_alarm_set(50 * US_PER_MS, test_multi_cb, (void *)5);
109 	rte_eal_alarm_set(40 * US_PER_MS, test_multi_cb, (void *)4);
110 	rte_eal_alarm_set(30 * US_PER_MS, test_multi_cb, (void *)3);
111 
112 	/* wait for expiry */
113 	rte_delay_ms(65);
114 	if (cb_count.cnt != 6) {
115 		printf("Missing callbacks\n");
116 		/* remove any callbacks that might remain */
117 		rte_eal_alarm_cancel(test_multi_cb, (void *)-1);
118 		return -1;
119 	}
120 
121 	cb_count.cnt = 0;
122 	printf("Expect only callbacks with args 1 and 3...\n");
123 	/* Add 3 flags, then delete one */
124 	rte_eal_alarm_set(30 * US_PER_MS, test_multi_cb, (void *)3);
125 	rte_eal_alarm_set(20 * US_PER_MS, test_multi_cb, (void *)2);
126 	rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)1);
127 	rm_count = rte_eal_alarm_cancel(test_multi_cb, (void *)2);
128 
129 	rte_delay_ms(35);
130 	if (cb_count.cnt != 2 || rm_count != 1) {
131 		printf("Error: invalid flags count or alarm removal failure"
132 				" -  flags value = %d, expected = %d\n",
133 				(int)cb_count.cnt, 2);
134 		/* remove any callbacks that might remain */
135 		rte_eal_alarm_cancel(test_multi_cb, (void *)-1);
136 		return -1;
137 	}
138 
139 	printf("Testing adding and then removing multiple alarms\n");
140 	/* finally test that no callbacks are called if we delete them all*/
141 	rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)1);
142 	rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)2);
143 	rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)3);
144 	rm_count = rte_eal_alarm_cancel(test_alarm_callback, (void *)-1);
145 	if (rm_count != 0) {
146 		printf("Error removing non-existant alarm succeeded\n");
147 		rte_eal_alarm_cancel(test_multi_cb, (void *) -1);
148 		return -1;
149 	}
150 	rm_count = rte_eal_alarm_cancel(test_multi_cb, (void *) -1);
151 	if (rm_count != 3) {
152 		printf("Error removing all pending alarm callbacks\n");
153 		return -1;
154 	}
155 
156 	/* Test that we cannot cancel an alarm from within the callback itself
157 	 * Also test that we can cancel head-of-line callbacks ok.*/
158 	flag = 0;
159 	recursive_error = 0;
160 	rte_eal_alarm_set(10 * US_PER_MS, test_remove_in_callback, (void *)1);
161 	rte_eal_alarm_set(20 * US_PER_MS, test_remove_in_callback, (void *)2);
162 	rm_count = rte_eal_alarm_cancel(test_remove_in_callback, (void *)1);
163 	if (rm_count != 1) {
164 		printf("Error cancelling head-of-list callback\n");
165 		return -1;
166 	}
167 	rte_delay_ms(15);
168 	if (flag != 0) {
169 		printf("Error, cancelling head-of-list leads to premature callback\n");
170 		return -1;
171 	}
172 	rte_delay_ms(10);
173 	if (flag != 2) {
174 		printf("Error - expected callback not called\n");
175 		rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1);
176 		return -1;
177 	}
178 	if (recursive_error == 1)
179 		return -1;
180 
181 	/* Check if it can cancel all for the same callback */
182 	printf("Testing canceling all for the same callback\n");
183 	flag_2 = 0;
184 	rte_eal_alarm_set(10 * US_PER_MS, test_remove_in_callback, (void *)1);
185 	rte_eal_alarm_set(20 * US_PER_MS, test_remove_in_callback_2, (void *)2);
186 	rte_eal_alarm_set(30 * US_PER_MS, test_remove_in_callback_2, (void *)3);
187 	rte_eal_alarm_set(40 * US_PER_MS, test_remove_in_callback, (void *)4);
188 	rm_count = rte_eal_alarm_cancel(test_remove_in_callback_2, (void *)-1);
189 	if (rm_count != 2) {
190 		printf("Error, cannot cancel all for the same callback\n");
191 		return -1;
192 	}
193 	rm_count = rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1);
194 	if (rm_count != 2) {
195 		printf("Error, cannot cancel all for the same callback\n");
196 		return -1;
197 	}
198 
199 	return 0;
200 }
201 
202 static int
203 test_alarm(void)
204 {
205 	int count = 0;
206 
207 	/* check if the callback will be called */
208 	printf("check if the callback will be called\n");
209 	flag = 0;
210 	if (rte_eal_alarm_set(RTE_TEST_ALARM_TIMEOUT * US_PER_MS,
211 			test_alarm_callback, NULL) < 0) {
212 		printf("fail to set alarm callback\n");
213 		return -1;
214 	}
215 	while (flag == 0 && count ++ < 6)
216 		rte_delay_ms(RTE_TEST_CHECK_PERIOD);
217 
218 	if (flag == 0){
219 		printf("Callback not called\n");
220 		return -1;
221 	}
222 
223 	/* check if it will fail to set alarm with wrong us value */
224 	printf("check if it will fail to set alarm with wrong ms values\n");
225 	if (rte_eal_alarm_set(0, test_alarm_callback,
226 						NULL) >= 0) {
227 		printf("should not be successful with 0 us value\n");
228 		return -1;
229 	}
230 	if (rte_eal_alarm_set(UINT64_MAX - 1, test_alarm_callback,
231 						NULL) >= 0) {
232 		printf("should not be successful with (UINT64_MAX-1) us value\n");
233 		return -1;
234 	}
235 
236 	/* check if it will fail to set alarm with null callback parameter */
237 	printf("check if it will fail to set alarm with null callback parameter\n");
238 	if (rte_eal_alarm_set(RTE_TEST_ALARM_TIMEOUT, NULL, NULL) >= 0) {
239 		printf("should not be successful to set alarm with null callback parameter\n");
240 		return -1;
241 	}
242 
243 	/* check if it will fail to remove alarm with null callback parameter */
244 	printf("check if it will fail to remove alarm with null callback parameter\n");
245 	if (rte_eal_alarm_cancel(NULL, NULL) == 0) {
246 		printf("should not be successful to remove alarm with null callback parameter");
247 		return -1;
248 	}
249 
250 	if (test_multi_alarms() != 0)
251 		return -1;
252 
253 	return 0;
254 }
255 
256 REGISTER_TEST_COMMAND(alarm_autotest, test_alarm);
257