2020-01-18 09:38:21 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
|
|
* list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2019-03-27 01:31:53 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2019-05-28 13:48:06 +02:00
|
|
|
#include <sys/types.h>
|
2020-06-21 13:42:21 -04:00
|
|
|
#include <time.h>
|
2019-03-27 01:31:53 +01:00
|
|
|
|
|
|
|
__BEGIN_DECLS
|
|
|
|
|
2019-05-28 13:48:06 +02:00
|
|
|
struct timeval {
|
|
|
|
time_t tv_sec;
|
|
|
|
suseconds_t tv_usec;
|
|
|
|
};
|
|
|
|
|
2019-04-21 02:59:20 +02:00
|
|
|
struct timezone {
|
|
|
|
int tz_minuteswest;
|
|
|
|
int tz_dsttime;
|
|
|
|
};
|
|
|
|
|
Kernel+LibC: Add adjtime(2)
Most systems (Linux, OpenBSD) adjust 0.5 ms per second, or 0.5 us per
1 ms tick. That is, the clock is sped up or slowed down by at most
0.05%. This means adjusting the clock by 1 s takes 2000 s, and the
clock an be adjusted by at most 1.8 s per hour.
FreeBSD adjusts 5 ms per second if the remaining time adjustment is
>= 1 s (0.5%) , else it adjusts by 0.5 ms as well. This allows adjusting
by (almost) 18 s per hour.
Since Serenity OS can lose more than 22 s per hour (#3429), this
picks an adjustment rate up to 1% for now. This allows us to
adjust up to 36s per hour, which should be sufficient to adjust
the clock fast enough to keep up with how much time the clock
currently loses. Once we have a fancier NTP implementation that can
adjust tick rate in addition to offset, we can think about reducing
this.
adjtime is a bit old-school and most current POSIX-y OSs instead
implement adjtimex/ntp_adjtime, but a) we have to start somewhere
b) ntp_adjtime() is a fairly gnarly API. OpenBSD's adjfreq looks
like it might provide similar functionality with a nicer API. But
before worrying about all this, it's probably a good idea to get
to a place where the kernel APIs are (barely) good enough so that
we can write an ntp service, and once we have that we should write
a way to automatically evaluate how well it keeps the time adjusted,
and only then should we add improvements ot the adjustment mechanism.
2020-11-05 16:00:51 -05:00
|
|
|
int adjtime(const struct timeval* delta, struct timeval* old_delta);
|
2019-05-28 11:53:16 +02:00
|
|
|
int gettimeofday(struct timeval* __restrict__, void* __restrict__) __attribute__((nonnull(1)));
|
2020-09-06 09:59:19 -04:00
|
|
|
int settimeofday(struct timeval* __restrict__, void* __restrict__) __attribute__((nonnull(1)));
|
2019-03-27 01:31:53 +01:00
|
|
|
|
2020-06-21 13:42:21 -04:00
|
|
|
static inline void timeradd(const struct timeval* a, const struct timeval* b, struct timeval* out)
|
|
|
|
{
|
|
|
|
out->tv_sec = a->tv_sec + b->tv_sec;
|
|
|
|
out->tv_usec = a->tv_usec + b->tv_usec;
|
|
|
|
if (out->tv_usec >= 1000 * 1000) {
|
|
|
|
out->tv_sec++;
|
|
|
|
out->tv_usec -= 1000 * 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void timersub(const struct timeval* a, const struct timeval* b, struct timeval* out)
|
|
|
|
{
|
|
|
|
out->tv_sec = a->tv_sec - b->tv_sec;
|
|
|
|
out->tv_usec = a->tv_usec - b->tv_usec;
|
|
|
|
if (out->tv_usec < 0) {
|
|
|
|
out->tv_sec--;
|
|
|
|
out->tv_usec += 1000 * 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void timerclear(struct timeval* out)
|
|
|
|
{
|
|
|
|
out->tv_sec = out->tv_usec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int timerisset(const struct timeval* tv)
|
|
|
|
{
|
|
|
|
return tv->tv_sec || tv->tv_usec;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define timeradd timeradd
|
|
|
|
#define timersub timersub
|
|
|
|
#define timerclear timerclear
|
|
|
|
#define timerisset timerisset
|
|
|
|
#define timercmp(tvp, uvp, cmp) \
|
|
|
|
(((tvp)->tv_sec == (uvp)->tv_sec) ? ((tvp)->tv_usec cmp(uvp)->tv_usec) : ((tvp)->tv_sec cmp(uvp)->tv_sec))
|
|
|
|
|
|
|
|
static inline void timespecadd(const struct timespec* a, const struct timespec* b, struct timespec* out)
|
|
|
|
{
|
|
|
|
out->tv_sec = a->tv_sec + b->tv_sec;
|
|
|
|
out->tv_nsec = a->tv_nsec + b->tv_nsec;
|
|
|
|
if (out->tv_nsec >= 1000 * 1000 * 1000) {
|
|
|
|
out->tv_sec++;
|
|
|
|
out->tv_nsec -= 1000 * 1000 * 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void timespecsub(const struct timespec* a, const struct timespec* b, struct timespec* out)
|
|
|
|
{
|
|
|
|
out->tv_sec = a->tv_sec - b->tv_sec;
|
|
|
|
out->tv_nsec = a->tv_nsec - b->tv_nsec;
|
|
|
|
if (out->tv_nsec < 0) {
|
|
|
|
out->tv_sec--;
|
|
|
|
out->tv_nsec += 1000 * 1000 * 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void timespecclear(struct timespec* out)
|
|
|
|
{
|
|
|
|
out->tv_sec = out->tv_nsec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int timespecisset(const struct timespec* ts)
|
|
|
|
{
|
|
|
|
return ts->tv_sec || ts->tv_nsec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void TIMEVAL_TO_TIMESPEC(const struct timeval* tv, struct timespec* ts)
|
|
|
|
{
|
|
|
|
ts->tv_sec = tv->tv_sec;
|
|
|
|
ts->tv_nsec = tv->tv_usec * 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void TIMESPEC_TO_TIMEVAL(struct timeval* tv, const struct timespec* ts)
|
|
|
|
{
|
|
|
|
tv->tv_sec = ts->tv_sec;
|
|
|
|
tv->tv_usec = ts->tv_nsec / 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define timespecadd timespecadd
|
|
|
|
#define timespecsub timespecsub
|
|
|
|
#define timespecclear timespecclear
|
|
|
|
#define timespecisset timespecisset
|
|
|
|
#define timespeccmp(ts, us, cmp) \
|
|
|
|
(((ts)->tv_sec == (us)->tv_sec) ? ((ts)->vf_nsec cmp(us)->tv_nsec) : ((ts)->tv_sec cmp(us)->tv_sec))
|
|
|
|
|
2019-03-27 01:31:53 +01:00
|
|
|
__END_DECLS
|