1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <time.h>
8 #include <unistd.h>
9
10 #include <zephyr/ztest.h>
11 #include <zephyr/logging/log.h>
12
13 #define SECS_TO_SLEEP 2
14 #define DURATION_SECS 1
15 #define DURATION_NSECS 0
16 #define PERIOD_SECS 0
17 #define PERIOD_NSECS 100000000
18
19 #define TEST_SIGNAL_VAL SIGTSTP
20
21 LOG_MODULE_REGISTER(timer_test);
22
23 static int exp_count;
24 static timer_t timerid = -1;
25
handler(union sigval val)26 void handler(union sigval val)
27 {
28 ++exp_count;
29 LOG_DBG("Handler Signal value %d for %d times", val.sival_int, exp_count);
30 zassert_equal(val.sival_int, TEST_SIGNAL_VAL);
31 }
32
test_timer(clockid_t clock_id,int sigev_notify)33 void test_timer(clockid_t clock_id, int sigev_notify)
34 {
35 struct sigevent sig = {0};
36 struct itimerspec value, ovalue;
37 struct timespec ts, te;
38 int64_t nsecs_elapsed, secs_elapsed;
39
40 exp_count = 0;
41 sig.sigev_notify = sigev_notify;
42 sig.sigev_notify_function = handler;
43 sig.sigev_value.sival_int = TEST_SIGNAL_VAL;
44
45 /*TESTPOINT: Check if timer is created successfully*/
46 zassert_ok(timer_create(clock_id, &sig, &timerid));
47
48 value.it_value.tv_sec = DURATION_SECS;
49 value.it_value.tv_nsec = DURATION_NSECS;
50 value.it_interval.tv_sec = PERIOD_SECS;
51 value.it_interval.tv_nsec = PERIOD_NSECS;
52 zassert_ok(timer_settime(timerid, 0, &value, &ovalue));
53 usleep(100 * USEC_PER_MSEC);
54 /*TESTPOINT: Check if timer has started successfully*/
55 zassert_ok(timer_gettime(timerid, &value));
56
57 LOG_DBG("Timer fires every %d secs and %d nsecs", (int)value.it_interval.tv_sec,
58 (int)value.it_interval.tv_nsec);
59 LOG_DBG("Time remaining to fire %d secs and %d nsecs", (int)value.it_value.tv_sec,
60 (int)value.it_value.tv_nsec);
61
62 clock_gettime(clock_id, &ts);
63 sleep(SECS_TO_SLEEP);
64 clock_gettime(clock_id, &te);
65
66 if (te.tv_nsec >= ts.tv_nsec) {
67 secs_elapsed = te.tv_sec - ts.tv_sec;
68 nsecs_elapsed = te.tv_nsec - ts.tv_nsec;
69 } else {
70 nsecs_elapsed = NSEC_PER_SEC + te.tv_nsec - ts.tv_nsec;
71 secs_elapsed = (te.tv_sec - ts.tv_sec - 1);
72 }
73
74 uint64_t elapsed = secs_elapsed * NSEC_PER_SEC + nsecs_elapsed;
75 uint64_t first_sig = value.it_value.tv_sec * NSEC_PER_SEC + value.it_value.tv_nsec;
76 uint64_t sig_interval = value.it_interval.tv_sec * NSEC_PER_SEC + value.it_interval.tv_nsec;
77 int expected_signal_count = (elapsed - first_sig) / sig_interval + 1;
78
79 /*TESTPOINT: Check if POSIX timer test passed*/
80 zassert_within(exp_count, expected_signal_count, 1, "POSIX timer test has failed %i != %i",
81 exp_count, expected_signal_count);
82 }
83
ZTEST(posix_timers,test_CLOCK_REALTIME__SIGEV_SIGNAL)84 ZTEST(posix_timers, test_CLOCK_REALTIME__SIGEV_SIGNAL)
85 {
86 test_timer(CLOCK_REALTIME, SIGEV_SIGNAL);
87 }
88
ZTEST(posix_timers,test_CLOCK_REALTIME__SIGEV_THREAD)89 ZTEST(posix_timers, test_CLOCK_REALTIME__SIGEV_THREAD)
90 {
91 test_timer(CLOCK_REALTIME, SIGEV_THREAD);
92 }
93
ZTEST(posix_timers,test_CLOCK_MONOTONIC__SIGEV_SIGNAL)94 ZTEST(posix_timers, test_CLOCK_MONOTONIC__SIGEV_SIGNAL)
95 {
96 test_timer(CLOCK_MONOTONIC, SIGEV_SIGNAL);
97 }
98
ZTEST(posix_timers,test_CLOCK_MONOTONIC__SIGEV_THREAD)99 ZTEST(posix_timers, test_CLOCK_MONOTONIC__SIGEV_THREAD)
100 {
101 test_timer(CLOCK_MONOTONIC, SIGEV_THREAD);
102 }
103
ZTEST(posix_timers,test_timer_overrun)104 ZTEST(posix_timers, test_timer_overrun)
105 {
106 struct sigevent sig = {0};
107 struct itimerspec value;
108
109 sig.sigev_notify = SIGEV_NONE;
110
111 zassert_ok(timer_create(CLOCK_MONOTONIC, &sig, &timerid));
112
113 /*Set the timer to expire every 500 milliseconds*/
114 value.it_interval.tv_sec = 0;
115 value.it_interval.tv_nsec = 500000000;
116 value.it_value.tv_sec = 0;
117 value.it_value.tv_nsec = 500000000;
118 zassert_ok(timer_settime(timerid, 0, &value, NULL));
119 k_sleep(K_MSEC(2500));
120
121 zassert_equal(timer_getoverrun(timerid), 4, "Number of overruns is incorrect");
122 }
123
ZTEST(posix_timers,test_one_shot__SIGEV_SIGNAL)124 ZTEST(posix_timers, test_one_shot__SIGEV_SIGNAL)
125 {
126 struct sigevent sig = {0};
127 struct itimerspec value;
128
129 exp_count = 0;
130 sig.sigev_notify = SIGEV_SIGNAL;
131 sig.sigev_notify_function = handler;
132 sig.sigev_value.sival_int = TEST_SIGNAL_VAL;
133
134 zassert_ok(timer_create(CLOCK_MONOTONIC, &sig, &timerid));
135
136 /*Set the timer to expire only once*/
137 value.it_interval.tv_sec = 0;
138 value.it_interval.tv_nsec = 0;
139 value.it_value.tv_sec = 0;
140 value.it_value.tv_nsec = 100 * NSEC_PER_MSEC;
141 zassert_ok(timer_settime(timerid, 0, &value, NULL));
142 k_sleep(K_MSEC(300));
143
144 zassert_equal(exp_count, 1, "Number of expiry is incorrect");
145 }
146
after(void * arg)147 static void after(void *arg)
148 {
149 ARG_UNUSED(arg);
150
151 if (timerid != -1) {
152 (void)timer_delete(timerid);
153 timerid = -1;
154 }
155 }
156
157 ZTEST_SUITE(posix_timers, NULL, NULL, NULL, after, NULL);
158