#include <cpus.h>
#include <stat_time.h>
#include <mach_prof.h>
#include <gprof.h>
#include <mach/boolean.h>
#include <mach/machine.h>
#include <mach/time_value.h>
#include <mach/vm_param.h>
#include <mach/vm_prot.h>
#include <kern/clock.h>
#include <kern/counters.h>
#include <kern/cpu_number.h>
#include <kern/host.h>
#include <kern/lock.h>
#include <kern/mach_param.h>
#include <kern/misc_protos.h>
#include <kern/processor.h>
#include <kern/profile.h>
#include <kern/sched.h>
#include <kern/sched_prim.h>
#include <kern/spl.h>
#include <kern/thread.h>
#include <kern/thread_swap.h>
#include <kern/time_out.h>
#include <vm/vm_kern.h>
#include <machine/mach_param.h>
#include <mach/clock_server.h>
#include <mach/clock_priv_server.h>
#include <mach/mach_host_server.h>
#include <profiling/profile-mk.h>
#if STAT_TIME
#define TICKBUMP(t) timer_bump(t, (1000000/HZ))
#else
#define TICKBUMP(t)
#endif
boolean_t profile_kernel_services = TRUE;
void
hertz_tick(
boolean_t usermode,
natural_t pc)
{
thread_act_t thr_act;
register int my_cpu;
register thread_t thread = current_thread();
int state;
#if MACH_PROF
#ifdef __MACHO__
#define ETEXT etext
extern long etext;
#else
#define ETEXT &etext
extern char etext;
#endif
boolean_t inkernel;
#endif
#if GPROF
struct profile_vars *pv;
prof_uptrint_t s;
#endif
#ifdef lint
pc++;
#endif
mp_disable_preemption();
my_cpu = cpu_number();
if (thread == THREAD_NULL) {
mp_enable_preemption();
return;
}
#if MACH_PROF
inkernel = !usermode && (pc < (unsigned int)ETEXT);
#endif
counter(c_clock_ticks++);
#if GPROF
pv = PROFILE_VARS(my_cpu);
#endif
if (usermode) {
TICKBUMP(&thread->user_timer);
#if 0
if (thread->priority < BASEPRI_DEFAULT)
state = CPU_STATE_NICE;
else
#endif
state = CPU_STATE_USER;
#if GPROF
if (pv->active)
PROF_CNT_INC(pv->stats.user_ticks);
#endif
}
else {
switch(processor_ptr[my_cpu]->state) {
case PROCESSOR_IDLE:
TICKBUMP(&thread->system_timer);
state = CPU_STATE_IDLE;
break;
default:
TICKBUMP(&thread->system_timer);
state = CPU_STATE_SYSTEM;
break;
}
#if GPROF
if (pv->active) {
if (state == CPU_STATE_SYSTEM)
PROF_CNT_INC(pv->stats.kernel_ticks);
else
PROF_CNT_INC(pv->stats.idle_ticks);
if ((prof_uptrint_t)pc < _profile_vars.profil_info.lowpc)
PROF_CNT_INC(pv->stats.too_low);
else {
s = (prof_uptrint_t)pc - _profile_vars.profil_info.lowpc;
if (s < pv->profil_info.text_len) {
LHISTCOUNTER *ptr = (LHISTCOUNTER *) pv->profil_buf;
LPROF_CNT_INC(ptr[s / HISTFRACTION]);
}
else
PROF_CNT_INC(pv->stats.too_high);
}
}
#endif
}
machine_slot[my_cpu].cpu_ticks[state]++;
thread_quantum_update(my_cpu, thread, 1, state);
if (my_cpu == master_cpu) {
#ifdef MACH_BSD
{
extern void bsd_hardclock(
boolean_t usermode,
natural_t pc,
int ticks);
bsd_hardclock(usermode, pc, 1);
}
#endif
}
#if MACH_PROF
thr_act = thread->top_act;
if (thr_act->act_profiled) {
if (inkernel && thr_act->map != kernel_map) {
if (profile_kernel_services)
profile(user_pc(thr_act), thr_act->profil_buffer);
}
else
profile(pc, thr_act->profil_buffer);
}
if (kernel_task->task_profiled) {
if (inkernel && thr_act->map != kernel_map)
profile(pc, kernel_task->profil_buffer);
}
#endif
mp_enable_preemption();
}