Changeset 205f1add in mainline for uspace/lib/c/generic/time.c


Ignore:
Timestamp:
2018-08-23T21:14:56Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
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)
Message:

Get rid of sys/time.h

This commit moves the POSIX-like time functionality from libc's
sys/time.h to libposix and introduces C99-like or HelenOS-specific
interfaces to libc.

Specifically, use of sys/time.h, struct timeval, suseconds_t and
gettimeofday is replaced by time.h (C99), struct timespec (C99),
usec_t (HelenOS) and getuptime / getrealtime (HelenOS).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/time.c

    re2625b1a r205f1add  
    3535 */
    3636
    37 #include <sys/time.h>
    3837#include <time.h>
    3938#include <stdbool.h>
     
    5756#define MINS_PER_HOUR  60
    5857#define SECS_PER_MIN   60
    59 #define USECS_PER_SEC  1000000
     58#define NSECS_PER_SEC  1000000000ll
    6059#define MINS_PER_DAY   (MINS_PER_HOUR * HOURS_PER_DAY)
    6160#define SECS_PER_HOUR  (SECS_PER_MIN * MINS_PER_HOUR)
     
    252251 *
    253252 * @param tm Broken-down time to normalize.
    254  * @param tv Timeval to add.
     253 * @param ts Timespec to add.
    255254 *
    256255 * @return 0 on success, -1 on overflow
    257256 *
    258257 */
    259 static int normalize_tm_tv(struct tm *tm, const struct timeval *tv)
     258static int normalize_tm_ts(struct tm *tm, const struct timespec *ts)
    260259{
    261260        // TODO: DST correction
    262261
    263262        /* Set initial values. */
    264         time_t usec = tm->tm_usec + tv->tv_usec;
    265         time_t sec = tm->tm_sec + tv->tv_sec;
     263        time_t nsec = tm->tm_nsec + ts->tv_nsec;
     264        time_t sec = tm->tm_sec + ts->tv_sec;
    266265        time_t min = tm->tm_min;
    267266        time_t hour = tm->tm_hour;
     
    271270
    272271        /* 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);
    275274        min += floor_div(sec, SECS_PER_MIN);
    276275        sec = floor_mod(sec, SECS_PER_MIN);
     
    321320
    322321        /* And put the values back to the struct. */
    323         tm->tm_usec = (int) usec;
     322        tm->tm_nsec = (int) nsec;
    324323        tm->tm_sec = (int) sec;
    325324        tm->tm_min = (int) min;
     
    340339static int normalize_tm_time(struct tm *tm, time_t time)
    341340{
    342         struct timeval tv = {
     341        struct timespec ts = {
    343342                .tv_sec = time,
    344                 .tv_usec = 0
     343                .tv_nsec = 0
    345344        };
    346345
    347         return normalize_tm_tv(tm, &tv);
     346        return normalize_tm_ts(tm, &ts);
    348347}
    349348
     
    456455}
    457456
    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)
     457static 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 */
     475void 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 */
     487void 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 */
     502nsec_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 */
     514void 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 */
     530bool ts_gt(const struct timespec *ts1, const struct timespec *ts2)
     531{
     532        if (ts1->tv_sec > ts2->tv_sec)
    535533                return true;
    536534
    537         if ((tv1->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))
    538536                return true;
    539537
     
    541539}
    542540
    543 /** Decide if one timeval is greater than or equal to the other.
    544  *
    545  * @param tv1 First timeval.
    546  * @param tv2 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 (tv1->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 */
     550bool ts_gteq(const struct timespec *ts1, const struct timespec *ts2)
     551{
     552        if (ts1->tv_sec > ts2->tv_sec)
    555553                return true;
    556554
    557         if ((tv1->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))
    558556                return true;
    559557
     
    561559}
    562560
    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 */
     567void getrealtime(struct timespec *ts)
     568{
    584569        if (clock_conn == NULL) {
    585570                category_id_t cat_id;
     
    620605                goto fallback;
    621606
    622         tv->tv_usec = time.tm_usec;
    623         tv->tv_sec = mktime(&time);
     607        ts->tv_nsec = time.tm_nsec;
     608        ts->tv_sec = mktime(&time);
    624609
    625610        return;
    626611
    627612fallback:
    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 */
     632void getuptime(struct timespec *ts)
    632633{
    633634        if (ktime == NULL) {
     
    654655
    655656        read_barrier();
    656         tv->tv_usec = ktime->useconds;
     657        ts->tv_nsec = USEC2NSEC(ktime->useconds);
    657658
    658659        read_barrier();
     
    660661
    661662        if (s1 != s2) {
    662                 tv->tv_sec = max(s1, s2);
    663                 tv->tv_usec = 0;
     663                ts->tv_sec = max(s1, s2);
     664                ts->tv_nsec = 0;
    664665        } else
    665                 tv->tv_sec = s1;
     666                ts->tv_sec = s1;
    666667
    667668        return;
    668669
    669670fallback:
    670         tv->tv_sec = 0;
    671         tv->tv_usec = 0;
     671        ts->tv_sec = 0;
     672        ts->tv_nsec = 0;
    672673}
    673674
    674675time_t time(time_t *tloc)
    675676{
    676         struct timeval tv;
    677         gettimeofday(&tv, NULL);
     677        struct timespec ts;
     678        getrealtime(&ts);
    678679
    679680        if (tloc)
    680                 *tloc = tv.tv_sec;
    681 
    682         return tv.tv_sec;
    683 }
    684 
    685 void udelay(useconds_t time)
     681                *tloc = ts.tv_sec;
     682
     683        return ts.tv_sec;
     684}
     685
     686void udelay(usec_t time)
    686687{
    687688        (void) __SYSCALL1(SYS_THREAD_UDELAY, (sysarg_t) time);
     
    884885                        break;
    885886                case 's':
    886                         APPEND("%ld", secs_since_epoch(tm));
     887                        APPEND("%lld", secs_since_epoch(tm));
    887888                        break;
    888889                case 'S':
     
    961962
    962963        /* Set result to epoch. */
    963         result->tm_usec = 0;
     964        result->tm_nsec = 0;
    964965        result->tm_sec = 0;
    965966        result->tm_min = 0;
     
    10381039 *
    10391040 */
    1040 errno_t time_tv2tm(const struct timeval *tv, struct tm *restrict result)
     1041errno_t time_ts2tm(const struct timespec *ts, struct tm *restrict result)
    10411042{
    10421043        // TODO: Deal with timezones.
     
    10441045
    10451046        /* Set result to epoch. */
    1046         result->tm_usec = 0;
     1047        result->tm_nsec = 0;
    10471048        result->tm_sec = 0;
    10481049        result->tm_min = 0;
     
    10521053        result->tm_year = 70; /* 1970 */
    10531054
    1054         if (normalize_tm_tv(result, tv) == -1)
     1055        if (normalize_tm_ts(result, ts) == -1)
    10551056                return EOVERFLOW;
    10561057
     
    10701071errno_t time_local2tm(const time_t time, struct tm *restrict result)
    10711072{
    1072         struct timeval tv = {
     1073        struct timespec ts = {
    10731074                .tv_sec = time,
    1074                 .tv_usec = 0
     1075                .tv_nsec = 0
    10751076        };
    10761077
    1077         return time_tv2tm(&tv, result);
     1078        return time_ts2tm(&ts, result);
    10781079}
    10791080
Note: See TracChangeset for help on using the changeset viewer.