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