blob: af6ae8581767b5519cd2b470ca12cfe5b1306d71 [file] [log] [blame]
Elliott Hughese0175ca2013-03-14 14:38:08 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes4b558f52014-03-04 15:58:02 -080017#include <time.h>
18
19#include <errno.h>
Elliott Hughese0175ca2013-03-14 14:38:08 -070020#include <features.h>
21#include <gtest/gtest.h>
Elliott Hughes4b558f52014-03-04 15:58:02 -080022#include <signal.h>
Brian Carlstrombe1d91d2014-03-08 15:05:26 -080023#include <sys/types.h>
24#include <sys/wait.h>
Elliott Hughese0175ca2013-03-14 14:38:08 -070025
Elliott Hughes4b558f52014-03-04 15:58:02 -080026#include "ScopedSignalHandler.h"
Elliott Hughese0175ca2013-03-14 14:38:08 -070027
Christopher Ferrisf04935c2013-12-20 18:43:21 -080028#if defined(__BIONIC__) // mktime_tz is a bionic extension.
Elliott Hughese0175ca2013-03-14 14:38:08 -070029#include <libc/private/bionic_time.h>
Christopher Ferrisf04935c2013-12-20 18:43:21 -080030#endif // __BIONIC__
31
Elliott Hughese0175ca2013-03-14 14:38:08 -070032TEST(time, mktime_tz) {
Christopher Ferrisf04935c2013-12-20 18:43:21 -080033#if defined(__BIONIC__)
Elliott Hughese0175ca2013-03-14 14:38:08 -070034 struct tm epoch;
35 memset(&epoch, 0, sizeof(tm));
36 epoch.tm_year = 1970 - 1900;
37 epoch.tm_mon = 1;
38 epoch.tm_mday = 1;
39
40 // Alphabetically first. Coincidentally equivalent to UTC.
41 ASSERT_EQ(2678400, mktime_tz(&epoch, "Africa/Abidjan"));
42
43 // Alphabetically last. Coincidentally equivalent to UTC.
44 ASSERT_EQ(2678400, mktime_tz(&epoch, "Zulu"));
45
46 // Somewhere in the middle, not UTC.
47 ASSERT_EQ(2707200, mktime_tz(&epoch, "America/Los_Angeles"));
48
49 // Missing. Falls back to UTC.
50 ASSERT_EQ(2678400, mktime_tz(&epoch, "PST"));
Christopher Ferrisf04935c2013-12-20 18:43:21 -080051#else // __BIONIC__
52 GTEST_LOG_(INFO) << "This test does nothing.\n";
53#endif // __BIONIC__
Elliott Hughese0175ca2013-03-14 14:38:08 -070054}
Elliott Hughesee178bf2013-07-12 11:25:20 -070055
56TEST(time, gmtime) {
57 time_t t = 0;
58 tm* broken_down = gmtime(&t);
59 ASSERT_TRUE(broken_down != NULL);
60 ASSERT_EQ(0, broken_down->tm_sec);
61 ASSERT_EQ(0, broken_down->tm_min);
62 ASSERT_EQ(0, broken_down->tm_hour);
63 ASSERT_EQ(1, broken_down->tm_mday);
64 ASSERT_EQ(0, broken_down->tm_mon);
65 ASSERT_EQ(1970, broken_down->tm_year + 1900);
66}
Elliott Hughes7843d442013-08-22 11:37:32 -070067
Elliott Hughes7843d442013-08-22 11:37:32 -070068TEST(time, mktime_10310929) {
69 struct tm t;
70 memset(&t, 0, sizeof(tm));
71 t.tm_year = 200;
72 t.tm_mon = 2;
73 t.tm_mday = 10;
74
Elliott Hughes0c401522013-10-18 16:21:54 -070075#if !defined(__LP64__)
76 // 32-bit bionic stupidly had a signed 32-bit time_t.
Elliott Hughes7843d442013-08-22 11:37:32 -070077 ASSERT_EQ(-1, mktime(&t));
Christopher Ferrisf04935c2013-12-20 18:43:21 -080078#if defined(__BIONIC__)
Elliott Hughes7843d442013-08-22 11:37:32 -070079 ASSERT_EQ(-1, mktime_tz(&t, "UTC"));
Christopher Ferrisf04935c2013-12-20 18:43:21 -080080#endif
Elliott Hughes0c401522013-10-18 16:21:54 -070081#else
82 // Everyone else should be using a signed 64-bit time_t.
83 ASSERT_GE(sizeof(time_t) * 8, 64U);
84
85 setenv("TZ", "America/Los_Angeles", 1);
86 tzset();
87 ASSERT_EQ(static_cast<time_t>(4108348800U), mktime(&t));
Christopher Ferrisf04935c2013-12-20 18:43:21 -080088#if defined(__BIONIC__)
Elliott Hughes0c401522013-10-18 16:21:54 -070089 ASSERT_EQ(static_cast<time_t>(4108320000U), mktime_tz(&t, "UTC"));
Christopher Ferrisf04935c2013-12-20 18:43:21 -080090#endif
Elliott Hughes0c401522013-10-18 16:21:54 -070091
92 setenv("TZ", "UTC", 1);
93 tzset();
94 ASSERT_EQ(static_cast<time_t>(4108320000U), mktime(&t));
Christopher Ferrisf04935c2013-12-20 18:43:21 -080095#if defined(__BIONIC__)
Elliott Hughes0c401522013-10-18 16:21:54 -070096 ASSERT_EQ(static_cast<time_t>(4108348800U), mktime_tz(&t, "America/Los_Angeles"));
97#endif
Elliott Hughes7843d442013-08-22 11:37:32 -070098#endif
Christopher Ferrisf04935c2013-12-20 18:43:21 -080099}
Elliott Hughes4b558f52014-03-04 15:58:02 -0800100
Elliott Hughes3e3409a2014-03-10 18:19:03 -0700101TEST(time, strftime) {
102 setenv("TZ", "UTC", 1);
103
104 struct tm t;
105 memset(&t, 0, sizeof(tm));
106 t.tm_year = 200;
107 t.tm_mon = 2;
108 t.tm_mday = 10;
109
110 char buf[64];
111
112 // Seconds since the epoch.
113#if defined(__BIONIC__) || defined(__LP64__) // Not 32-bit glibc.
114 EXPECT_EQ(10U, strftime(buf, sizeof(buf), "%s", &t));
115 EXPECT_STREQ("4108320000", buf);
116#endif
117
118 // Date and time as text.
119 EXPECT_EQ(24U, strftime(buf, sizeof(buf), "%c", &t));
120 EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf);
121}
122
123TEST(time, strptime) {
124 setenv("TZ", "UTC", 1);
125
126 struct tm t;
127 char buf[64];
128
129 memset(&t, 0, sizeof(t));
130 strptime("11:14", "%R", &t);
131 strftime(buf, sizeof(buf), "%H:%M", &t);
132 EXPECT_STREQ("11:14", buf);
133
134 memset(&t, 0, sizeof(t));
135 strptime("09:41:53", "%T", &t);
136 strftime(buf, sizeof(buf), "%H:%M:%S", &t);
137 EXPECT_STREQ("09:41:53", buf);
138}
139
Elliott Hughes4b558f52014-03-04 15:58:02 -0800140void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
141 itimerspec ts;
142 ts.it_value.tv_sec = value_s;
143 ts.it_value.tv_nsec = value_ns;
144 ts.it_interval.tv_sec = interval_s;
145 ts.it_interval.tv_nsec = interval_ns;
146 ASSERT_EQ(0, timer_settime(t, TIMER_ABSTIME, &ts, NULL));
147}
148
149static void NoOpNotifyFunction(sigval_t) {
150}
151
152TEST(time, timer_create) {
153 sigevent_t se;
154 memset(&se, 0, sizeof(se));
155 se.sigev_notify = SIGEV_THREAD;
156 se.sigev_notify_function = NoOpNotifyFunction;
157 timer_t timer_id;
158 ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
159
160 int pid = fork();
161 ASSERT_NE(-1, pid) << strerror(errno);
162
163 if (pid == 0) {
164 // Timers are not inherited by the child.
165 ASSERT_EQ(-1, timer_delete(timer_id));
166 ASSERT_EQ(EINVAL, errno);
167 _exit(0);
168 }
169
170 int status;
171 ASSERT_EQ(pid, waitpid(pid, &status, 0));
172 ASSERT_TRUE(WIFEXITED(status));
173 ASSERT_EQ(0, WEXITSTATUS(status));
174
175 ASSERT_EQ(0, timer_delete(timer_id));
176}
177
178static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
179static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) {
180 ++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
181 ASSERT_EQ(SIGUSR1, signal_number);
182}
183
184TEST(time, timer_create_SIGEV_SIGNAL) {
185 sigevent_t se;
186 memset(&se, 0, sizeof(se));
187 se.sigev_notify = SIGEV_SIGNAL;
188 se.sigev_signo = SIGUSR1;
189
190 timer_t timer_id;
191 ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
192
193 ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler);
194
195 ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
196
197 itimerspec ts;
198 ts.it_value.tv_sec = 0;
199 ts.it_value.tv_nsec = 1;
200 ts.it_interval.tv_sec = 0;
201 ts.it_interval.tv_nsec = 0;
202 ASSERT_EQ(0, timer_settime(timer_id, TIMER_ABSTIME, &ts, NULL));
203
204 usleep(500000);
205 ASSERT_EQ(1, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
206}
207
208struct Counter {
209 volatile int value;
210 timer_t timer_id;
211 sigevent_t se;
212
213 Counter(void (*fn)(sigval_t)) : value(0) {
214 memset(&se, 0, sizeof(se));
215 se.sigev_notify = SIGEV_THREAD;
216 se.sigev_notify_function = fn;
217 se.sigev_value.sival_ptr = this;
218 }
219
220 void Create() {
221 ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
222 }
223
224 ~Counter() {
225 if (timer_delete(timer_id) != 0) {
226 abort();
227 }
228 }
229
230 static void CountNotifyFunction(sigval_t value) {
231 Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
232 ++cd->value;
233 }
234
235 static void CountAndDisarmNotifyFunction(sigval_t value) {
236 Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
237 ++cd->value;
238
239 // Setting the initial expiration time to 0 disarms the timer.
240 SetTime(cd->timer_id, 0, 0, 1, 0);
241 }
242};
243
244TEST(time, timer_settime_0) {
245 Counter counter(Counter::CountAndDisarmNotifyFunction);
246 counter.Create();
247
248 ASSERT_EQ(0, counter.value);
249
250 SetTime(counter.timer_id, 0, 1, 1, 0);
251 usleep(500000);
252
253 // The count should just be 1 because we disarmed the timer the first time it fired.
254 ASSERT_EQ(1, counter.value);
255}
256
257TEST(time, timer_settime_repeats) {
258 Counter counter(Counter::CountNotifyFunction);
259 counter.Create();
260
261 ASSERT_EQ(0, counter.value);
262
263 SetTime(counter.timer_id, 0, 1, 0, 10);
264 usleep(500000);
265
266 // The count should just be > 1 because we let the timer repeat.
267 ASSERT_GT(counter.value, 1);
268}
269
270static int timer_create_NULL_signal_handler_invocation_count = 0;
271static void timer_create_NULL_signal_handler(int signal_number) {
272 ++timer_create_NULL_signal_handler_invocation_count;
273 ASSERT_EQ(SIGALRM, signal_number);
274}
275
276TEST(time, timer_create_NULL) {
277 // A NULL sigevent* is equivalent to asking for SIGEV_SIGNAL for SIGALRM.
278 timer_t timer_id;
279 ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
280
281 ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler);
282
283 ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count);
284
285 SetTime(timer_id, 0, 1, 0, 0);
286 usleep(500000);
287
288 ASSERT_EQ(1, timer_create_NULL_signal_handler_invocation_count);
289}
290
291TEST(time, timer_create_EINVAL) {
292 clockid_t invalid_clock = 16;
293
294 // A SIGEV_SIGNAL timer is easy; the kernel does all that.
295 timer_t timer_id;
296 ASSERT_EQ(-1, timer_create(invalid_clock, NULL, &timer_id));
297 ASSERT_EQ(EINVAL, errno);
298
299 // A SIGEV_THREAD timer is more interesting because we have stuff to clean up.
300 sigevent_t se;
301 memset(&se, 0, sizeof(se));
302 se.sigev_notify = SIGEV_THREAD;
303 se.sigev_notify_function = NoOpNotifyFunction;
304 ASSERT_EQ(-1, timer_create(invalid_clock, &se, &timer_id));
305 ASSERT_EQ(EINVAL, errno);
306}
307
308TEST(time, timer_delete_multiple) {
309 timer_t timer_id;
310 ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
311 ASSERT_EQ(0, timer_delete(timer_id));
312 ASSERT_EQ(-1, timer_delete(timer_id));
313 ASSERT_EQ(EINVAL, errno);
314
315 sigevent_t se;
316 memset(&se, 0, sizeof(se));
317 se.sigev_notify = SIGEV_THREAD;
318 se.sigev_notify_function = NoOpNotifyFunction;
319 ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
320 ASSERT_EQ(0, timer_delete(timer_id));
321 ASSERT_EQ(-1, timer_delete(timer_id));
322 ASSERT_EQ(EINVAL, errno);
323}
324
325TEST(time, timer_create_multiple) {
326 Counter counter1(Counter::CountNotifyFunction);
327 counter1.Create();
328 Counter counter2(Counter::CountNotifyFunction);
329 counter2.Create();
330 Counter counter3(Counter::CountNotifyFunction);
331 counter3.Create();
332
333 ASSERT_EQ(0, counter1.value);
334 ASSERT_EQ(0, counter2.value);
335 ASSERT_EQ(0, counter3.value);
336
337 SetTime(counter2.timer_id, 0, 1, 0, 0);
338 usleep(500000);
339
340 EXPECT_EQ(0, counter1.value);
341 EXPECT_EQ(1, counter2.value);
342 EXPECT_EQ(0, counter3.value);
343}