/* * 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 . * * Author(s): Peter Jones */ #ifndef UDELAY_H #define UDELAY_H 1 #include #include #include #include #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; #if 0 ts->tv_nsec = (tv.tv_usec % NSECS_PER_USEC >= NSECS_PER_USEC / 2) ? tv.tv_usec / NSECS_PER_USEC + 1 : tv.tv_usec / NSECS_PER_USEC; #else ts->tv_nsec = tv.tv_usec / NSECS_PER_USEC; #endif } 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 */