1 /*
2  * Copyright (c) 2019 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/tc_util.h>
9 #include <zephyr/ztest.h>
10 
11 #include <zephyr/sys/printk.h>
12 
13 #define STAMP_INTERVAL_s 60
14 #define TIMER_DELAY_ms 500
15 #define BUSY_WAIT_ms 100
16 
17 static volatile uint32_t na;
18 
handler(struct k_timer * timer)19 static void handler(struct k_timer *timer)
20 {
21 	++na;
22 }
23 
24 static uint32_t iters;
25 static uint32_t now;
26 
tag(void)27 static const char *tag(void)
28 {
29 	static char buf[32];
30 
31 	snprintf(buf, sizeof(buf), "[%6u.%03u] %u: ",
32 		 now / MSEC_PER_SEC, now % MSEC_PER_SEC, iters);
33 	return buf;
34 }
35 
ZTEST(starve_fn,test_starve)36 ZTEST(starve_fn, test_starve)
37 {
38 	static struct k_timer tmr;
39 	static struct k_spinlock lock;
40 	uint32_t stamp = 0;
41 	uint32_t last_now = 0;
42 	uint64_t last_ticks = 0;
43 	k_spinlock_key_t key;
44 
45 	TC_PRINT("Cycle clock runs at %u Hz\n",
46 		 k_ms_to_cyc_ceil32(MSEC_PER_SEC));
47 	TC_PRINT("There are %u cycles per tick (%u Hz ticks)\n",
48 		 k_ticks_to_cyc_ceil32(1U),
49 		 k_ms_to_ticks_ceil32(MSEC_PER_SEC));
50 
51 	k_timer_init(&tmr, handler, NULL);
52 	while (true) {
53 		now = k_uptime_get_32();
54 		if ((now / MSEC_PER_SEC) > CONFIG_APP_STOP_S) {
55 			break;
56 		}
57 
58 		++iters;
59 
60 		if (now > stamp) {
61 			TC_PRINT("%sstill running, would pass at %u s\n",
62 				 tag(), CONFIG_APP_STOP_S);
63 			stamp += STAMP_INTERVAL_s * MSEC_PER_SEC;
64 		}
65 
66 		int32_t now_diff = now - last_now;
67 
68 		zassert_true(now_diff > 0,
69 			     "%sTime went backwards by %d: was %u.%03u\n",
70 			     tag(), -now_diff, last_now / MSEC_PER_SEC,
71 			     last_now % MSEC_PER_SEC);
72 		last_now = now;
73 
74 		/* Assume tick delta fits in printable 32 bits */
75 		uint64_t ticks = sys_clock_tick_get();
76 		int64_t ticks_diff = ticks - last_ticks;
77 
78 		zassert_true(ticks_diff > 0,
79 			     "%sTicks went backwards by %d\n",
80 			     tag(), -(int32_t)ticks_diff);
81 		last_ticks = ticks;
82 
83 		uint32_t na_capture = na;
84 
85 		zassert_equal(na_capture, 0,
86 			      "%sTimer alarm fired: %u\n",
87 			      na_capture);
88 
89 		k_timer_start(&tmr, K_MSEC(TIMER_DELAY_ms), K_NO_WAIT);
90 
91 		/* Wait with interrupts disabled to increase chance
92 		 * that overflow is detected.
93 		 */
94 		key = k_spin_lock(&lock);
95 		k_busy_wait(BUSY_WAIT_ms * USEC_PER_MSEC);
96 		k_spin_unlock(&lock, key);
97 	}
98 	TC_PRINT("%sCompleted %u iters without failure\n",
99 		 tag(), iters);
100 }
101 
102 ZTEST_SUITE(starve_fn, NULL, NULL, NULL, NULL, NULL);
103