Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_clocksource.c
Show First 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | struct pcpu_state { | ||||
sbintime_t now; /* Last tick time. */ | sbintime_t now; /* Last tick time. */ | ||||
sbintime_t nextevent; /* Next scheduled event on this CPU. */ | sbintime_t nextevent; /* Next scheduled event on this CPU. */ | ||||
sbintime_t nexttick; /* Next timer tick time. */ | sbintime_t nexttick; /* Next timer tick time. */ | ||||
sbintime_t nexthard; /* Next hardclock() event. */ | sbintime_t nexthard; /* Next hardclock() event. */ | ||||
sbintime_t nextstat; /* Next statclock() event. */ | sbintime_t nextstat; /* Next statclock() event. */ | ||||
sbintime_t nextprof; /* Next profclock() event. */ | sbintime_t nextprof; /* Next profclock() event. */ | ||||
sbintime_t nextcall; /* Next callout event. */ | sbintime_t nextcall; /* Next callout event. */ | ||||
sbintime_t nextcallopt; /* Next optional callout event. */ | sbintime_t nextcallopt; /* Next optional callout event. */ | ||||
int ipi; /* This CPU needs IPI. */ | bool ipi; /* This CPU needs IPI. */ | ||||
int idle; /* This CPU is in idle mode. */ | bool idle; /* This CPU is in idle mode. */ | ||||
bool running; /* handleevents() is running. */ | |||||
}; | }; | ||||
static DPCPU_DEFINE(struct pcpu_state, timerstate); | static DPCPU_DEFINE(struct pcpu_state, timerstate); | ||||
DPCPU_DEFINE(sbintime_t, hardclocktime); | DPCPU_DEFINE(sbintime_t, hardclocktime); | ||||
/* | /* | ||||
* Timer broadcast IPI handler. | * Timer broadcast IPI handler. | ||||
*/ | */ | ||||
Show All 19 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
handleevents(sbintime_t now, int fake) | handleevents(sbintime_t now, int fake) | ||||
{ | { | ||||
sbintime_t t, *hct; | sbintime_t t, *hct; | ||||
struct trapframe *frame; | struct trapframe *frame; | ||||
struct pcpu_state *state; | struct pcpu_state *state; | ||||
int usermode; | int usermode; | ||||
int done, runs; | int done, hardruns, profruns, statruns; | ||||
bool calloutready; | |||||
hselasky: Where are you setting calloutready to false? | |||||
CTR3(KTR_SPARE2, "handle at %d: now %d.%08x", | CTR3(KTR_SPARE2, "handle at %d: now %d.%08x", | ||||
curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); | curcpu, (int)(now >> 32), (u_int)(now & 0xffffffff)); | ||||
done = 0; | done = 0; | ||||
if (fake) { | if (fake) { | ||||
frame = NULL; | frame = NULL; | ||||
usermode = 0; | usermode = 0; | ||||
} else { | } else { | ||||
frame = curthread->td_intr_frame; | frame = curthread->td_intr_frame; | ||||
usermode = TRAPF_USERMODE(frame); | usermode = TRAPF_USERMODE(frame); | ||||
} | } | ||||
state = DPCPU_PTR(timerstate); | state = DPCPU_PTR(timerstate); | ||||
runs = 0; | /* Acquire lock and determine what work needs to be done. */ | ||||
ET_HW_LOCK(state); | |||||
again: | |||||
hardruns = profruns = statruns = 0; | |||||
while (now >= state->nexthard) { | while (now >= state->nexthard) { | ||||
state->nexthard += tick_sbt; | state->nexthard += tick_sbt; | ||||
runs++; | hardruns++; | ||||
} | } | ||||
if (runs) { | if (hardruns) { | ||||
hct = DPCPU_PTR(hardclocktime); | hct = DPCPU_PTR(hardclocktime); | ||||
*hct = state->nexthard - tick_sbt; | *hct = state->nexthard - tick_sbt; | ||||
if (fake < 2) { | |||||
hardclock_cnt(runs, usermode); | |||||
done = 1; | |||||
} | } | ||||
} | |||||
runs = 0; | |||||
while (now >= state->nextstat) { | while (now >= state->nextstat) { | ||||
state->nextstat += statperiod; | state->nextstat += statperiod; | ||||
runs++; | statruns++; | ||||
} | } | ||||
if (runs && fake < 2) { | |||||
statclock_cnt(runs, usermode); | |||||
done = 1; | |||||
} | |||||
if (profiling) { | if (profiling) { | ||||
runs = 0; | |||||
while (now >= state->nextprof) { | while (now >= state->nextprof) { | ||||
state->nextprof += profperiod; | state->nextprof += profperiod; | ||||
runs++; | profruns++; | ||||
} | } | ||||
if (runs && !fake) { | |||||
profclock_cnt(runs, usermode, TRAPF_PC(frame)); | |||||
done = 1; | |||||
} | |||||
} else | } else | ||||
state->nextprof = state->nextstat; | state->nextprof = state->nextstat; | ||||
if (now >= state->nextcallopt || now >= state->nextcall) { | if (now >= state->nextcallopt || now >= state->nextcall) { | ||||
state->nextcall = state->nextcallopt = SBT_MAX; | state->nextcall = state->nextcallopt = SBT_MAX; | ||||
callout_process(now); | calloutready = true; | ||||
} | } | ||||
state->running = true; | |||||
t = getnextcpuevent(0); | /* Drop the lock and do the work. */ | ||||
kibUnsubmitted Not Done Inline ActionsIs it possible that the function was called without work to do ? If this case has non-trivial number of occurrences, you might consider to calculate done under the lock and not dropping the lock if done == 0. kib: Is it possible that the function was called without work to do ? If this case has non-trivial… | |||||
jtlAuthorUnsubmitted Not Done Inline ActionsI'll add a counter and check. jtl: I'll add a counter and check. | |||||
ET_HW_UNLOCK(state); | |||||
if (hardruns && fake < 2) { | |||||
hardclock_cnt(hardruns, usermode); | |||||
done = 1; | |||||
} | |||||
if (statruns && fake < 2) { | |||||
statclock_cnt(statruns, usermode); | |||||
done = 1; | |||||
} | |||||
if (profruns && !fake) { | |||||
profclock_cnt(profruns, usermode, TRAPF_PC(frame)); | |||||
done = 1; | |||||
} | |||||
if (calloutready) | |||||
callout_process(now); | |||||
/* Obtain the lock and reschedule the timer. */ | |||||
ET_HW_LOCK(state); | ET_HW_LOCK(state); | ||||
t = getnextcpuevent(0); | |||||
if (!periodic) { | |||||
now = sbinuptime(); | |||||
if (now >= t || now >= state->nextcallopt) | |||||
goto again; | |||||
} | |||||
if (!busy) { | if (!busy) { | ||||
state->idle = 0; | state->idle = 0; | ||||
state->nextevent = t; | state->nextevent = t; | ||||
loadtimer(now, (fake == 2) && | loadtimer(now, (fake == 2) && | ||||
(timer->et_flags & ET_FLAGS_PERCPU)); | (timer->et_flags & ET_FLAGS_PERCPU)); | ||||
} | } | ||||
state->running = false; | |||||
ET_HW_UNLOCK(state); | ET_HW_UNLOCK(state); | ||||
return (done); | return (done); | ||||
} | } | ||||
/* | /* | ||||
* Schedule binuptime of the next event on current CPU. | * Schedule binuptime of the next event on current CPU. | ||||
*/ | */ | ||||
static sbintime_t | static sbintime_t | ||||
▲ Show 20 Lines • Show All 360 Lines • ▼ Show 20 Lines | cpu_initclocks_bsp(void) | ||||
int base, div, cpu; | int base, div, cpu; | ||||
mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); | mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); | ||||
CPU_FOREACH(cpu) { | CPU_FOREACH(cpu) { | ||||
state = DPCPU_ID_PTR(cpu, timerstate); | state = DPCPU_ID_PTR(cpu, timerstate); | ||||
mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); | mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); | ||||
state->nextcall = SBT_MAX; | state->nextcall = SBT_MAX; | ||||
state->nextcallopt = SBT_MAX; | state->nextcallopt = SBT_MAX; | ||||
state->ipi = state->idle = state->running = false; | |||||
} | } | ||||
periodic = want_periodic; | periodic = want_periodic; | ||||
/* Grab requested timer or the best of present. */ | /* Grab requested timer or the best of present. */ | ||||
if (timername[0]) | if (timername[0]) | ||||
timer = et_find(timername, 0, 0); | timer = et_find(timername, 0, 0); | ||||
if (timer == NULL && periodic) { | if (timer == NULL && periodic) { | ||||
timer = et_find(NULL, | timer = et_find(NULL, | ||||
ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); | ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); | ||||
▲ Show 20 Lines • Show All 229 Lines • ▼ Show 20 Lines | cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt) | ||||
* and scheduling. | * and scheduling. | ||||
*/ | */ | ||||
state->nextcallopt = bt_opt; | state->nextcallopt = bt_opt; | ||||
if (bt >= state->nextcall) | if (bt >= state->nextcall) | ||||
goto done; | goto done; | ||||
state->nextcall = bt; | state->nextcall = bt; | ||||
/* If there is some other event set earlier -- do nothing. */ | /* If there is some other event set earlier -- do nothing. */ | ||||
if (bt >= state->nextevent) | if (bt >= state->nextevent) | ||||
goto done; | |||||
/* | |||||
* If handleevents() is running, it will pick up the earlier | |||||
* callout and schedule the correct execution at the correct | |||||
* time. | |||||
*/ | |||||
if (state->running) | |||||
goto done; | goto done; | ||||
state->nextevent = bt; | state->nextevent = bt; | ||||
/* If timer is periodic -- there is nothing to reprogram. */ | /* If timer is periodic -- there is nothing to reprogram. */ | ||||
if (periodic) | if (periodic) | ||||
goto done; | goto done; | ||||
/* If timer is global or of the current CPU -- reprogram it. */ | /* If timer is global or of the current CPU -- reprogram it. */ | ||||
if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) { | if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) { | ||||
loadtimer(sbinuptime(), 0); | loadtimer(sbinuptime(), 0); | ||||
▲ Show 20 Lines • Show All 117 Lines • Show Last 20 Lines |
Where are you setting calloutready to false?