Ignore:
File:
1 edited

Legend:

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

    r3c45353 r05882233  
    3535 */
    3636
     37#include <sys/time.h>
    3738#include <time.h>
    3839#include <stdbool.h>
     
    5051#include <loc.h>
    5152#include <device/clock_dev.h>
    52 #include <stats.h>
    5353
    5454#define ASCTIME_BUF_LEN  26
     
    5757#define MINS_PER_HOUR  60
    5858#define SECS_PER_MIN   60
    59 #define NSECS_PER_SEC  1000000000ll
     59#define USECS_PER_SEC  1000000
    6060#define MINS_PER_DAY   (MINS_PER_HOUR * HOURS_PER_DAY)
    6161#define SECS_PER_HOUR  (SECS_PER_MIN * MINS_PER_HOUR)
     
    7171static async_sess_t *clock_conn = NULL;
    7272
    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 
    10573/** Check whether the year is a leap year.
    10674 *
     
    284252 *
    285253 * @param tm Broken-down time to normalize.
    286  * @param ts Timespec to add.
     254 * @param tv Timeval to add.
    287255 *
    288256 * @return 0 on success, -1 on overflow
    289257 *
    290258 */
    291 static int normalize_tm_ts(struct tm *tm, const struct timespec *ts)
     259static int normalize_tm_tv(struct tm *tm, const struct timeval *tv)
    292260{
    293261        // TODO: DST correction
    294262
    295263        /* Set initial values. */
    296         time_t nsec = tm->tm_nsec + ts->tv_nsec;
    297         time_t sec = tm->tm_sec + ts->tv_sec;
     264        time_t usec = tm->tm_usec + tv->tv_usec;
     265        time_t sec = tm->tm_sec + tv->tv_sec;
    298266        time_t min = tm->tm_min;
    299267        time_t hour = tm->tm_hour;
     
    303271
    304272        /* Adjust time. */
    305         sec += floor_div(nsec, NSECS_PER_SEC);
    306         nsec = floor_mod(nsec, NSECS_PER_SEC);
     273        sec += floor_div(usec, USECS_PER_SEC);
     274        usec = floor_mod(usec, USECS_PER_SEC);
    307275        min += floor_div(sec, SECS_PER_MIN);
    308276        sec = floor_mod(sec, SECS_PER_MIN);
     
    353321
    354322        /* And put the values back to the struct. */
    355         tm->tm_nsec = (int) nsec;
     323        tm->tm_usec = (int) usec;
    356324        tm->tm_sec = (int) sec;
    357325        tm->tm_min = (int) min;
     
    372340static int normalize_tm_time(struct tm *tm, time_t time)
    373341{
    374         struct timespec ts = {
     342        struct timeval tv = {
    375343                .tv_sec = time,
    376                 .tv_nsec = 0
     344                .tv_usec = 0
    377345        };
    378346
    379         return normalize_tm_ts(tm, &ts);
     347        return normalize_tm_tv(tm, &tv);
    380348}
    381349
     
    488456}
    489457
    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)
     458static 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 */
     476void 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 */
     488void 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 */
     504suseconds_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 */
     516void 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 */
     532int tv_gt(const struct timeval *tv1, const struct timeval *tv2)
     533{
     534        if (tv1->tv_sec > tv2->tv_sec)
    566535                return true;
    567536
    568         if ((ts1->tv_sec == ts2->tv_sec) && (ts1->tv_nsec > ts2->tv_nsec))
     537        if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec))
    569538                return true;
    570539
     
    572541}
    573542
    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)
     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 */
     552int tv_gteq(const struct timeval *tv1, const struct timeval *tv2)
     553{
     554        if (tv1->tv_sec > tv2->tv_sec)
    586555                return true;
    587556
    588         if ((ts1->tv_sec == ts2->tv_sec) && (ts1->tv_nsec >= ts2->tv_nsec))
     557        if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec >= tv2->tv_usec))
    589558                return true;
    590559
     
    592561}
    593562
    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 {
     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 */
     577void gettimeofday(struct timeval *tv, struct timezone *tz)
     578{
     579        if (tz) {
     580                tz->tz_minuteswest = 0;
     581                tz->tz_dsttime = DST_NONE;
     582        }
     583
    602584        if (clock_conn == NULL) {
    603585                category_id_t cat_id;
     
    638620                goto fallback;
    639621
    640         ts->tv_nsec = time.tm_nsec;
    641         ts->tv_sec = mktime(&time);
     622        tv->tv_usec = time.tm_usec;
     623        tv->tv_sec = mktime(&time);
    642624
    643625        return;
    644626
    645627fallback:
    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)
     628        getuptime(tv);
     629}
     630
     631void getuptime(struct timeval *tv)
    666632{
    667633        if (ktime == NULL) {
     
    688654
    689655        read_barrier();
    690         ts->tv_nsec = USEC2NSEC(ktime->useconds);
     656        tv->tv_usec = ktime->useconds;
    691657
    692658        read_barrier();
     
    694660
    695661        if (s1 != s2) {
    696                 ts->tv_sec = max(s1, s2);
    697                 ts->tv_nsec = 0;
     662                tv->tv_sec = max(s1, s2);
     663                tv->tv_usec = 0;
    698664        } else
    699                 ts->tv_sec = s1;
     665                tv->tv_sec = s1;
    700666
    701667        return;
    702668
    703669fallback:
    704         ts->tv_sec = 0;
    705         ts->tv_nsec = 0;
     670        tv->tv_sec = 0;
     671        tv->tv_usec = 0;
    706672}
    707673
    708674time_t time(time_t *tloc)
    709675{
    710         struct timespec ts;
    711         getrealtime(&ts);
     676        struct timeval tv;
     677        gettimeofday(&tv, NULL);
    712678
    713679        if (tloc)
    714                 *tloc = ts.tv_sec;
    715 
    716         return ts.tv_sec;
    717 }
    718 
    719 void udelay(sysarg_t time)
     680                *tloc = tv.tv_sec;
     681
     682        return tv.tv_sec;
     683}
     684
     685void udelay(useconds_t time)
    720686{
    721687        (void) __SYSCALL1(SYS_THREAD_UDELAY, (sysarg_t) time);
     
    918884                        break;
    919885                case 's':
    920                         APPEND("%lld", secs_since_epoch(tm));
     886                        APPEND("%ld", secs_since_epoch(tm));
    921887                        break;
    922888                case 'S':
     
    995961
    996962        /* Set result to epoch. */
    997         result->tm_nsec = 0;
     963        result->tm_usec = 0;
    998964        result->tm_sec = 0;
    999965        result->tm_min = 0;
     
    10721038 *
    10731039 */
    1074 errno_t time_ts2tm(const struct timespec *ts, struct tm *restrict result)
     1040errno_t time_tv2tm(const struct timeval *tv, struct tm *restrict result)
    10751041{
    10761042        // TODO: Deal with timezones.
     
    10781044
    10791045        /* Set result to epoch. */
    1080         result->tm_nsec = 0;
     1046        result->tm_usec = 0;
    10811047        result->tm_sec = 0;
    10821048        result->tm_min = 0;
     
    10861052        result->tm_year = 70; /* 1970 */
    10871053
    1088         if (normalize_tm_ts(result, ts) == -1)
     1054        if (normalize_tm_tv(result, tv) == -1)
    10891055                return EOVERFLOW;
    10901056
     
    11041070errno_t time_local2tm(const time_t time, struct tm *restrict result)
    11051071{
    1106         struct timespec ts = {
     1072        struct timeval tv = {
    11071073                .tv_sec = time,
    1108                 .tv_nsec = 0
     1074                .tv_usec = 0
    11091075        };
    11101076
    1111         return time_ts2tm(&ts, result);
     1077        return time_tv2tm(&tv, result);
    11121078}
    11131079
Note: See TracChangeset for help on using the changeset viewer.