Changeset 205f1add in mainline for uspace/lib/c/generic/time.c
- Timestamp:
- 2018-08-23T21:14:56Z (7 years ago)
- Children:
- f33c989e
- Parents:
- e2625b1a
- git-author:
- Jakub Jermar <jakub@…> (2018-08-21 21:58:52)
- git-committer:
- Jakub Jermar <jakub@…> (2018-08-23 21:14:56)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/time.c
re2625b1a r205f1add 35 35 */ 36 36 37 #include <sys/time.h>38 37 #include <time.h> 39 38 #include <stdbool.h> … … 57 56 #define MINS_PER_HOUR 60 58 57 #define SECS_PER_MIN 60 59 #define USECS_PER_SEC 100000058 #define NSECS_PER_SEC 1000000000ll 60 59 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 61 60 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) … … 252 251 * 253 252 * @param tm Broken-down time to normalize. 254 * @param t v Timevalto add.253 * @param ts Timespec to add. 255 254 * 256 255 * @return 0 on success, -1 on overflow 257 256 * 258 257 */ 259 static int normalize_tm_t v(struct tm *tm, const struct timeval *tv)258 static int normalize_tm_ts(struct tm *tm, const struct timespec *ts) 260 259 { 261 260 // TODO: DST correction 262 261 263 262 /* Set initial values. */ 264 time_t usec = tm->tm_usec + tv->tv_usec;265 time_t sec = tm->tm_sec + t v->tv_sec;263 time_t nsec = tm->tm_nsec + ts->tv_nsec; 264 time_t sec = tm->tm_sec + ts->tv_sec; 266 265 time_t min = tm->tm_min; 267 266 time_t hour = tm->tm_hour; … … 271 270 272 271 /* Adjust time. */ 273 sec += floor_div( usec, USECS_PER_SEC);274 usec = floor_mod(usec, USECS_PER_SEC);272 sec += floor_div(nsec, NSECS_PER_SEC); 273 nsec = floor_mod(nsec, NSECS_PER_SEC); 275 274 min += floor_div(sec, SECS_PER_MIN); 276 275 sec = floor_mod(sec, SECS_PER_MIN); … … 321 320 322 321 /* And put the values back to the struct. */ 323 tm->tm_ usec = (int) usec;322 tm->tm_nsec = (int) nsec; 324 323 tm->tm_sec = (int) sec; 325 324 tm->tm_min = (int) min; … … 340 339 static int normalize_tm_time(struct tm *tm, time_t time) 341 340 { 342 struct time val tv= {341 struct timespec ts = { 343 342 .tv_sec = time, 344 .tv_ usec = 0343 .tv_nsec = 0 345 344 }; 346 345 347 return normalize_tm_t v(tm, &tv);346 return normalize_tm_ts(tm, &ts); 348 347 } 349 348 … … 456 455 } 457 456 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) 457 static void ts_normalize(struct timespec *ts) 458 { 459 while (ts->tv_nsec >= NSECS_PER_SEC) { 460 ts->tv_sec++; 461 ts->tv_nsec -= NSECS_PER_SEC; 462 } 463 while (ts->tv_nsec < 0) { 464 ts->tv_sec--; 465 ts->tv_nsec += NSECS_PER_SEC; 466 } 467 } 468 469 /** Add nanoseconds to given timespec. 470 * 471 * @param ts Destination timespec. 472 * @param nsecs Number of nanoseconds to add. 473 * 474 */ 475 void ts_add_diff(struct timespec *ts, nsec_t nsecs) 476 { 477 ts->tv_sec += nsecs / NSECS_PER_SEC; 478 ts->tv_nsec += nsecs % NSECS_PER_SEC; 479 ts_normalize(ts); 480 } 481 482 /** Add two timespecs. 483 * 484 * @param ts1 First timespec. 485 * @param ts2 Second timespec. 486 */ 487 void ts_add(struct timespec *ts1, const struct timespec *ts2) 488 { 489 ts1->tv_sec += ts2->tv_sec; 490 ts1->tv_nsec += ts2->tv_nsec; 491 ts_normalize(ts1); 492 } 493 494 /** Subtract two timespecs. 495 * 496 * @param ts1 First timespec. 497 * @param ts2 Second timespec. 498 * 499 * @return Difference between ts1 and ts2 (ts1 - ts2) in nanoseconds. 500 * 501 */ 502 nsec_t ts_sub_diff(const struct timespec *ts1, const struct timespec *ts2) 503 { 504 return (nsec_t) (ts1->tv_nsec - ts2->tv_nsec) + 505 SEC2NSEC((ts1->tv_sec - ts2->tv_sec)); 506 } 507 508 /** Subtract two timespecs. 509 * 510 * @param ts1 First timespec. 511 * @param ts2 Second timespec. 512 * 513 */ 514 void ts_sub(struct timespec *ts1, const struct timespec *ts2) 515 { 516 ts1->tv_sec -= ts2->tv_sec; 517 ts1->tv_nsec -= ts2->tv_nsec; 518 ts_normalize(ts1); 519 } 520 521 /** Decide if one timespec is greater than the other. 522 * 523 * @param ts1 First timespec. 524 * @param ts2 Second timespec. 525 * 526 * @return True if ts1 is greater than ts2. 527 * @return False otherwise. 528 * 529 */ 530 bool ts_gt(const struct timespec *ts1, const struct timespec *ts2) 531 { 532 if (ts1->tv_sec > ts2->tv_sec) 535 533 return true; 536 534 537 if ((t v1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec))535 if ((ts1->tv_sec == ts2->tv_sec) && (ts1->tv_nsec > ts2->tv_nsec)) 538 536 return true; 539 537 … … 541 539 } 542 540 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)541 /** Decide if one timespec is greater than or equal to the other. 542 * 543 * @param ts1 First timespec. 544 * @param ts2 Second timespec. 545 * 546 * @return True if ts1 is greater than or equal to ts2. 547 * @return False otherwise. 548 * 549 */ 550 bool ts_gteq(const struct timespec *ts1, const struct timespec *ts2) 551 { 552 if (ts1->tv_sec > ts2->tv_sec) 555 553 return true; 556 554 557 if ((t v1->tv_sec == tv2->tv_sec) && (tv1->tv_usec >= tv2->tv_usec))555 if ((ts1->tv_sec == ts2->tv_sec) && (ts1->tv_nsec >= ts2->tv_nsec)) 558 556 return true; 559 557 … … 561 559 } 562 560 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 561 /** Get real time from a RTC service. 562 * 563 * @param[out] ts Timespec to hold time read from the RTC service (if 564 * available). If no such service exists, the returned time 565 * corresponds to system uptime. 566 */ 567 void getrealtime(struct timespec *ts) 568 { 584 569 if (clock_conn == NULL) { 585 570 category_id_t cat_id; … … 620 605 goto fallback; 621 606 622 t v->tv_usec = time.tm_usec;623 t v->tv_sec = mktime(&time);607 ts->tv_nsec = time.tm_nsec; 608 ts->tv_sec = mktime(&time); 624 609 625 610 return; 626 611 627 612 fallback: 628 getuptime(tv); 629 } 630 631 void getuptime(struct timeval *tv) 613 getuptime(ts); 614 } 615 616 /** Get system uptime. 617 * 618 * @param[out] ts Timespec to hold time current uptime. 619 * 620 * The time variables are memory mapped (read-only) from kernel which 621 * updates them periodically. 622 * 623 * As it is impossible to read 2 values atomically, we use a trick: 624 * First we read the seconds, then we read the microseconds, then we 625 * read the seconds again. If a second elapsed in the meantime, set 626 * the microseconds to zero. 627 * 628 * This assures that the values returned by two subsequent calls 629 * to getuptime() are monotonous. 630 * 631 */ 632 void getuptime(struct timespec *ts) 632 633 { 633 634 if (ktime == NULL) { … … 654 655 655 656 read_barrier(); 656 t v->tv_usec = ktime->useconds;657 ts->tv_nsec = USEC2NSEC(ktime->useconds); 657 658 658 659 read_barrier(); … … 660 661 661 662 if (s1 != s2) { 662 t v->tv_sec = max(s1, s2);663 t v->tv_usec = 0;663 ts->tv_sec = max(s1, s2); 664 ts->tv_nsec = 0; 664 665 } else 665 t v->tv_sec = s1;666 ts->tv_sec = s1; 666 667 667 668 return; 668 669 669 670 fallback: 670 t v->tv_sec = 0;671 t v->tv_usec = 0;671 ts->tv_sec = 0; 672 ts->tv_nsec = 0; 672 673 } 673 674 674 675 time_t time(time_t *tloc) 675 676 { 676 struct time val tv;677 get timeofday(&tv, NULL);677 struct timespec ts; 678 getrealtime(&ts); 678 679 679 680 if (tloc) 680 *tloc = t v.tv_sec;681 682 return t v.tv_sec;683 } 684 685 void udelay(usec onds_t time)681 *tloc = ts.tv_sec; 682 683 return ts.tv_sec; 684 } 685 686 void udelay(usec_t time) 686 687 { 687 688 (void) __SYSCALL1(SYS_THREAD_UDELAY, (sysarg_t) time); … … 884 885 break; 885 886 case 's': 886 APPEND("%l d", secs_since_epoch(tm));887 APPEND("%lld", secs_since_epoch(tm)); 887 888 break; 888 889 case 'S': … … 961 962 962 963 /* Set result to epoch. */ 963 result->tm_ usec = 0;964 result->tm_nsec = 0; 964 965 result->tm_sec = 0; 965 966 result->tm_min = 0; … … 1038 1039 * 1039 1040 */ 1040 errno_t time_t v2tm(const struct timeval *tv, struct tm *restrict result)1041 errno_t time_ts2tm(const struct timespec *ts, struct tm *restrict result) 1041 1042 { 1042 1043 // TODO: Deal with timezones. … … 1044 1045 1045 1046 /* Set result to epoch. */ 1046 result->tm_ usec = 0;1047 result->tm_nsec = 0; 1047 1048 result->tm_sec = 0; 1048 1049 result->tm_min = 0; … … 1052 1053 result->tm_year = 70; /* 1970 */ 1053 1054 1054 if (normalize_tm_t v(result, tv) == -1)1055 if (normalize_tm_ts(result, ts) == -1) 1055 1056 return EOVERFLOW; 1056 1057 … … 1070 1071 errno_t time_local2tm(const time_t time, struct tm *restrict result) 1071 1072 { 1072 struct time val tv= {1073 struct timespec ts = { 1073 1074 .tv_sec = time, 1074 .tv_ usec = 01075 .tv_nsec = 0 1075 1076 }; 1076 1077 1077 return time_t v2tm(&tv, result);1078 return time_ts2tm(&ts, result); 1078 1079 } 1079 1080
Note:
See TracChangeset
for help on using the changeset viewer.