Source to osfmk/kern/mach_clock.c
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT@
*/
/*
* Mach Operating System
* Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or [email protected]
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
*/
/*
* File: clock_prim.c
* Author: Avadis Tevanian, Jr.
* Date: 1986
*
* Clock primitives.
*/
#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> /* kernel_map */
#include <machine/mach_param.h> /* HZ */
#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; /* Indicates wether or not we
* account kernel services
* samples for user task */
/*
* Hertz rate clock interrupt servicing. Primarily used to
* update CPU statistics, recompute thread priority, and to
* do profiling
*/
void
hertz_tick(
boolean_t usermode, /* executing user code */
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 /* MACH_PROF */
#if GPROF
struct profile_vars *pv;
prof_uptrint_t s;
#endif
#ifdef lint
pc++;
#endif /* lint */
mp_disable_preemption();
my_cpu = cpu_number();
/*
* The system startup sequence initializes the clock
* before kicking off threads. So it's possible,
* especially when debugging, to wind up here with
* no thread to bill against. So ignore the tick.
*/
if (thread == THREAD_NULL) {
mp_enable_preemption();
return;
}
#if MACH_PROF
inkernel = !usermode && (pc < (unsigned int)ETEXT);
#endif /* MACH_PROF */
/*
* Hertz processing performed by all processors
* includes statistics gathering, state tracking,
* and quantum updating.
*/
counter(c_clock_ticks++);
#if GPROF
pv = PROFILE_VARS(my_cpu);
#endif
if (usermode) {
TICKBUMP(&thread->user_timer);
#if 0
if (thread->priority < BASEPRI_USER)
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);
/*
* Hertz processing performed by the master-cpu
* exclusively.
*/
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 /* MACH_BSD */
}
#if MACH_PROF
thr_act = thread->top_act;
if (thr_act->act_profiled && thread->sched_pri != DEPRESSPRI) {
if (inkernel && thr_act->map != kernel_map) {
/*
* Non-kernel thread running in kernel
* Register user pc (mach_msg, vm_allocate ...)
*/
if (profile_kernel_services)
profile(user_pc(thr_act), thr_act->profil_buffer);
}
else
/*
* User thread and user mode or
* user (server) thread in kernel-loaded server or
* kernel thread and kernel mode
* register interrupted pc
*/
profile(pc, thr_act->profil_buffer);
}
if (kernel_task->task_profiled && thread->sched_pri != DEPRESSPRI) {
if (inkernel && thr_act->map != kernel_map)
/*
* User thread not profiled in kernel mode,
* kernel task profiled, register kernel pc
* for kernel task
*/
profile(pc, kernel_task->profil_buffer);
}
#endif /* MACH_PROF */
mp_enable_preemption();
}
/*
* Kernel timeout services.
*/
/*
* Set a timeout.
*
* fcn: function to call
* param: parameter to pass to function
* interval: timeout interval, in hz.
*/
void
timeout(
timeout_fcn_t fcn,
void *param,
int interval)
{
AbsoluteTime deadline;
clock_interval_to_deadline(interval, NSEC_PER_SEC / hz, &deadline);
thread_call_func_delayed((thread_call_func_t)fcn, param, deadline);
}
/*
* Cancel a timeout.
*/
void
untimeout(
register timeout_fcn_t fcn,
register void *param)
{
thread_call_func_cancel((thread_call_func_t)fcn, param, FALSE);
}