Changeset bd41ac52 in mainline for uspace/lib/c/generic/time.c
- Timestamp:
- 2018-08-25T22:21:25Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- cca80a2
- Parents:
- e2625b1a
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/time.c
re2625b1a rbd41ac52 35 35 */ 36 36 37 #include <sys/time.h>38 37 #include <time.h> 39 38 #include <stdbool.h> … … 51 50 #include <loc.h> 52 51 #include <device/clock_dev.h> 52 #include <stats.h> 53 53 54 54 #define ASCTIME_BUF_LEN 26 … … 57 57 #define MINS_PER_HOUR 60 58 58 #define SECS_PER_MIN 60 59 #define USECS_PER_SEC 100000059 #define NSECS_PER_SEC 1000000000ll 60 60 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 61 61 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) … … 71 71 static async_sess_t *clock_conn = NULL; 72 72 73 /** 74 * Get CPU time used since the process invocation. 75 * 76 * @return Consumed microseconds by this process or -1 if not available. 77 */ 78 clock_t clock(void) 79 { 80 static_assert(CLOCKS_PER_SEC == 1000000); 81 82 size_t count; 83 stats_cpu_t *cpu_stats = stats_get_cpus(&count); 84 if (!cpu_stats) 85 return (clock_t) -1; 86 if (!cpu_stats->frequency_mhz) { 87 free(cpu_stats); 88 return (clock_t) -1; 89 } 90 91 clock_t total_usecs = -1; 92 if (cpu_stats) { 93 stats_task_t *task_stats = stats_get_task(task_get_id()); 94 if (task_stats) { 95 total_usecs = (clock_t) (task_stats->kcycles + 96 task_stats->ucycles) / cpu_stats->frequency_mhz; 97 free(task_stats); 98 } 99 free(cpu_stats); 100 } 101 102 return total_usecs; 103 } 104 73 105 /** Check whether the year is a leap year. 74 106 * … … 252 284 * 253 285 * @param tm Broken-down time to normalize. 254 * @param t v Timevalto add.286 * @param ts Timespec to add. 255 287 * 256 288 * @return 0 on success, -1 on overflow 257 289 * 258 290 */ 259 static int normalize_tm_t v(struct tm *tm, const struct timeval *tv)291 static int normalize_tm_ts(struct tm *tm, const struct timespec *ts) 260 292 { 261 293 // TODO: DST correction 262 294 263 295 /* Set initial values. */ 264 time_t usec = tm->tm_usec + tv->tv_usec;265 time_t sec = tm->tm_sec + t v->tv_sec;296 time_t nsec = tm->tm_nsec + ts->tv_nsec; 297 time_t sec = tm->tm_sec + ts->tv_sec; 266 298 time_t min = tm->tm_min; 267 299 time_t hour = tm->tm_hour; … … 271 303 272 304 /* Adjust time. */ 273 sec += floor_div( usec, USECS_PER_SEC);274 usec = floor_mod(usec, USECS_PER_SEC);305 sec += floor_div(nsec, NSECS_PER_SEC); 306 nsec = floor_mod(nsec, NSECS_PER_SEC); 275 307 min += floor_div(sec, SECS_PER_MIN); 276 308 sec = floor_mod(sec, SECS_PER_MIN); … … 321 353 322 354 /* And put the values back to the struct. */ 323 tm->tm_ usec = (int) usec;355 tm->tm_nsec = (int) nsec; 324 356 tm->tm_sec = (int) sec; 325 357 tm->tm_min = (int) min; … … 340 372 static int normalize_tm_time(struct tm *tm, time_t time) 341 373 { 342 struct time val tv= {374 struct timespec ts = { 343 375 .tv_sec = time, 344 .tv_ usec = 0376 .tv_nsec = 0 345 377 }; 346 378 347 return normalize_tm_t v(tm, &tv);379 return normalize_tm_ts(tm, &ts); 348 380 } 349 381 … … 456 488 } 457 489 458 static void tv_normalize(struct timeval *tv) 459 { 460 while (tv->tv_usec > USECS_PER_SEC) { 461 tv->tv_sec++; 462 tv->tv_usec -= USECS_PER_SEC; 463 } 464 while (tv->tv_usec < 0) { 465 tv->tv_sec--; 466 tv->tv_usec += USECS_PER_SEC; 467 } 468 } 469 470 /** Add microseconds to given timeval. 471 * 472 * @param tv Destination timeval. 473 * @param usecs Number of microseconds to add. 474 * 475 */ 476 void tv_add_diff(struct timeval *tv, suseconds_t usecs) 477 { 478 tv->tv_sec += usecs / USECS_PER_SEC; 479 tv->tv_usec += usecs % USECS_PER_SEC; 480 tv_normalize(tv); 481 } 482 483 /** Add two timevals. 484 * 485 * @param tv1 First timeval. 486 * @param tv2 Second timeval. 487 */ 488 void tv_add(struct timeval *tv1, const struct timeval *tv2) 489 { 490 tv1->tv_sec += tv2->tv_sec; 491 tv1->tv_usec += tv2->tv_usec; 492 tv_normalize(tv1); 493 } 494 495 /** Subtract two timevals. 496 * 497 * @param tv1 First timeval. 498 * @param tv2 Second timeval. 499 * 500 * @return Difference between tv1 and tv2 (tv1 - tv2) in 501 * microseconds. 502 * 503 */ 504 suseconds_t tv_sub_diff(const struct timeval *tv1, const struct timeval *tv2) 505 { 506 return (tv1->tv_usec - tv2->tv_usec) + 507 ((tv1->tv_sec - tv2->tv_sec) * USECS_PER_SEC); 508 } 509 510 /** Subtract two timevals. 511 * 512 * @param tv1 First timeval. 513 * @param tv2 Second timeval. 514 * 515 */ 516 void tv_sub(struct timeval *tv1, const struct timeval *tv2) 517 { 518 tv1->tv_sec -= tv2->tv_sec; 519 tv1->tv_usec -= tv2->tv_usec; 520 tv_normalize(tv1); 521 } 522 523 /** Decide if one timeval is greater than the other. 524 * 525 * @param t1 First timeval. 526 * @param t2 Second timeval. 527 * 528 * @return True if tv1 is greater than tv2. 529 * @return False otherwise. 530 * 531 */ 532 int tv_gt(const struct timeval *tv1, const struct timeval *tv2) 533 { 534 if (tv1->tv_sec > tv2->tv_sec) 490 static void ts_normalize(struct timespec *ts) 491 { 492 while (ts->tv_nsec >= NSECS_PER_SEC) { 493 ts->tv_sec++; 494 ts->tv_nsec -= NSECS_PER_SEC; 495 } 496 while (ts->tv_nsec < 0) { 497 ts->tv_sec--; 498 ts->tv_nsec += NSECS_PER_SEC; 499 } 500 } 501 502 /** Add nanoseconds to given timespec. 503 * 504 * @param ts Destination timespec. 505 * @param nsecs Number of nanoseconds to add. 506 * 507 */ 508 void ts_add_diff(struct timespec *ts, nsec_t nsecs) 509 { 510 ts->tv_sec += nsecs / NSECS_PER_SEC; 511 ts->tv_nsec += nsecs % NSECS_PER_SEC; 512 ts_normalize(ts); 513 } 514 515 /** Add two timespecs. 516 * 517 * @param ts1 First timespec. 518 * @param ts2 Second timespec. 519 */ 520 void ts_add(struct timespec *ts1, const struct timespec *ts2) 521 { 522 ts1->tv_sec += ts2->tv_sec; 523 ts1->tv_nsec += ts2->tv_nsec; 524 ts_normalize(ts1); 525 } 526 527 /** Subtract two timespecs. 528 * 529 * @param ts1 First timespec. 530 * @param ts2 Second timespec. 531 * 532 * @return Difference between ts1 and ts2 (ts1 - ts2) in nanoseconds. 533 * 534 */ 535 nsec_t ts_sub_diff(const struct timespec *ts1, const struct timespec *ts2) 536 { 537 return (nsec_t) (ts1->tv_nsec - ts2->tv_nsec) + 538 SEC2NSEC((ts1->tv_sec - ts2->tv_sec)); 539 } 540 541 /** Subtract two timespecs. 542 * 543 * @param ts1 First timespec. 544 * @param ts2 Second timespec. 545 * 546 */ 547 void ts_sub(struct timespec *ts1, const struct timespec *ts2) 548 { 549 ts1->tv_sec -= ts2->tv_sec; 550 ts1->tv_nsec -= ts2->tv_nsec; 551 ts_normalize(ts1); 552 } 553 554 /** Decide if one timespec is greater than the other. 555 * 556 * @param ts1 First timespec. 557 * @param ts2 Second timespec. 558 * 559 * @return True if ts1 is greater than ts2. 560 * @return False otherwise. 561 * 562 */ 563 bool ts_gt(const struct timespec *ts1, const struct timespec *ts2) 564 { 565 if (ts1->tv_sec > ts2->tv_sec) 535 566 return true; 536 567 537 if ((t v1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec))568 if ((ts1->tv_sec == ts2->tv_sec) && (ts1->tv_nsec > ts2->tv_nsec)) 538 569 return true; 539 570 … … 541 572 } 542 573 543 /** Decide if one time valis greater than or equal to the other.544 * 545 * @param t v1 First timeval.546 * @param t v2 Second timeval.547 * 548 * @return True if tv1 is greater than or equal to tv2.549 * @return False otherwise.550 * 551 */ 552 int tv_gteq(const struct timeval *tv1, const struct timeval *tv2)553 { 554 if (t v1->tv_sec > tv2->tv_sec)574 /** Decide if one timespec is greater than or equal to the other. 575 * 576 * @param ts1 First timespec. 577 * @param ts2 Second timespec. 578 * 579 * @return True if ts1 is greater than or equal to ts2. 580 * @return False otherwise. 581 * 582 */ 583 bool ts_gteq(const struct timespec *ts1, const struct timespec *ts2) 584 { 585 if (ts1->tv_sec > ts2->tv_sec) 555 586 return true; 556 587 557 if ((t v1->tv_sec == tv2->tv_sec) && (tv1->tv_usec >= tv2->tv_usec))588 if ((ts1->tv_sec == ts2->tv_sec) && (ts1->tv_nsec >= ts2->tv_nsec)) 558 589 return true; 559 590 … … 561 592 } 562 593 563 /** Get time of day. 564 * 565 * The time variables are memory mapped (read-only) from kernel which 566 * updates them periodically. 567 * 568 * As it is impossible to read 2 values atomically, we use a trick: 569 * First we read the seconds, then we read the microseconds, then we 570 * read the seconds again. If a second elapsed in the meantime, set 571 * the microseconds to zero. 572 * 573 * This assures that the values returned by two subsequent calls 574 * to gettimeofday() are monotonous. 575 * 576 */ 577 void gettimeofday(struct timeval *tv, struct timezone *tz) 578 { 579 if (tz) { 580 tz->tz_minuteswest = 0; 581 tz->tz_dsttime = DST_NONE; 582 } 583 594 /** Get real time from a RTC service. 595 * 596 * @param[out] ts Timespec to hold time read from the RTC service (if 597 * available). If no such service exists, the returned time 598 * corresponds to system uptime. 599 */ 600 void getrealtime(struct timespec *ts) 601 { 584 602 if (clock_conn == NULL) { 585 603 category_id_t cat_id; … … 620 638 goto fallback; 621 639 622 t v->tv_usec = time.tm_usec;623 t v->tv_sec = mktime(&time);640 ts->tv_nsec = time.tm_nsec; 641 ts->tv_sec = mktime(&time); 624 642 625 643 return; 626 644 627 645 fallback: 628 getuptime(tv); 629 } 630 631 void getuptime(struct timeval *tv) 646 getuptime(ts); 647 } 648 649 /** Get system uptime. 650 * 651 * @param[out] ts Timespec to hold time current uptime. 652 * 653 * The time variables are memory mapped (read-only) from kernel which 654 * updates them periodically. 655 * 656 * As it is impossible to read 2 values atomically, we use a trick: 657 * First we read the seconds, then we read the microseconds, then we 658 * read the seconds again. If a second elapsed in the meantime, set 659 * the microseconds to zero. 660 * 661 * This assures that the values returned by two subsequent calls 662 * to getuptime() are monotonous. 663 * 664 */ 665 void getuptime(struct timespec *ts) 632 666 { 633 667 if (ktime == NULL) { … … 654 688 655 689 read_barrier(); 656 t v->tv_usec = ktime->useconds;690 ts->tv_nsec = USEC2NSEC(ktime->useconds); 657 691 658 692 read_barrier(); … … 660 694 661 695 if (s1 != s2) { 662 t v->tv_sec = max(s1, s2);663 t v->tv_usec = 0;696 ts->tv_sec = max(s1, s2); 697 ts->tv_nsec = 0; 664 698 } else 665 t v->tv_sec = s1;699 ts->tv_sec = s1; 666 700 667 701 return; 668 702 669 703 fallback: 670 t v->tv_sec = 0;671 t v->tv_usec = 0;704 ts->tv_sec = 0; 705 ts->tv_nsec = 0; 672 706 } 673 707 674 708 time_t time(time_t *tloc) 675 709 { 676 struct time val tv;677 get timeofday(&tv, NULL);710 struct timespec ts; 711 getrealtime(&ts); 678 712 679 713 if (tloc) 680 *tloc = t v.tv_sec;681 682 return t v.tv_sec;683 } 684 685 void udelay( useconds_t time)714 *tloc = ts.tv_sec; 715 716 return ts.tv_sec; 717 } 718 719 void udelay(sysarg_t time) 686 720 { 687 721 (void) __SYSCALL1(SYS_THREAD_UDELAY, (sysarg_t) time); … … 884 918 break; 885 919 case 's': 886 APPEND("%l d", secs_since_epoch(tm));920 APPEND("%lld", secs_since_epoch(tm)); 887 921 break; 888 922 case 'S': … … 961 995 962 996 /* Set result to epoch. */ 963 result->tm_ usec = 0;997 result->tm_nsec = 0; 964 998 result->tm_sec = 0; 965 999 result->tm_min = 0; … … 1038 1072 * 1039 1073 */ 1040 errno_t time_t v2tm(const struct timeval *tv, struct tm *restrict result)1074 errno_t time_ts2tm(const struct timespec *ts, struct tm *restrict result) 1041 1075 { 1042 1076 // TODO: Deal with timezones. … … 1044 1078 1045 1079 /* Set result to epoch. */ 1046 result->tm_ usec = 0;1080 result->tm_nsec = 0; 1047 1081 result->tm_sec = 0; 1048 1082 result->tm_min = 0; … … 1052 1086 result->tm_year = 70; /* 1970 */ 1053 1087 1054 if (normalize_tm_t v(result, tv) == -1)1088 if (normalize_tm_ts(result, ts) == -1) 1055 1089 return EOVERFLOW; 1056 1090 … … 1070 1104 errno_t time_local2tm(const time_t time, struct tm *restrict result) 1071 1105 { 1072 struct time val tv= {1106 struct timespec ts = { 1073 1107 .tv_sec = time, 1074 .tv_ usec = 01108 .tv_nsec = 0 1075 1109 }; 1076 1110 1077 return time_t v2tm(&tv, result);1111 return time_ts2tm(&ts, result); 1078 1112 } 1079 1113
Note:
See TracChangeset
for help on using the changeset viewer.