From: Alan Cox Date: Fri, 2 Jan 2015 20:39:02 +0000 (+0000) Subject: clock: Fix up all the clock 1 handling X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=954e2423409b7b22d2871eeda6e79aaf6006adbd;p=FUZIX.git clock: Fix up all the clock 1 handling We can't do things simply because clock 1 runs at 10HZ (as from the last kernel fixes). Instead try and avoid divides, and also pull a few cunning tricks for fixed division by ten functions --- diff --git a/Library/libs/Makefile b/Library/libs/Makefile index 57762f2d..28acf62b 100644 --- a/Library/libs/Makefile +++ b/Library/libs/Makefile @@ -12,7 +12,7 @@ SRC_CRT0 = crt0.s OBJ_CRT0 = $(SRC_CRT0:.s=.rel) SRC_ASM = OBJ_ASM = $(SRC_ASM:.s=.rel) -SRC_C = __hz.c abort.c asctime.c assert.c atexit.c +SRC_C = abort.c asctime.c assert.c atexit.c SRC_C += bcmp.c bcopy.c bsearch.c bzero.c calloc.c cfree.c clock.c closedir.c SRC_C += clock_gettime.c clock_getres.c clock_settime.c SRC_C += creat.c crypt.c ctime.c ctype.c difftime.c errno.c error.c execl.c execv.c diff --git a/Library/libs/__hz.c b/Library/libs/__hz.c deleted file mode 100644 index 171f4a2a..00000000 --- a/Library/libs/__hz.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -static int hz; - -int __hz(void) -{ - if (!hz) { - struct _uzisysinfoblk info; - _uname(&info, sizeof(info)); - hz = info.ticks; - } - return hz; -} - - diff --git a/Library/libs/clock_getres.c b/Library/libs/clock_getres.c index c5bc7002..d893807a 100644 --- a/Library/libs/clock_getres.c +++ b/Library/libs/clock_getres.c @@ -4,11 +4,14 @@ int clock_getres(clockid_t clk_id, struct timespec *res) { - res->tv_nsec = 0; - res->tv_sec = 1; switch(clk_id) { case CLOCK_REALTIME: + res->tv_nsec = 0; + res->tv_sec = 1; + return 0; case CLOCK_MONOTONIC: + res->tv_nsec = 100000000UL; + res->tv_sec = 0; return 0; default: errno = EINVAL; diff --git a/Library/libs/clock_gettime.c b/Library/libs/clock_gettime.c index 6b605760..08053bfd 100644 --- a/Library/libs/clock_gettime.c +++ b/Library/libs/clock_gettime.c @@ -2,8 +2,29 @@ #include #include +/* Divide *tp by 10 and also return the remainder */ +/* On processors with real idiv we should probably just use that */ +unsigned long div10quickm(unsigned long *tp) +{ + unsigned long q, r, t; + t = *tp; + q = (t >> 1) + (t >> 2); + q = q + (q >> 4); + q = q + (q >> 8); + q = q + (q >> 16); + q >>= 3; + r = t - (((q << 2) + q) << 1); + t = q + (r >> 9); + *tp = t; + t <<= 1; + t = (t << 2) + t; + return *tp - t; +} + int clock_gettime(clockid_t clk_id, struct timespec *res) { + int r; + unsigned long d; res->tv_nsec = 0; switch(clk_id) { case CLOCK_REALTIME: @@ -11,6 +32,12 @@ int clock_gettime(clockid_t clk_id, struct timespec *res) return 0; case CLOCK_MONOTONIC: _time(&res->tv_sec, 1); + d = res->tv_sec; + /* We know that this wraps at 2^32 ticks which also means we know + it'll fit 32bits */ + r = div10quickm(&d); + res->tv_nsec = 100000UL * r; + res->tv_sec = d; return 0; default: errno = EINVAL; diff --git a/Library/libs/nanosleep.c b/Library/libs/nanosleep.c index c85e599a..daeeb2db 100644 --- a/Library/libs/nanosleep.c +++ b/Library/libs/nanosleep.c @@ -5,38 +5,61 @@ /* Ok so this doesn't score too highly on accuracy but it'll wrap code using the modern API's for long sleeps just fine */ -int clock_nanosleep(clockid_t clock, int flags, const struct timespec *req, struct timespec *rem) +int clock_nanosleep(clockid_t clock, int flags, const struct timespec *reqp, struct timespec *rem) { - time_t tbase; - time_t tend; - uint16_t t = req->tv_sec * 10; - long nsec = req->tv_nsec; + struct timespec tbase, tend, req; + uint16_t t; - if (clock != CLOCK_REALTIME && clock != CLOCK_MONOTONIC) { - errno = EINVAL; + if (clock_gettime(clock, &tbase)) return -1; - } - - /* Will be 0-9 range so avoid costly divides */ - while(nsec > 50000000UL) { - nsec -= 50000000UL; - t++; - } - if (_time(&tbase, clock) == -1) - return -1; + req.tv_sec = reqp->tv_sec; + req.tv_nsec = reqp->tv_nsec; + /* Absolute time means we are handed a time relative to system 0 not + a time relative to 'now' */ if (flags & TIMER_ABSTIME) { - if (tbase < req->tv_sec) - return 0; - t += (tbase - req->tv_sec) * 10; + req.tv_sec -= tbase.tv_sec; + req.tv_nsec -= tbase.tv_nsec; + if (req.tv_nsec < 0) { + req.tv_nsec += 1000000L; + --req.tv_sec; + } + if (req.tv_sec < 0) + return 0; + /* req is now the relative time for all cases */ + } + /* Convert duration into 16bit 10ths of a second */ + t = ((uint16_t)req.tv_sec) * 10; + while(req.tv_nsec > 100000000UL) { + req.tv_nsec -= 100000000UL; + t++; } - if (_pause(t) == 0) + if (t == 0 || _pause(t) == 0) return 0; - _time(&tend, clock); - if (rem) { - rem->tv_sec = tbase + t/10 - tend; - rem->tv_nsec = 0; + /* When did we finish */ + clock_gettime(clock, &tend); + + /* Work out the time left avoiding divisions */ + if (!(flags & TIMER_ABSTIME)) { + tend.tv_sec -= tbase.tv_sec; + tend.tv_nsec -= tbase.tv_nsec; + if (tend.tv_nsec < 0) { + tend.tv_sec--; + tend.tv_nsec += 1000000000UL; + } + if (tend.tv_sec < 0) + return 0; + if (rem) { + rem->tv_sec = tend.tv_sec; + rem->tv_nsec = tend.tv_nsec; + } + } else { + /* In absolute mode rem is req, easy as that */ + if (rem) { + rem->tv_sec = reqp->tv_sec; + rem->tv_nsec = reqp->tv_nsec; + } } return -1; } diff --git a/Library/libs/sleep.c b/Library/libs/sleep.c index 6a94d6f5..4fe35056 100644 --- a/Library/libs/sleep.c +++ b/Library/libs/sleep.c @@ -5,13 +5,27 @@ #include #include +/* Divide by ten in shifts. Would be nice if the compiler did that for us 8) + + FIXME: probably worth having a Z80 asm version of this */ +static div10quicki(unsigned int i) +{ + unsigned int q, r; + q = (i >> 1) + (i >> 2); + q = q + (q >> 4); + q = q + (q >> 8); + q >>= 3; + r = i - (((q << 2) + q) << 1); + return q + (r >> 9); +} + unsigned int sleep(unsigned int seconds) { time_t end, now; - _time(&end, 1); - end += seconds; + _time(&end, 1); /* in 1/10ths */ + end += seconds * 10; if (_pause(seconds * 10) == 0) return 0; _time(&now, 1); - return (int)(end - now); + return div10quicki(end - now); }