#include <unistd.h>
#include <errno.h>
+/* 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:
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;
/* 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;
}
#include <signal.h>
#include <syscalls.h>
+/* 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);
}