time_test.cpp revision be1d91dedcfb346ced5ac496cd454f5b2e9bc4a9
1/*
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
17#include <time.h>
18
19#include <errno.h>
20#include <features.h>
21#include <gtest/gtest.h>
22#include <signal.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25
26#include "ScopedSignalHandler.h"
27
28#if defined(__BIONIC__) // mktime_tz is a bionic extension.
29#include <libc/private/bionic_time.h>
30#endif // __BIONIC__
31
32TEST(time, mktime_tz) {
33#if defined(__BIONIC__)
34  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"));
51#else // __BIONIC__
52  GTEST_LOG_(INFO) << "This test does nothing.\n";
53#endif // __BIONIC__
54}
55
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}
67
68TEST(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
75#if !defined(__LP64__)
76  // 32-bit bionic stupidly had a signed 32-bit time_t.
77  ASSERT_EQ(-1, mktime(&t));
78#if defined(__BIONIC__)
79  ASSERT_EQ(-1, mktime_tz(&t, "UTC"));
80#endif
81#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));
88#if defined(__BIONIC__)
89  ASSERT_EQ(static_cast<time_t>(4108320000U), mktime_tz(&t, "UTC"));
90#endif
91
92  setenv("TZ", "UTC", 1);
93  tzset();
94  ASSERT_EQ(static_cast<time_t>(4108320000U), mktime(&t));
95#if defined(__BIONIC__)
96  ASSERT_EQ(static_cast<time_t>(4108348800U), mktime_tz(&t, "America/Los_Angeles"));
97#endif
98#endif
99}
100
101void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
102  itimerspec ts;
103  ts.it_value.tv_sec = value_s;
104  ts.it_value.tv_nsec = value_ns;
105  ts.it_interval.tv_sec = interval_s;
106  ts.it_interval.tv_nsec = interval_ns;
107  ASSERT_EQ(0, timer_settime(t, TIMER_ABSTIME, &ts, NULL));
108}
109
110static void NoOpNotifyFunction(sigval_t) {
111}
112
113TEST(time, timer_create) {
114  sigevent_t se;
115  memset(&se, 0, sizeof(se));
116  se.sigev_notify = SIGEV_THREAD;
117  se.sigev_notify_function = NoOpNotifyFunction;
118  timer_t timer_id;
119  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
120
121  int pid = fork();
122  ASSERT_NE(-1, pid) << strerror(errno);
123
124  if (pid == 0) {
125    // Timers are not inherited by the child.
126    ASSERT_EQ(-1, timer_delete(timer_id));
127    ASSERT_EQ(EINVAL, errno);
128    _exit(0);
129  }
130
131  int status;
132  ASSERT_EQ(pid, waitpid(pid, &status, 0));
133  ASSERT_TRUE(WIFEXITED(status));
134  ASSERT_EQ(0, WEXITSTATUS(status));
135
136  ASSERT_EQ(0, timer_delete(timer_id));
137}
138
139static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
140static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) {
141  ++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
142  ASSERT_EQ(SIGUSR1, signal_number);
143}
144
145TEST(time, timer_create_SIGEV_SIGNAL) {
146  sigevent_t se;
147  memset(&se, 0, sizeof(se));
148  se.sigev_notify = SIGEV_SIGNAL;
149  se.sigev_signo = SIGUSR1;
150
151  timer_t timer_id;
152  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
153
154  ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler);
155
156  ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
157
158  itimerspec ts;
159  ts.it_value.tv_sec =  0;
160  ts.it_value.tv_nsec = 1;
161  ts.it_interval.tv_sec = 0;
162  ts.it_interval.tv_nsec = 0;
163  ASSERT_EQ(0, timer_settime(timer_id, TIMER_ABSTIME, &ts, NULL));
164
165  usleep(500000);
166  ASSERT_EQ(1, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
167}
168
169struct Counter {
170  volatile int value;
171  timer_t timer_id;
172  sigevent_t se;
173
174  Counter(void (*fn)(sigval_t)) : value(0) {
175    memset(&se, 0, sizeof(se));
176    se.sigev_notify = SIGEV_THREAD;
177    se.sigev_notify_function = fn;
178    se.sigev_value.sival_ptr = this;
179  }
180
181  void Create() {
182    ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
183  }
184
185  ~Counter() {
186    if (timer_delete(timer_id) != 0) {
187      abort();
188    }
189  }
190
191  static void CountNotifyFunction(sigval_t value) {
192    Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
193    ++cd->value;
194  }
195
196  static void CountAndDisarmNotifyFunction(sigval_t value) {
197    Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
198    ++cd->value;
199
200    // Setting the initial expiration time to 0 disarms the timer.
201    SetTime(cd->timer_id, 0, 0, 1, 0);
202  }
203};
204
205TEST(time, timer_settime_0) {
206  Counter counter(Counter::CountAndDisarmNotifyFunction);
207  counter.Create();
208
209  ASSERT_EQ(0, counter.value);
210
211  SetTime(counter.timer_id, 0, 1, 1, 0);
212  usleep(500000);
213
214  // The count should just be 1 because we disarmed the timer the first time it fired.
215  ASSERT_EQ(1, counter.value);
216}
217
218TEST(time, timer_settime_repeats) {
219  Counter counter(Counter::CountNotifyFunction);
220  counter.Create();
221
222  ASSERT_EQ(0, counter.value);
223
224  SetTime(counter.timer_id, 0, 1, 0, 10);
225  usleep(500000);
226
227  // The count should just be > 1 because we let the timer repeat.
228  ASSERT_GT(counter.value, 1);
229}
230
231static int timer_create_NULL_signal_handler_invocation_count = 0;
232static void timer_create_NULL_signal_handler(int signal_number) {
233  ++timer_create_NULL_signal_handler_invocation_count;
234  ASSERT_EQ(SIGALRM, signal_number);
235}
236
237TEST(time, timer_create_NULL) {
238  // A NULL sigevent* is equivalent to asking for SIGEV_SIGNAL for SIGALRM.
239  timer_t timer_id;
240  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
241
242  ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler);
243
244  ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count);
245
246  SetTime(timer_id, 0, 1, 0, 0);
247  usleep(500000);
248
249  ASSERT_EQ(1, timer_create_NULL_signal_handler_invocation_count);
250}
251
252TEST(time, timer_create_EINVAL) {
253  clockid_t invalid_clock = 16;
254
255  // A SIGEV_SIGNAL timer is easy; the kernel does all that.
256  timer_t timer_id;
257  ASSERT_EQ(-1, timer_create(invalid_clock, NULL, &timer_id));
258  ASSERT_EQ(EINVAL, errno);
259
260  // A SIGEV_THREAD timer is more interesting because we have stuff to clean up.
261  sigevent_t se;
262  memset(&se, 0, sizeof(se));
263  se.sigev_notify = SIGEV_THREAD;
264  se.sigev_notify_function = NoOpNotifyFunction;
265  ASSERT_EQ(-1, timer_create(invalid_clock, &se, &timer_id));
266  ASSERT_EQ(EINVAL, errno);
267}
268
269TEST(time, timer_delete_multiple) {
270  timer_t timer_id;
271  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
272  ASSERT_EQ(0, timer_delete(timer_id));
273  ASSERT_EQ(-1, timer_delete(timer_id));
274  ASSERT_EQ(EINVAL, errno);
275
276  sigevent_t se;
277  memset(&se, 0, sizeof(se));
278  se.sigev_notify = SIGEV_THREAD;
279  se.sigev_notify_function = NoOpNotifyFunction;
280  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
281  ASSERT_EQ(0, timer_delete(timer_id));
282  ASSERT_EQ(-1, timer_delete(timer_id));
283  ASSERT_EQ(EINVAL, errno);
284}
285
286TEST(time, timer_create_multiple) {
287  Counter counter1(Counter::CountNotifyFunction);
288  counter1.Create();
289  Counter counter2(Counter::CountNotifyFunction);
290  counter2.Create();
291  Counter counter3(Counter::CountNotifyFunction);
292  counter3.Create();
293
294  ASSERT_EQ(0, counter1.value);
295  ASSERT_EQ(0, counter2.value);
296  ASSERT_EQ(0, counter3.value);
297
298  SetTime(counter2.timer_id, 0, 1, 0, 0);
299  usleep(500000);
300
301  EXPECT_EQ(0, counter1.value);
302  EXPECT_EQ(1, counter2.value);
303  EXPECT_EQ(0, counter3.value);
304}
305