200 lines
4.2 KiB
C
200 lines
4.2 KiB
C
|
/*
|
||
|
* udelay.h -- udelay and other time related functions.
|
||
|
*
|
||
|
* Copyright (C) 2006, 2007 Red Hat, Inc. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 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 General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* Author(s): Peter Jones <pjones@redhat.com>
|
||
|
*/
|
||
|
|
||
|
#ifndef UDELAY_H
|
||
|
#define UDELAY_H 1
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <time.h>
|
||
|
|
||
|
#define USECS_PER_SEC 1000000LL
|
||
|
#define NSECS_PER_USEC 1000LL
|
||
|
#define NSECS_PER_SEC (NSECS_PER_USEC * USECS_PER_SEC)
|
||
|
|
||
|
static inline void
|
||
|
nsectospec(long long nsecs, struct timespec *ts)
|
||
|
{
|
||
|
if (nsecs < 0) {
|
||
|
ts->tv_sec = -1;
|
||
|
ts->tv_nsec = -1;
|
||
|
return;
|
||
|
}
|
||
|
ts->tv_sec = nsecs / NSECS_PER_SEC;
|
||
|
ts->tv_nsec = (nsecs % NSECS_PER_SEC);
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
usectospec(long long usecs, struct timespec *ts)
|
||
|
{
|
||
|
if (usecs > 0 && LLONG_MAX / NSECS_PER_USEC > usecs)
|
||
|
usecs *= NSECS_PER_USEC;
|
||
|
|
||
|
nsectospec(usecs, ts);
|
||
|
}
|
||
|
|
||
|
static inline int
|
||
|
speczero(struct timespec *ts)
|
||
|
{
|
||
|
return (ts->tv_sec == 0 && ts->tv_nsec == 0);
|
||
|
}
|
||
|
|
||
|
static inline int
|
||
|
specinf(struct timespec *ts)
|
||
|
{
|
||
|
return (ts->tv_sec < 0 || ts->tv_nsec < 0);
|
||
|
}
|
||
|
|
||
|
static inline long long
|
||
|
spectonsec(struct timespec *ts)
|
||
|
{
|
||
|
long long nsecs = 0;
|
||
|
if (specinf(ts))
|
||
|
return -1;
|
||
|
|
||
|
nsecs = ts->tv_sec * NSECS_PER_SEC;
|
||
|
nsecs += ts->tv_nsec;
|
||
|
return nsecs;
|
||
|
}
|
||
|
|
||
|
static inline long long
|
||
|
spectousec(struct timespec *ts)
|
||
|
{
|
||
|
long long usecs = spectonsec(ts);
|
||
|
|
||
|
return usecs < 0 ? usecs : usecs / NSECS_PER_USEC;
|
||
|
}
|
||
|
|
||
|
static inline int
|
||
|
gettimespecofday(struct timespec *ts)
|
||
|
{
|
||
|
struct timeval tv = {0, 0};
|
||
|
int rc;
|
||
|
|
||
|
rc = gettimeofday(&tv, NULL);
|
||
|
if (rc >= 0) {
|
||
|
ts->tv_sec = tv.tv_sec;
|
||
|
ts->tv_nsec = tv.tv_usec * NSECS_PER_USEC;
|
||
|
}
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/* minuend minus subtrahend equals difference */
|
||
|
static inline void
|
||
|
tssub(struct timespec *minuend, struct timespec *subtrahend,
|
||
|
struct timespec *difference)
|
||
|
{
|
||
|
long long m, s, d;
|
||
|
|
||
|
m = spectonsec(minuend);
|
||
|
s = spectonsec(subtrahend);
|
||
|
|
||
|
if (s < 0) {
|
||
|
d = 0;
|
||
|
} else if (m < 0) {
|
||
|
d = -1;
|
||
|
} else {
|
||
|
m -= s;
|
||
|
d = m < 0 ? 0 : m;
|
||
|
}
|
||
|
|
||
|
nsectospec(d, difference);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
tsadd(struct timespec *augend, struct timespec *addend, struct timespec *sum)
|
||
|
{
|
||
|
long long aug, add;
|
||
|
|
||
|
aug = spectonsec(augend);
|
||
|
add = spectonsec(addend);
|
||
|
|
||
|
// printf("aug: %Ld add: %Ld\n", aug, add);
|
||
|
|
||
|
if (aug < 0 || add < 0)
|
||
|
nsectospec(-1, sum);
|
||
|
else if (LLONG_MAX - MAX(add,aug) < MAX(add,aug))
|
||
|
nsectospec(LLONG_MAX, sum);
|
||
|
else
|
||
|
nsectospec(aug+add, sum);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#define tsGT(x,y) (tscmp((x), (y)) < 0)
|
||
|
#define tsGE(x,y) (tscmp((x), (y)) <= 0)
|
||
|
#define tsET(x,y) (tscmp((x), (y)) == 0)
|
||
|
#define tsNE(x,y) (tscmp((x), (y)) != 0)
|
||
|
#define tsLE(x,y) (tscmp((x), (y)) >= 0)
|
||
|
#define tsLT(x,y) (tscmp((x), (y)) > 0)
|
||
|
|
||
|
static inline int
|
||
|
tscmp(struct timespec *a, struct timespec *b)
|
||
|
{
|
||
|
long long m, s;
|
||
|
long long rc;
|
||
|
|
||
|
m = spectonsec(a);
|
||
|
s = spectonsec(b);
|
||
|
|
||
|
if (s < 0) {
|
||
|
rc = 1;
|
||
|
if (m < 0)
|
||
|
rc = 0;
|
||
|
} else if (m < 0) {
|
||
|
rc = -1;
|
||
|
} else {
|
||
|
rc = MIN(MAX(s-m, -1), 1);
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
udelayspec(struct timespec total)
|
||
|
{
|
||
|
struct timespec rem;
|
||
|
if (specinf(&total)) {
|
||
|
do {
|
||
|
usectospec(LLONG_MAX, &rem);
|
||
|
} while (nanosleep(&rem, &rem) == -1 && errno == EINTR);
|
||
|
} else {
|
||
|
rem = total;
|
||
|
while (nanosleep(&rem, &rem) == -1 && errno == EINTR)
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
udelay(long long usecs)
|
||
|
{
|
||
|
struct timespec rem = {0,0};
|
||
|
|
||
|
usectospec(usecs, &rem);
|
||
|
udelayspec(rem);
|
||
|
}
|
||
|
|
||
|
#endif /* UDELAY_H */
|
||
|
/*
|
||
|
* vim:ts=8:sw=4:sts=4:et
|
||
|
*/
|