void timerintr(Ureg *u, Tval) { uvlong dt, when; int i, j, s, hz; Timer *t, *n. *cascade; Timers *tt; Wheel *w; intrcount[m->machno]++; tt = &timers[m->machno]; ilock(tt); tt->tnow = fastticks(nil); dt = tt->tnow - tt->tlast; assert((vlong)dt >= 0); tt->tlast = tt->tnow; /* * We need to look at all the wheels. */ hz = 0; cascade = nil; for(i = 0; i < NWHEEL; i++){ w = &tt->wheels[i]; s = w->idx; w->idx = (s+dt)&SMASK; for(j = s; j <= s+dt && j < s+NSLOT; j++){ for(t = slot(tt, i, j); t != nil; t = n){ assert(t->tt == tt); n = t->tnext; /* * The last wheel can contain timers that are * expiring both before and after now. * Pull out the ones that are going to cascade * or expire, so we can deal with them later, * but leave the rest in place. */ if(t->twhen <= tt->tnow+TMAX){ tdel(t); t->tnext = cascade; cascade = t; } } } dt += s; dt >>= WSHIFT; } /* * Now that we've updated all the wheel indexes, * process the expiring and cascading timers all * together. */ for(t = cascade; t != nil; t = n){ n = t->tnext; /* * Cascade this timer into a new slot in a closer * wheel; Tins is guaranteed to find the closest * slot, even if there are aliasing slots. */ if(t->twhen > tt->tnow){ tins(tt, t); continue; } /* * 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 */ t->tactive = MACHP(m->machno); fcallcount[m->machno]++; iunlock(tt); if(t->tf) t->tf(u, t); else hz = 1; t->tactive = nil; ilock(tt); if(t->tmode == Tperiodic) tadd(tt, t); } when = tnext(tt, ~0ULL); if(when != 0) timerset(when); iunlock(tt); if(hz) hzclock(u); }