]> sigrok.org Git - libserialport.git/blame - timing.c
windows: Use a fixed worst-case WRITEFILE_MAX_SIZE.
[libserialport.git] / timing.c
CommitLineData
39acdc47
ML
1/*
2 * This file is part of the libserialport project.
3 *
4 * Copyright (C) 2019 Martin Ling <martin-libserialport@earth.li>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <config.h>
21#include "libserialport.h"
22#include "libserialport_internal.h"
23
24SP_PRIV void time_get(struct time *time)
25{
26#ifdef _WIN32
27 LARGE_INTEGER count;
28 QueryPerformanceCounter(&count);
29 time->ticks = count.QuadPart;
30#elif defined(HAVE_CLOCK_GETTIME)
31 struct timespec ts;
32 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
33 clock_gettime(CLOCK_REALTIME, &ts);
34 time->tv.tv_sec = ts.tv_sec;
35 time->tv.tv_usec = ts.tv_nsec / 1000;
36#elif defined(__APPLE__)
37 mach_timebase_info_data_t info;
38 mach_timebase_info(&info);
39 uint64_t ticks = mach_absolute_time();
40 uint64_t ns = (ticks * info.numer) / info.denom;
41 time->tv.tv_sec = ns / 1000000000;
42 time->tv.tv_usec = (ns % 1000000000) / 1000;
43#else
44 gettimeofday(&time->tv, NULL);
45#endif
46}
47
48SP_PRIV void time_set_ms(struct time *time, unsigned int ms)
49{
50#ifdef _WIN32
51 LARGE_INTEGER frequency;
52 QueryPerformanceFrequency(&frequency);
53 time->ticks = ms * (frequency.QuadPart / 1000);
54#else
55 time->tv.tv_sec = ms / 1000;
56 time->tv.tv_usec = (ms % 1000) * 1000;
57#endif
58}
59
60SP_PRIV void time_add(const struct time *a,
61 const struct time *b, struct time *result)
62{
63#ifdef _WIN32
64 result->ticks = a->ticks + b->ticks;
65#else
66 timeradd(&a->tv, &b->tv, &result->tv);
67#endif
68}
69
70SP_PRIV void time_sub(const struct time *a,
71 const struct time *b, struct time *result)
72{
73#ifdef _WIN32
74 result->ticks = a->ticks - b->ticks;
75#else
76 timersub(&a->tv, &b->tv, &result->tv);
77#endif
78}
79
80SP_PRIV bool time_greater(const struct time *a, const struct time *b)
81{
82#ifdef _WIN32
83 return (a->ticks > b->ticks);
84#else
85 return timercmp(&a->tv, &b->tv, >);
86#endif
87}
88
89SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv)
90{
91#ifdef _WIN32
92 LARGE_INTEGER frequency;
93 QueryPerformanceFrequency(&frequency);
94 tv->tv_sec = time->ticks / frequency.QuadPart;
95 tv->tv_usec = (time->ticks % frequency.QuadPart) /
96 (frequency.QuadPart / 1000000);
97#else
98 *tv = time->tv;
99#endif
100}
101
102SP_PRIV unsigned int time_as_ms(const struct time *time)
103{
104#ifdef _WIN32
105 LARGE_INTEGER frequency;
106 QueryPerformanceFrequency(&frequency);
107 return time->ticks / (frequency.QuadPart / 1000);
108#else
109 return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
110#endif
111}
112
113SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms)
114{
115 timeout->ms = timeout_ms;
116
117 /* Get time at start of operation. */
118 time_get(&timeout->start);
119 /* Define duration of timeout. */
120 time_set_ms(&timeout->delta, timeout_ms);
121 /* Calculate time at which we should give up. */
122 time_add(&timeout->start, &timeout->delta, &timeout->end);
123 /* Disable limit unless timeout_limit() called. */
124 timeout->limit_ms = 0;
125 /* First blocking call has not yet been made. */
126 timeout->calls_started = false;
127}
128
129SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms)
130{
131 timeout->limit_ms = limit_ms;
132 timeout->overflow = (timeout->ms > timeout->limit_ms);
133 time_set_ms(&timeout->delta_max, timeout->limit_ms);
134}
135
136SP_PRIV bool timeout_check(struct timeout *timeout)
137{
138 if (!timeout->calls_started)
139 return false;
140
141 if (timeout->ms == 0)
142 return false;
143
144 time_get(&timeout->now);
145 time_sub(&timeout->end, &timeout->now, &timeout->delta);
146 if (timeout->limit_ms)
147 if ((timeout->overflow = time_greater(&timeout->delta, &timeout->delta_max)))
148 timeout->delta = timeout->delta_max;
149
150 return time_greater(&timeout->now, &timeout->end);
151}
152
153SP_PRIV void timeout_update(struct timeout *timeout)
154{
155 timeout->calls_started = true;
156}
157
158#ifndef _WIN32
159SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout)
160{
161 if (timeout->ms == 0)
162 return NULL;
163
164 time_as_timeval(&timeout->delta, &timeout->delta_tv);
165
166 return &timeout->delta_tv;
167}
168#endif
169
170SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout)
171{
172 if (timeout->limit_ms && timeout->overflow)
173 return timeout->limit_ms;
174 else
175 return time_as_ms(&timeout->delta);
176}