-
Notifications
You must be signed in to change notification settings - Fork 85
/
timing.c
174 lines (154 loc) · 4.51 KB
/
timing.c
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
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2019 Martin Ling <martin-libserialport@earth.li>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "libserialport_internal.h"
SP_PRIV void time_get(struct time *time)
{
#ifdef _WIN32
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
time->ticks = count.QuadPart;
#elif defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
clock_gettime(CLOCK_REALTIME, &ts);
time->tv.tv_sec = ts.tv_sec;
time->tv.tv_usec = ts.tv_nsec / 1000;
#elif defined(__APPLE__)
mach_timebase_info_data_t info;
mach_timebase_info(&info);
uint64_t ticks = mach_absolute_time();
uint64_t ns = (ticks * info.numer) / info.denom;
time->tv.tv_sec = ns / 1000000000;
time->tv.tv_usec = (ns % 1000000000) / 1000;
#else
gettimeofday(&time->tv, NULL);
#endif
}
SP_PRIV void time_set_ms(struct time *time, unsigned int ms)
{
#ifdef _WIN32
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
time->ticks = ms * (frequency.QuadPart / 1000);
#else
time->tv.tv_sec = ms / 1000;
time->tv.tv_usec = (ms % 1000) * 1000;
#endif
}
SP_PRIV void time_add(const struct time *a,
const struct time *b, struct time *result)
{
#ifdef _WIN32
result->ticks = a->ticks + b->ticks;
#else
timeradd(&a->tv, &b->tv, &result->tv);
#endif
}
SP_PRIV void time_sub(const struct time *a,
const struct time *b, struct time *result)
{
#ifdef _WIN32
result->ticks = a->ticks - b->ticks;
#else
timersub(&a->tv, &b->tv, &result->tv);
#endif
}
SP_PRIV bool time_greater(const struct time *a, const struct time *b)
{
#ifdef _WIN32
return (a->ticks > b->ticks);
#else
return timercmp(&a->tv, &b->tv, >);
#endif
}
SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv)
{
#ifdef _WIN32
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
tv->tv_sec = (long) (time->ticks / frequency.QuadPart);
tv->tv_usec = (long) ((time->ticks % frequency.QuadPart) /
(frequency.QuadPart / 1000000));
#else
*tv = time->tv;
#endif
}
SP_PRIV unsigned int time_as_ms(const struct time *time)
{
#ifdef _WIN32
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return (unsigned int) (time->ticks / (frequency.QuadPart / 1000));
#else
return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
#endif
}
SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms)
{
timeout->ms = timeout_ms;
/* Get time at start of operation. */
time_get(&timeout->start);
/* Define duration of timeout. */
time_set_ms(&timeout->delta, timeout_ms);
/* Calculate time at which we should give up. */
time_add(&timeout->start, &timeout->delta, &timeout->end);
/* Disable limit unless timeout_limit() called. */
timeout->limit_ms = 0;
/* First blocking call has not yet been made. */
timeout->calls_started = false;
}
SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms)
{
timeout->limit_ms = limit_ms;
timeout->overflow = (timeout->ms > timeout->limit_ms);
time_set_ms(&timeout->delta_max, timeout->limit_ms);
}
SP_PRIV bool timeout_check(struct timeout *timeout)
{
if (!timeout->calls_started)
return false;
if (timeout->ms == 0)
return false;
time_get(&timeout->now);
time_sub(&timeout->end, &timeout->now, &timeout->delta);
if (timeout->limit_ms)
if ((timeout->overflow = time_greater(&timeout->delta, &timeout->delta_max)))
timeout->delta = timeout->delta_max;
return time_greater(&timeout->now, &timeout->end);
}
SP_PRIV void timeout_update(struct timeout *timeout)
{
timeout->calls_started = true;
}
#ifndef _WIN32
SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout)
{
if (timeout->ms == 0)
return NULL;
time_as_timeval(&timeout->delta, &timeout->delta_tv);
return &timeout->delta_tv;
}
#endif
SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout)
{
if (timeout->limit_ms && timeout->overflow)
return timeout->limit_ms;
else
return time_as_ms(&timeout->delta);
}