time_test.cpp revision 753ad778bc1c3aecc4cd82b8387a7dc8a9b44d34
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 101TEST(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 140void 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} 344 345struct TimerDeleteData { 346 timer_t timer_id; 347 pthread_t thread_id; 348 volatile bool complete; 349}; 350 351static void TimerDeleteCallback(sigval_t value) { 352 TimerDeleteData* tdd = reinterpret_cast<TimerDeleteData*>(value.sival_ptr); 353 354 tdd->thread_id = pthread_self(); 355 timer_delete(tdd->timer_id); 356 tdd->complete = true; 357} 358 359TEST(time, timer_delete_from_timer_thread) { 360 TimerDeleteData tdd; 361 sigevent_t se; 362 363 memset(&se, 0, sizeof(se)); 364 se.sigev_notify = SIGEV_THREAD; 365 se.sigev_notify_function = TimerDeleteCallback; 366 se.sigev_value.sival_ptr = &tdd; 367 368 tdd.complete = false; 369 ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &tdd.timer_id)); 370 371 itimerspec ts; 372 ts.it_value.tv_sec = 0; 373 ts.it_value.tv_nsec = 100; 374 ts.it_interval.tv_sec = 0; 375 ts.it_interval.tv_nsec = 0; 376 ASSERT_EQ(0, timer_settime(tdd.timer_id, TIMER_ABSTIME, &ts, NULL)); 377 378 time_t cur_time = time(NULL); 379 while (!tdd.complete && (time(NULL) - cur_time) < 5); 380 ASSERT_TRUE(tdd.complete); 381 382#if defined(__BIONIC__) 383 // Since bionic timers are implemented by creating a thread to handle the 384 // callback, verify that the thread actually completes. 385 cur_time = time(NULL); 386 while (pthread_detach(tdd.thread_id) != ESRCH && (time(NULL) - cur_time) < 5); 387 ASSERT_EQ(ESRCH, pthread_detach(tdd.thread_id)); 388#endif 389} 390