time_test.cpp revision 329103d3e2f42d3e35a060c3e0d326d6476eb2ef
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 <pthread.h>
23#include <signal.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26
27#include "ScopedSignalHandler.h"
28
29#if defined(__BIONIC__) // mktime_tz is a bionic extension.
30#include <libc/private/bionic_time.h>
31#endif // __BIONIC__
32
33TEST(time, mktime_tz) {
34#if defined(__BIONIC__)
35  struct tm epoch;
36  memset(&epoch, 0, sizeof(tm));
37  epoch.tm_year = 1970 - 1900;
38  epoch.tm_mon = 1;
39  epoch.tm_mday = 1;
40
41  // Alphabetically first. Coincidentally equivalent to UTC.
42  ASSERT_EQ(2678400, mktime_tz(&epoch, "Africa/Abidjan"));
43
44  // Alphabetically last. Coincidentally equivalent to UTC.
45  ASSERT_EQ(2678400, mktime_tz(&epoch, "Zulu"));
46
47  // Somewhere in the middle, not UTC.
48  ASSERT_EQ(2707200, mktime_tz(&epoch, "America/Los_Angeles"));
49
50  // Missing. Falls back to UTC.
51  ASSERT_EQ(2678400, mktime_tz(&epoch, "PST"));
52#else // __BIONIC__
53  GTEST_LOG_(INFO) << "This test does nothing.\n";
54#endif // __BIONIC__
55}
56
57TEST(time, gmtime) {
58  time_t t = 0;
59  tm* broken_down = gmtime(&t);
60  ASSERT_TRUE(broken_down != NULL);
61  ASSERT_EQ(0, broken_down->tm_sec);
62  ASSERT_EQ(0, broken_down->tm_min);
63  ASSERT_EQ(0, broken_down->tm_hour);
64  ASSERT_EQ(1, broken_down->tm_mday);
65  ASSERT_EQ(0, broken_down->tm_mon);
66  ASSERT_EQ(1970, broken_down->tm_year + 1900);
67}
68
69static void* gmtime_no_stack_overflow_14313703_fn(void*) {
70  const char* original_tz = getenv("TZ");
71  // Ensure we'll actually have to enter tzload by using a time zone that doesn't exist.
72  setenv("TZ", "gmtime_stack_overflow_14313703", 1);
73  tzset();
74  if (original_tz != NULL) {
75    setenv("TZ", original_tz, 1);
76  }
77  tzset();
78  return NULL;
79}
80
81TEST(time, gmtime_no_stack_overflow_14313703) {
82  // Is it safe to call tzload on a thread with a small stack?
83  // http://b/14313703
84  // https://code.google.com/p/android/issues/detail?id=61130
85  pthread_attr_t attributes;
86  ASSERT_EQ(0, pthread_attr_init(&attributes));
87#if defined(__BIONIC__)
88  ASSERT_EQ(0, pthread_attr_setstacksize(&attributes, PTHREAD_STACK_MIN));
89#else
90  // PTHREAD_STACK_MIN not currently in the host GCC sysroot.
91  ASSERT_EQ(0, pthread_attr_setstacksize(&attributes, 4 * getpagesize()));
92#endif
93
94  pthread_t t;
95  ASSERT_EQ(0, pthread_create(&t, &attributes, gmtime_no_stack_overflow_14313703_fn, NULL));
96  void* result;
97  ASSERT_EQ(0, pthread_join(t, &result));
98}
99
100TEST(time, mktime_10310929) {
101  struct tm t;
102  memset(&t, 0, sizeof(tm));
103  t.tm_year = 200;
104  t.tm_mon = 2;
105  t.tm_mday = 10;
106
107#if !defined(__LP64__)
108  // 32-bit bionic stupidly had a signed 32-bit time_t.
109  ASSERT_EQ(-1, mktime(&t));
110#if defined(__BIONIC__)
111  ASSERT_EQ(-1, mktime_tz(&t, "UTC"));
112#endif
113#else
114  // Everyone else should be using a signed 64-bit time_t.
115  ASSERT_GE(sizeof(time_t) * 8, 64U);
116
117  setenv("TZ", "America/Los_Angeles", 1);
118  tzset();
119  ASSERT_EQ(static_cast<time_t>(4108348800U), mktime(&t));
120#if defined(__BIONIC__)
121  ASSERT_EQ(static_cast<time_t>(4108320000U), mktime_tz(&t, "UTC"));
122#endif
123
124  setenv("TZ", "UTC", 1);
125  tzset();
126  ASSERT_EQ(static_cast<time_t>(4108320000U), mktime(&t));
127#if defined(__BIONIC__)
128  ASSERT_EQ(static_cast<time_t>(4108348800U), mktime_tz(&t, "America/Los_Angeles"));
129#endif
130#endif
131}
132
133TEST(time, strftime) {
134  setenv("TZ", "UTC", 1);
135
136  struct tm t;
137  memset(&t, 0, sizeof(tm));
138  t.tm_year = 200;
139  t.tm_mon = 2;
140  t.tm_mday = 10;
141
142  char buf[64];
143
144  // Seconds since the epoch.
145#if defined(__BIONIC__) || defined(__LP64__) // Not 32-bit glibc.
146  EXPECT_EQ(10U, strftime(buf, sizeof(buf), "%s", &t));
147  EXPECT_STREQ("4108320000", buf);
148#endif
149
150  // Date and time as text.
151  EXPECT_EQ(24U, strftime(buf, sizeof(buf), "%c", &t));
152  EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf);
153}
154
155TEST(time, strptime) {
156  setenv("TZ", "UTC", 1);
157
158  struct tm t;
159  char buf[64];
160
161  memset(&t, 0, sizeof(t));
162  strptime("11:14", "%R", &t);
163  strftime(buf, sizeof(buf), "%H:%M", &t);
164  EXPECT_STREQ("11:14", buf);
165
166  memset(&t, 0, sizeof(t));
167  strptime("09:41:53", "%T", &t);
168  strftime(buf, sizeof(buf), "%H:%M:%S", &t);
169  EXPECT_STREQ("09:41:53", buf);
170}
171
172void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
173  itimerspec ts;
174  ts.it_value.tv_sec = value_s;
175  ts.it_value.tv_nsec = value_ns;
176  ts.it_interval.tv_sec = interval_s;
177  ts.it_interval.tv_nsec = interval_ns;
178  ASSERT_EQ(0, timer_settime(t, TIMER_ABSTIME, &ts, NULL));
179}
180
181static void NoOpNotifyFunction(sigval_t) {
182}
183
184TEST(time, timer_create) {
185  sigevent_t se;
186  memset(&se, 0, sizeof(se));
187  se.sigev_notify = SIGEV_THREAD;
188  se.sigev_notify_function = NoOpNotifyFunction;
189  timer_t timer_id;
190  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
191
192  int pid = fork();
193  ASSERT_NE(-1, pid) << strerror(errno);
194
195  if (pid == 0) {
196    // Timers are not inherited by the child.
197    ASSERT_EQ(-1, timer_delete(timer_id));
198    ASSERT_EQ(EINVAL, errno);
199    _exit(0);
200  }
201
202  int status;
203  ASSERT_EQ(pid, waitpid(pid, &status, 0));
204  ASSERT_TRUE(WIFEXITED(status));
205  ASSERT_EQ(0, WEXITSTATUS(status));
206
207  ASSERT_EQ(0, timer_delete(timer_id));
208}
209
210static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
211static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) {
212  ++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
213  ASSERT_EQ(SIGUSR1, signal_number);
214}
215
216TEST(time, timer_create_SIGEV_SIGNAL) {
217  sigevent_t se;
218  memset(&se, 0, sizeof(se));
219  se.sigev_notify = SIGEV_SIGNAL;
220  se.sigev_signo = SIGUSR1;
221
222  timer_t timer_id;
223  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
224
225  ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler);
226
227  ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
228
229  itimerspec ts;
230  ts.it_value.tv_sec =  0;
231  ts.it_value.tv_nsec = 1;
232  ts.it_interval.tv_sec = 0;
233  ts.it_interval.tv_nsec = 0;
234  ASSERT_EQ(0, timer_settime(timer_id, TIMER_ABSTIME, &ts, NULL));
235
236  usleep(500000);
237  ASSERT_EQ(1, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
238}
239
240struct Counter {
241  volatile int value;
242  timer_t timer_id;
243  sigevent_t se;
244
245  Counter(void (*fn)(sigval_t)) : value(0) {
246    memset(&se, 0, sizeof(se));
247    se.sigev_notify = SIGEV_THREAD;
248    se.sigev_notify_function = fn;
249    se.sigev_value.sival_ptr = this;
250  }
251
252  void Create() {
253    ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
254  }
255
256  ~Counter() {
257    if (timer_delete(timer_id) != 0) {
258      abort();
259    }
260  }
261
262  static void CountNotifyFunction(sigval_t value) {
263    Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
264    ++cd->value;
265  }
266
267  static void CountAndDisarmNotifyFunction(sigval_t value) {
268    Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
269    ++cd->value;
270
271    // Setting the initial expiration time to 0 disarms the timer.
272    SetTime(cd->timer_id, 0, 0, 1, 0);
273  }
274};
275
276TEST(time, timer_settime_0) {
277  Counter counter(Counter::CountAndDisarmNotifyFunction);
278  counter.Create();
279
280  ASSERT_EQ(0, counter.value);
281
282  SetTime(counter.timer_id, 0, 1, 1, 0);
283  usleep(500000);
284
285  // The count should just be 1 because we disarmed the timer the first time it fired.
286  ASSERT_EQ(1, counter.value);
287}
288
289TEST(time, timer_settime_repeats) {
290  Counter counter(Counter::CountNotifyFunction);
291  counter.Create();
292
293  ASSERT_EQ(0, counter.value);
294
295  SetTime(counter.timer_id, 0, 1, 0, 10);
296  usleep(500000);
297
298  // The count should just be > 1 because we let the timer repeat.
299  ASSERT_GT(counter.value, 1);
300}
301
302static int timer_create_NULL_signal_handler_invocation_count = 0;
303static void timer_create_NULL_signal_handler(int signal_number) {
304  ++timer_create_NULL_signal_handler_invocation_count;
305  ASSERT_EQ(SIGALRM, signal_number);
306}
307
308TEST(time, timer_create_NULL) {
309  // A NULL sigevent* is equivalent to asking for SIGEV_SIGNAL for SIGALRM.
310  timer_t timer_id;
311  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
312
313  ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler);
314
315  ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count);
316
317  SetTime(timer_id, 0, 1, 0, 0);
318  usleep(500000);
319
320  ASSERT_EQ(1, timer_create_NULL_signal_handler_invocation_count);
321}
322
323TEST(time, timer_create_EINVAL) {
324  clockid_t invalid_clock = 16;
325
326  // A SIGEV_SIGNAL timer is easy; the kernel does all that.
327  timer_t timer_id;
328  ASSERT_EQ(-1, timer_create(invalid_clock, NULL, &timer_id));
329  ASSERT_EQ(EINVAL, errno);
330
331  // A SIGEV_THREAD timer is more interesting because we have stuff to clean up.
332  sigevent_t se;
333  memset(&se, 0, sizeof(se));
334  se.sigev_notify = SIGEV_THREAD;
335  se.sigev_notify_function = NoOpNotifyFunction;
336  ASSERT_EQ(-1, timer_create(invalid_clock, &se, &timer_id));
337  ASSERT_EQ(EINVAL, errno);
338}
339
340TEST(time, timer_delete_multiple) {
341  timer_t timer_id;
342  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
343  ASSERT_EQ(0, timer_delete(timer_id));
344  ASSERT_EQ(-1, timer_delete(timer_id));
345  ASSERT_EQ(EINVAL, errno);
346
347  sigevent_t se;
348  memset(&se, 0, sizeof(se));
349  se.sigev_notify = SIGEV_THREAD;
350  se.sigev_notify_function = NoOpNotifyFunction;
351  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
352  ASSERT_EQ(0, timer_delete(timer_id));
353  ASSERT_EQ(-1, timer_delete(timer_id));
354  ASSERT_EQ(EINVAL, errno);
355}
356
357TEST(time, timer_create_multiple) {
358  Counter counter1(Counter::CountNotifyFunction);
359  counter1.Create();
360  Counter counter2(Counter::CountNotifyFunction);
361  counter2.Create();
362  Counter counter3(Counter::CountNotifyFunction);
363  counter3.Create();
364
365  ASSERT_EQ(0, counter1.value);
366  ASSERT_EQ(0, counter2.value);
367  ASSERT_EQ(0, counter3.value);
368
369  SetTime(counter2.timer_id, 0, 1, 0, 0);
370  usleep(500000);
371
372  EXPECT_EQ(0, counter1.value);
373  EXPECT_EQ(1, counter2.value);
374  EXPECT_EQ(0, counter3.value);
375}
376
377struct TimerDeleteData {
378  timer_t timer_id;
379  pthread_t thread_id;
380  volatile bool complete;
381};
382
383static void TimerDeleteCallback(sigval_t value) {
384  TimerDeleteData* tdd = reinterpret_cast<TimerDeleteData*>(value.sival_ptr);
385
386  tdd->thread_id = pthread_self();
387  timer_delete(tdd->timer_id);
388  tdd->complete = true;
389}
390
391TEST(time, timer_delete_from_timer_thread) {
392  TimerDeleteData tdd;
393  sigevent_t se;
394
395  memset(&se, 0, sizeof(se));
396  se.sigev_notify = SIGEV_THREAD;
397  se.sigev_notify_function = TimerDeleteCallback;
398  se.sigev_value.sival_ptr = &tdd;
399
400  tdd.complete = false;
401  ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &tdd.timer_id));
402
403  itimerspec ts;
404  ts.it_value.tv_sec = 0;
405  ts.it_value.tv_nsec = 100;
406  ts.it_interval.tv_sec = 0;
407  ts.it_interval.tv_nsec = 0;
408  ASSERT_EQ(0, timer_settime(tdd.timer_id, TIMER_ABSTIME, &ts, NULL));
409
410  time_t cur_time = time(NULL);
411  while (!tdd.complete && (time(NULL) - cur_time) < 5);
412  ASSERT_TRUE(tdd.complete);
413
414#if defined(__BIONIC__)
415  // Since bionic timers are implemented by creating a thread to handle the
416  // callback, verify that the thread actually completes.
417  cur_time = time(NULL);
418  while (pthread_detach(tdd.thread_id) != ESRCH && (time(NULL) - cur_time) < 5);
419  ASSERT_EQ(ESRCH, pthread_detach(tdd.thread_id));
420#endif
421}
422