summaryrefslogtreecommitdiff
path: root/device_mapper/libdm-timestamp.c
blob: 236cf1a1c9136dcb85f7881e77922b52c6ed8955 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
 * Copyright (C) 2006 Rackable Systems All rights reserved.
 * Copyright (C) 2015 Red Hat, Inc. All rights reserved.
 *
 * This file is part of the device-mapper userspace tools.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License v.2.1.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/*
 * Abstract out the time methods used so they can be adjusted later -
 * the results of these routines should stay in-core.  
 */

#include "base/memory/zalloc.h"
#include "misc/dmlib.h"

#include <stdlib.h>

#define NSEC_PER_USEC	UINT64_C(1000)
#define NSEC_PER_MSEC	UINT64_C(1000000)
#define NSEC_PER_SEC	UINT64_C(1000000000)

/*
 * The realtime section uses clock_gettime with the CLOCK_MONOTONIC
 * parameter to prevent issues with time warps
 * This implementation requires librt.
 */
#ifdef HAVE_REALTIME

#include <time.h>

struct dm_timestamp {
	struct timespec t;
};

static uint64_t _timestamp_to_uint64(struct dm_timestamp *ts)
{
	uint64_t stamp = 0;

	stamp += (uint64_t) ts->t.tv_sec * NSEC_PER_SEC;
	stamp += (uint64_t) ts->t.tv_nsec;

	return stamp;
}

struct dm_timestamp *dm_timestamp_alloc(void)
{
	struct dm_timestamp *ts = NULL;

	if (!(ts = zalloc(sizeof(*ts))))
		stack;

	return ts;
}

int dm_timestamp_get(struct dm_timestamp *ts)
{
	if (!ts)
		return 0;

	if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
		log_sys_error("clock_gettime", "get_timestamp");
		ts->t.tv_sec = 0;
		ts->t.tv_nsec = 0;
		return 0;
	}

	return 1;
}

#else /* ! HAVE_REALTIME */

/*
 * The !realtime section just uses gettimeofday and is therefore subject
 * to ntp-type time warps - not sure if should allow that.
 */

#include <sys/time.h>

struct dm_timestamp {
	struct timeval t;
};

static uint64_t _timestamp_to_uint64(struct dm_timestamp *ts)
{
	uint64_t stamp = 0;

	stamp += ts->t.tv_sec * NSEC_PER_SEC;
	stamp += ts->t.tv_usec * NSEC_PER_USEC;

	return stamp;
}

struct dm_timestamp *dm_timestamp_alloc(void)
{
	struct dm_timestamp *ts;

	if (!(ts = malloc(sizeof(*ts))))
		stack;

	return ts;
}

int dm_timestamp_get(struct dm_timestamp *ts)
{
	if (!ts)
		return 0;

	if (gettimeofday(&ts->t, NULL)) {
		log_sys_error("gettimeofday", "get_timestamp");
		ts->t.tv_sec = 0;
		ts->t.tv_usec = 0;
		return 0;
	}

	return 1;
}

#endif /* HAVE_REALTIME */

/*
 * Compare two timestamps.
 *
 * Return: -1 if ts1 is less than ts2
 *          0 if ts1 is equal to ts2
 *          1 if ts1 is greater than ts2
 */
int dm_timestamp_compare(struct dm_timestamp *ts1, struct dm_timestamp *ts2)
{
	uint64_t t1, t2;

	t1 = _timestamp_to_uint64(ts1);
	t2 = _timestamp_to_uint64(ts2);

	if (t2 < t1)
		return 1;

	if (t1 < t2)
		return -1;

	return 0;
}

/*
 * Return the absolute difference in nanoseconds between
 * the dm_timestamp objects ts1 and ts2.
 *
 * Callers that need to know whether ts1 is before, equal to, or after ts2
 * in addition to the magnitude should use dm_timestamp_compare.
 */
uint64_t dm_timestamp_delta(struct dm_timestamp *ts1, struct dm_timestamp *ts2)
{
	uint64_t t1, t2;

	t1 = _timestamp_to_uint64(ts1);
	t2 = _timestamp_to_uint64(ts2);

	if (t1 > t2)
		return t1 - t2;

	return t2 - t1;
}

void dm_timestamp_copy(struct dm_timestamp *ts_new, struct dm_timestamp *ts_old)
{
	*ts_new = *ts_old;
}

void dm_timestamp_destroy(struct dm_timestamp *ts)
{
	free(ts);
}