summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/timespec.c
blob: d0d5005fbb33864846f1fa7771b75dd032103777 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
  Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
  This file is part of GlusterFS.

  This file is licensed to you under your choice of the GNU Lesser
  General Public License, version 3 or any later version (LGPLv3 or
  later), or the GNU General Public License, version 2 (GPLv2), in all
  cases as published by the Free Software Foundation.
*/

#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>

#if defined GF_DARWIN_HOST_OS
#include <mach/mach_time.h>
static mach_timebase_info_data_t gf_timebase;
#endif

#include "glusterfs/logging.h"
#include "glusterfs/timespec.h"
#include "glusterfs/libglusterfs-messages.h"
#include "glusterfs/common-utils.h"

void
timespec_now(struct timespec *ts)
{
#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS ||                  \
    defined GF_BSD_HOST_OS
    if (0 == clock_gettime(CLOCK_MONOTONIC, ts)) {
        /* All good */
        return;
    }

    /* Fall back, but there is hope in gettimeofday() syscall */
    struct timeval tv;
    if (0 == gettimeofday(&tv, NULL)) {
        /* Again, all good */
        TIMEVAL_TO_TIMESPEC(&tv, ts);
        return;
    }

    /* If control hits here, there is surely a problem,
       mainly because, as per man page too, these syscalls
       shouldn't fail. Best way is to ABORT, because it is
       not right */
    GF_ABORT("gettimeofday() failed!!");

#elif defined GF_DARWIN_HOST_OS
    uint64_t time = mach_absolute_time();
    static double scaling = 0.0;

    if (mach_timebase_info(&gf_timebase) != KERN_SUCCESS) {
        gf_timebase.numer = 1;
        gf_timebase.denom = 1;
    }
    if (gf_timebase.denom == 0) {
        gf_timebase.numer = 1;
        gf_timebase.denom = 1;
    }

    scaling = (double)gf_timebase.numer / (double)gf_timebase.denom;
    time *= scaling;

    ts->tv_sec = (time * NANO);
    ts->tv_nsec = (time - (ts->tv_sec * GIGA));

#endif /* Platform verification */
}

void
timespec_now_realtime(struct timespec *ts)
{
#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS ||                  \
    defined GF_BSD_HOST_OS
    if (0 == clock_gettime(CLOCK_REALTIME, ts)) {
        return;
    }
#endif

    /* Fall back to gettimeofday()*/
    struct timeval tv = {
        0,
    };
    if (0 == gettimeofday(&tv, NULL)) {
        TIMEVAL_TO_TIMESPEC(&tv, ts);
        return;
    }

    return;
}

void
timespec_adjust_delta(struct timespec *ts, struct timespec delta)
{
    ts->tv_nsec = ((ts->tv_nsec + delta.tv_nsec) % 1000000000);
    ts->tv_sec += ((ts->tv_nsec + delta.tv_nsec) / 1000000000);
    ts->tv_sec += delta.tv_sec;
}

void
timespec_sub(const struct timespec *begin, const struct timespec *end,
             struct timespec *res)
{
    if (end->tv_nsec < begin->tv_nsec) {
        res->tv_sec = end->tv_sec - begin->tv_sec - 1;
        res->tv_nsec = end->tv_nsec + 1000000000 - begin->tv_nsec;
    } else {
        res->tv_sec = end->tv_sec - begin->tv_sec;
        res->tv_nsec = end->tv_nsec - begin->tv_nsec;
    }
}

int
timespec_cmp(const struct timespec *lhs_ts, const struct timespec *rhs_ts)
{
    if (lhs_ts->tv_sec < rhs_ts->tv_sec) {
        return -1;
    } else if (lhs_ts->tv_sec > rhs_ts->tv_sec) {
        return 1;
    } else if (lhs_ts->tv_nsec < rhs_ts->tv_nsec) {
        return -1;
    } else if (lhs_ts->tv_nsec > rhs_ts->tv_nsec) {
        return 1;
    }

    return 0;
}