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