Copyright (C) 1994, Digital Equipment Corp.
MODULE TickPosix EXPORTS Tick;
IMPORT Utime, Word;
CONST
IntModulus = FLOAT(LAST(INTEGER), LONGREAL) + 1.0D0;
WordModulus = 2.0D0 * IntModulus;
IntModulusAsWord = Word.Plus(LAST(INTEGER), 1);
VAR (*CONST*) MicrosecondsPerTick, SecondsPerTick: LONGREAL;
PROCEDURE Now(): T =
VAR
tv: Utime.struct_timeval;
tz: Utime.struct_timezone;
i := Utime.gettimeofday(tv, tz);
d: LONGREAL;
BEGIN
<* ASSERT i=0 *>
d := (FLOAT(tv.tv_sec, LONGREAL)*1.0D6 + FLOAT(tv.tv_usec, LONGREAL))
/ MicrosecondsPerTick
MOD WordModulus;
IF d < IntModulus THEN
RETURN TRUNC(d)
ELSE
RETURN Word.Plus(IntModulusAsWord, TRUNC(d-IntModulus))
END
END Now;
PROCEDURE ToSeconds(t: Word.T): LONGREAL =
BEGIN
IF Word.LT(t, IntModulusAsWord) THEN
RETURN FLOAT(t, LONGREAL) * SecondsPerTick
ELSE
RETURN (FLOAT(Word.Minus(t, IntModulusAsWord), LONGREAL) + IntModulus)
* SecondsPerTick
END
END ToSeconds;
PROCEDURE FromSeconds(s: LONGREAL): Word.T RAISES {Overflow} =
BEGIN
WITH d = s / SecondsPerTick DO
IF d < IntModulus THEN
RETURN TRUNC(d)
ELSIF d < WordModulus THEN
RETURN Word.Plus(IntModulusAsWord, TRUNC(d-IntModulus))
ELSE
RAISE Overflow
END
END
END FromSeconds;
VAR t0, t1: T;
BEGIN
(* Determine value of "MicrosecondsPerTick" experimentally. Note that
this will fail if this thread is descheduled for a tick during the
loop below. *)
MicrosecondsPerTick := 1.0D0; (* just for now! *)
t0 := Now();
REPEAT t1 := Now() UNTIL t1 # t0;
MicrosecondsPerTick := FLOAT(t1-t0, LONGREAL);
SecondsPerTick := MicrosecondsPerTick / 1.0D6
END TickPosix.