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 <cmdline_parse.h> 38 39 #include <rte_common.h> 40 #include <rte_cycles.h> 41 #include <rte_interrupts.h> 42 #include <rte_common.h> 43 #include <rte_atomic.h> 44 #include <rte_alarm.h> 45 46 #include "test.h" 47 48 #define US_PER_MS 1000 49 50 #define RTE_TEST_ALARM_TIMEOUT 3000 /* ms */ 51 #define RTE_TEST_CHECK_PERIOD 1000 /* ms */ 52 53 static volatile int flag; 54 55 static void 56 test_alarm_callback(void *cb_arg) 57 { 58 flag = 1; 59 printf("Callback setting flag - OK. [cb_arg = %p]\n", cb_arg); 60 } 61 62 static rte_atomic32_t cb_count; 63 64 static void 65 test_multi_cb(void *arg) 66 { 67 rte_atomic32_inc(&cb_count); 68 printf("In %s - arg = %p\n", __func__, arg); 69 } 70 71 static volatile int recursive_error = 0; 72 73 static void 74 test_remove_in_callback(void *arg) 75 { 76 printf("In %s - arg = %p\n", __func__, arg); 77 if (rte_eal_alarm_cancel(test_remove_in_callback, arg) || 78 rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1)) { 79 printf("Error - cancelling callback from within function succeeded!\n"); 80 recursive_error = 1; 81 } 82 flag = (int)((uintptr_t)arg); 83 } 84 85 static volatile int flag_2; 86 87 static void 88 test_remove_in_callback_2(void *arg) 89 { 90 if (rte_eal_alarm_cancel(test_remove_in_callback_2, arg) || rte_eal_alarm_cancel(test_remove_in_callback_2, (void *)-1)) { 91 printf("Error - cancelling callback of test_remove_in_callback_2\n"); 92 return; 93 } 94 flag_2 = 1; 95 } 96 97 static int 98 test_multi_alarms(void) 99 { 100 int rm_count = 0; 101 cb_count.cnt = 0; 102 103 printf("Expect 6 callbacks in order...\n"); 104 /* add two alarms in order */ 105 rte_eal_alarm_set(1000 * US_PER_MS, test_multi_cb, (void *)1); 106 rte_eal_alarm_set(2000 * US_PER_MS, test_multi_cb, (void *)2); 107 108 /* now add in reverse order */ 109 rte_eal_alarm_set(6000 * US_PER_MS, test_multi_cb, (void *)6); 110 rte_eal_alarm_set(5000 * US_PER_MS, test_multi_cb, (void *)5); 111 rte_eal_alarm_set(4000 * US_PER_MS, test_multi_cb, (void *)4); 112 rte_eal_alarm_set(3000 * US_PER_MS, test_multi_cb, (void *)3); 113 114 /* wait for expiry */ 115 rte_delay_ms(6500); 116 if (cb_count.cnt != 6) { 117 printf("Missing callbacks\n"); 118 /* remove any callbacks that might remain */ 119 rte_eal_alarm_cancel(test_multi_cb, (void *)-1); 120 return -1; 121 } 122 123 cb_count.cnt = 0; 124 printf("Expect only callbacks with args 1 and 3...\n"); 125 /* Add 3 flags, then delete one */ 126 rte_eal_alarm_set(3000 * US_PER_MS, test_multi_cb, (void *)3); 127 rte_eal_alarm_set(2000 * US_PER_MS, test_multi_cb, (void *)2); 128 rte_eal_alarm_set(1000 * US_PER_MS, test_multi_cb, (void *)1); 129 rm_count = rte_eal_alarm_cancel(test_multi_cb, (void *)2); 130 131 rte_delay_ms(3500); 132 if (cb_count.cnt != 2 || rm_count != 1) { 133 printf("Error: invalid flags count or alarm removal failure" 134 " - flags value = %d, expected = %d\n", 135 (int)cb_count.cnt, 2); 136 /* remove any callbacks that might remain */ 137 rte_eal_alarm_cancel(test_multi_cb, (void *)-1); 138 return -1; 139 } 140 141 printf("Testing adding and then removing multiple alarms\n"); 142 /* finally test that no callbacks are called if we delete them all*/ 143 rte_eal_alarm_set(1000 * US_PER_MS, test_multi_cb, (void *)1); 144 rte_eal_alarm_set(1000 * US_PER_MS, test_multi_cb, (void *)2); 145 rte_eal_alarm_set(1000 * US_PER_MS, test_multi_cb, (void *)3); 146 rm_count = rte_eal_alarm_cancel(test_alarm_callback, (void *)-1); 147 if (rm_count != 0) { 148 printf("Error removing non-existant alarm succeeded\n"); 149 rte_eal_alarm_cancel(test_multi_cb, (void *) -1); 150 return -1; 151 } 152 rm_count = rte_eal_alarm_cancel(test_multi_cb, (void *) -1); 153 if (rm_count != 3) { 154 printf("Error removing all pending alarm callbacks\n"); 155 return -1; 156 } 157 158 /* Test that we cannot cancel an alarm from within the callback itself 159 * Also test that we can cancel head-of-line callbacks ok.*/ 160 flag = 0; 161 recursive_error = 0; 162 rte_eal_alarm_set(1000 * US_PER_MS, test_remove_in_callback, (void *)1); 163 rte_eal_alarm_set(2000 * US_PER_MS, test_remove_in_callback, (void *)2); 164 rm_count = rte_eal_alarm_cancel(test_remove_in_callback, (void *)1); 165 if (rm_count != 1) { 166 printf("Error cancelling head-of-list callback\n"); 167 return -1; 168 } 169 rte_delay_ms(1500); 170 if (flag != 0) { 171 printf("Error, cancelling head-of-list leads to premature callback\n"); 172 return -1; 173 } 174 rte_delay_ms(1000); 175 if (flag != 2) { 176 printf("Error - expected callback not called\n"); 177 rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1); 178 return -1; 179 } 180 if (recursive_error == 1) 181 return -1; 182 183 /* Check if it can cancel all for the same callback */ 184 printf("Testing canceling all for the same callback\n"); 185 flag_2 = 0; 186 rte_eal_alarm_set(1000 * US_PER_MS, test_remove_in_callback, (void *)1); 187 rte_eal_alarm_set(2000 * US_PER_MS, test_remove_in_callback_2, (void *)2); 188 rte_eal_alarm_set(3000 * US_PER_MS, test_remove_in_callback_2, (void *)3); 189 rte_eal_alarm_set(4000 * US_PER_MS, test_remove_in_callback, (void *)4); 190 rm_count = rte_eal_alarm_cancel(test_remove_in_callback_2, (void *)-1); 191 if (rm_count != 2) { 192 printf("Error, cannot cancel all for the same callback\n"); 193 return -1; 194 } 195 rm_count = rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1); 196 if (rm_count != 2) { 197 printf("Error, cannot cancel all for the same callback\n"); 198 return -1; 199 } 200 201 return 0; 202 } 203 204 int 205 test_alarm(void) 206 { 207 int count = 0; 208 209 /* check if the callback will be called */ 210 printf("check if the callback will be called\n"); 211 flag = 0; 212 if (rte_eal_alarm_set(RTE_TEST_ALARM_TIMEOUT * US_PER_MS, 213 test_alarm_callback, NULL) < 0) { 214 printf("fail to set alarm callback\n"); 215 return -1; 216 } 217 while (flag == 0 && count ++ < 6) 218 rte_delay_ms(RTE_TEST_CHECK_PERIOD); 219 220 if (flag == 0){ 221 printf("Callback not called\n"); 222 return -1; 223 } 224 225 /* check if it will fail to set alarm with wrong us value */ 226 printf("check if it will fail to set alarm with wrong ms values\n"); 227 if (rte_eal_alarm_set(0, test_alarm_callback, 228 NULL) >= 0) { 229 printf("should not be successful with 0 us value\n"); 230 return -1; 231 } 232 if (rte_eal_alarm_set(UINT64_MAX - 1, test_alarm_callback, 233 NULL) >= 0) { 234 printf("should not be successful with (UINT64_MAX-1) us value\n"); 235 return -1; 236 } 237 238 /* check if it will fail to set alarm with null callback parameter */ 239 printf("check if it will fail to set alarm with null callback parameter\n"); 240 if (rte_eal_alarm_set(RTE_TEST_ALARM_TIMEOUT, NULL, NULL) >= 0) { 241 printf("should not be successful to set alarm with null callback parameter\n"); 242 return -1; 243 } 244 245 /* check if it will fail to remove alarm with null callback parameter */ 246 printf("check if it will fail to remove alarm with null callback parameter\n"); 247 if (rte_eal_alarm_cancel(NULL, NULL) == 0) { 248 printf("should not be successful to remove alarm with null callback parameter"); 249 return -1; 250 } 251 252 if (test_multi_alarms() != 0) 253 return -1; 254 255 return 0; 256 } 257 258