#include <mach/mach_types.h>
#include <kern/thread.h>
#include <kern/machine.h>
#include <kern/kalloc.h>
#include <sys/errno.h>
#include <kperf/sample.h>
#include <kperf/pet.h>
#include <kperf/action.h>
#include <kperf/kperf.h>
#include <kperf/timetrigger.h>
#include <kern/ipc_tt.h>
#include <chud/chud_xnu.h>
thread_t *kperf_thread_on_cpus = NULL;
static struct kperf_sample *intr_samplev = NULL;
static unsigned intr_samplec = 0;
static struct
{
int active;
int pad[64 / sizeof(int)];
} *kpdbg_recursev;
static unsigned kpdbg_recursec = 0;
static unsigned sampling_status = KPERF_SAMPLING_OFF;
static unsigned kperf_initted = 0;
extern void (*chudxnu_thread_ast_handler)(thread_t);
struct kperf_sample*
kperf_intr_sample_buffer(void)
{
unsigned ncpu = chudxnu_cpu_number();
if( ncpu >= intr_samplec )
return NULL;
return &intr_samplev[ncpu];
}
int
kperf_kdbg_recurse(int step)
{
unsigned ncpu = chudxnu_cpu_number();
if( ncpu >= kpdbg_recursec )
return 1;
if( (step > 0)
&& (kpdbg_recursev[ncpu].active == 0) )
{
kpdbg_recursev[ncpu].active = 1;
return 0;
}
if( (step > 0)
&& (kpdbg_recursev[ncpu].active != 0) )
{
return 1;
}
if( (step < 0)
&& (kpdbg_recursev[ncpu].active != 0) )
{
kpdbg_recursev[ncpu].active = 0;
return 0;
}
if( (step < 0)
&& (kpdbg_recursev[ncpu].active == 0) )
panic( "return from non-recursed kperf kdebug call" );
panic( "unknown kperf kdebug call" );
return 1;
}
int
kperf_init(void)
{
unsigned ncpus = 0;
int err;
if( kperf_initted )
return 0;
ncpus = machine_info.logical_cpu_max;
kperf_thread_on_cpus = kalloc( ncpus * sizeof(*kperf_thread_on_cpus) );
if( kperf_thread_on_cpus == NULL )
{
err = ENOMEM;
goto error;
}
bzero( kperf_thread_on_cpus, ncpus * sizeof(*kperf_thread_on_cpus) );
intr_samplev = kalloc( ncpus * sizeof(*intr_samplev));
intr_samplec = ncpus;
if( intr_samplev == NULL )
{
err = ENOMEM;
goto error;
}
bzero( intr_samplev, ncpus * sizeof(*intr_samplev) );
kpdbg_recursev = kalloc( ncpus * sizeof(*kpdbg_recursev));
kpdbg_recursec = ncpus;
bzero( kpdbg_recursev, ncpus * sizeof(*kpdbg_recursev) );
kperf_initted = 1;
return 0;
error:
if( intr_samplev )
kfree( intr_samplev, ncpus * sizeof(*intr_samplev) );
if( kperf_thread_on_cpus )
kfree( kperf_thread_on_cpus, ncpus * sizeof(*kperf_thread_on_cpus) );
return err;
}
uint32_t
kperf_get_thread_bits( thread_t thread )
{
return thread->t_chud;
}
void
kperf_set_thread_bits( thread_t thread, uint32_t bits )
{
thread->t_chud = bits;
}
void
kperf_set_thread_ast( thread_t thread )
{
if( thread != current_thread() )
panic( "unsafe AST set" );
act_set_kperf(thread);
}
unsigned
kperf_sampling_status(void)
{
return sampling_status;
}
int
kperf_sampling_enable(void)
{
if( sampling_status == KPERF_SAMPLING_ON )
return 0;
if ( sampling_status != KPERF_SAMPLING_OFF )
panic( "kperf: sampling wasn't off" );
if( !kperf_initted
|| (kperf_action_get_count() == 0) )
return ECANCELED;
sampling_status = KPERF_SAMPLING_ON;
kperf_timer_go();
return 0;
}
int
kperf_sampling_disable(void)
{
if( sampling_status != KPERF_SAMPLING_ON )
return 0;
sampling_status = KPERF_SAMPLING_SHUTDOWN;
kperf_timer_stop();
sampling_status = KPERF_SAMPLING_OFF;
return 0;
}
int
kperf_port_to_pid(mach_port_name_t portname)
{
task_t task;
int pid;
if( !MACH_PORT_VALID(portname) )
return -1;
task = port_name_to_task(portname);
if( task == TASK_NULL )
return -1;
pid = chudxnu_pid_for_task(task);
task_deallocate_internal(task);
return pid;
}