summaryrefslogtreecommitdiff
path: root/sys/src/9/port/portclock.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/port/portclock.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/port/portclock.c')
-rwxr-xr-xsys/src/9/port/portclock.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/sys/src/9/port/portclock.c b/sys/src/9/port/portclock.c
new file mode 100755
index 000000000..624283d3c
--- /dev/null
+++ b/sys/src/9/port/portclock.c
@@ -0,0 +1,272 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+
+struct Timers
+{
+ Lock;
+ Timer *head;
+};
+
+static Timers timers[MAXMACH];
+
+ulong intrcount[MAXMACH];
+ulong fcallcount[MAXMACH];
+
+static vlong
+tadd(Timers *tt, Timer *nt)
+{
+ Timer *t, **last;
+
+ /* Called with tt locked */
+ assert(nt->tt == nil);
+ switch(nt->tmode){
+ default:
+ panic("timer");
+ break;
+ case Trelative:
+ if(nt->tns <= 0)
+ nt->tns = 1;
+ nt->twhen = fastticks(nil) + ns2fastticks(nt->tns);
+ break;
+ case Tperiodic:
+ assert(nt->tns >= 100000); /* At least 100 µs period */
+ if(nt->twhen == 0){
+ /* look for another timer at same frequency for combining */
+ for(t = tt->head; t; t = t->tnext){
+ if(t->tmode == Tperiodic && t->tns == nt->tns)
+ break;
+ }
+ if (t)
+ nt->twhen = t->twhen;
+ else
+ nt->twhen = fastticks(nil);
+ }
+ nt->twhen += ns2fastticks(nt->tns);
+ break;
+ }
+
+ for(last = &tt->head; t = *last; last = &t->tnext){
+ if(t->twhen > nt->twhen)
+ break;
+ }
+ nt->tnext = *last;
+ *last = nt;
+ nt->tt = tt;
+ if(last == &tt->head)
+ return nt->twhen;
+ return 0;
+}
+
+static uvlong
+tdel(Timer *dt)
+{
+
+ Timer *t, **last;
+ Timers *tt;
+
+ tt = dt->tt;
+ if (tt == nil)
+ return 0;
+ for(last = &tt->head; t = *last; last = &t->tnext){
+ if(t == dt){
+ assert(dt->tt);
+ dt->tt = nil;
+ *last = t->tnext;
+ break;
+ }
+ }
+ if(last == &tt->head && tt->head)
+ return tt->head->twhen;
+ return 0;
+}
+
+/* add or modify a timer */
+void
+timeradd(Timer *nt)
+{
+ Timers *tt;
+ vlong when;
+
+ /* Must lock Timer struct before Timers struct */
+ ilock(nt);
+ if(tt = nt->tt){
+ ilock(tt);
+ tdel(nt);
+ iunlock(tt);
+ }
+ tt = &timers[m->machno];
+ ilock(tt);
+ when = tadd(tt, nt);
+ if(when)
+ timerset(when);
+ iunlock(tt);
+ iunlock(nt);
+}
+
+
+void
+timerdel(Timer *dt)
+{
+ Timers *tt;
+ uvlong when;
+
+ ilock(dt);
+ if(tt = dt->tt){
+ ilock(tt);
+ when = tdel(dt);
+ if(when && tt == &timers[m->machno])
+ timerset(tt->head->twhen);
+ iunlock(tt);
+ }
+ iunlock(dt);
+}
+
+void
+hzclock(Ureg *ur)
+{
+ m->ticks++;
+ if(m->proc)
+ m->proc->pc = ur->pc;
+
+ if(m->flushmmu){
+ if(up)
+ flushmmu();
+ m->flushmmu = 0;
+ }
+
+ accounttime();
+ kmapinval();
+
+ if(kproftimer != nil)
+ kproftimer(ur->pc);
+
+ if((active.machs&(1<<m->machno)) == 0)
+ return;
+
+ if(active.exiting) {
+ print("someone's exiting\n");
+ exit(0);
+ }
+
+ checkalarms();
+
+ if(up && up->state == Running)
+ hzsched(); /* in proc.c */
+}
+
+void
+timerintr(Ureg *u, Tval)
+{
+ Timer *t;
+ Timers *tt;
+ uvlong when, now;
+ int callhzclock;
+ static int sofar;
+
+ intrcount[m->machno]++;
+ callhzclock = 0;
+ tt = &timers[m->machno];
+ now = fastticks(nil);
+ ilock(tt);
+ while(t = tt->head){
+ /*
+ * No need to ilock t here: any manipulation of t
+ * requires tdel(t) and this must be done with a
+ * lock to tt held. We have tt, so the tdel will
+ * wait until we're done
+ */
+ when = t->twhen;
+ if(when > now){
+ timerset(when);
+ iunlock(tt);
+ if(callhzclock)
+ hzclock(u);
+ return;
+ }
+ tt->head = t->tnext;
+ assert(t->tt == tt);
+ t->tt = nil;
+ fcallcount[m->machno]++;
+ iunlock(tt);
+ if(t->tf)
+ (*t->tf)(u, t);
+ else
+ callhzclock++;
+ ilock(tt);
+ if(t->tmode == Tperiodic)
+ tadd(tt, t);
+ }
+ iunlock(tt);
+}
+
+void
+timersinit(void)
+{
+ Timer *t;
+
+ /*
+ * T->tf == nil means the HZ clock for this processor.
+ */
+ todinit();
+ t = malloc(sizeof(*t));
+ t->tmode = Tperiodic;
+ t->tt = nil;
+ t->tns = 1000000000/HZ;
+ t->tf = nil;
+ timeradd(t);
+}
+
+Timer*
+addclock0link(void (*f)(void), int ms)
+{
+ Timer *nt;
+ uvlong when;
+
+ /* Synchronize to hztimer if ms is 0 */
+ nt = malloc(sizeof(Timer));
+ if(ms == 0)
+ ms = 1000/HZ;
+ nt->tns = (vlong)ms*1000000LL;
+ nt->tmode = Tperiodic;
+ nt->tt = nil;
+ nt->tf = (void (*)(Ureg*, Timer*))f;
+
+ ilock(&timers[0]);
+ when = tadd(&timers[0], nt);
+ if(when)
+ timerset(when);
+ iunlock(&timers[0]);
+ return nt;
+}
+
+/*
+ * This tk2ms avoids overflows that the macro version is prone to.
+ * It is a LOT slower so shouldn't be used if you're just converting
+ * a delta.
+ */
+ulong
+tk2ms(ulong ticks)
+{
+ uvlong t, hz;
+
+ t = ticks;
+ hz = HZ;
+ t *= 1000L;
+ t = t/hz;
+ ticks = t;
+ return ticks;
+}
+
+ulong
+ms2tk(ulong ms)
+{
+ /* avoid overflows at the cost of precision */
+ if(ms >= 1000000000/HZ)
+ return (ms/1000)*HZ;
+ return (ms*HZ+500)/1000;
+}