2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 
  30  * Copyright (c) 1982, 1986, 1991, 1993 
  31  *      The Regents of the University of California.  All rights reserved. 
  32  * (c) UNIX System Laboratories, Inc. 
  33  * All or some portions of this file are derived from material licensed 
  34  * to the University of California by American Telephone and Telegraph 
  35  * Co. or Unix System Laboratories, Inc. and are reproduced herein with 
  36  * the permission of UNIX System Laboratories, Inc. 
  38  * Redistribution and use in source and binary forms, with or without 
  39  * modification, are permitted provided that the following conditions 
  41  * 1. Redistributions of source code must retain the above copyright 
  42  *    notice, this list of conditions and the following disclaimer. 
  43  * 2. Redistributions in binary form must reproduce the above copyright 
  44  *    notice, this list of conditions and the following disclaimer in the 
  45  *    documentation and/or other materials provided with the distribution. 
  46  * 3. All advertising materials mentioning features or use of this software 
  47  *    must display the following acknowledgement: 
  48  *      This product includes software developed by the University of 
  49  *      California, Berkeley and its contributors. 
  50  * 4. Neither the name of the University nor the names of its contributors 
  51  *    may be used to endorse or promote products derived from this software 
  52  *    without specific prior written permission. 
  54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
  55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
  58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  66  *      @(#)kern_clock.c        8.5 (Berkeley) 1/21/94 
  72 #include <machine/spl.h> 
  74 #include <sys/param.h> 
  75 #include <sys/systm.h> 
  77 #include <sys/resourcevar.h> 
  78 #include <sys/kernel.h> 
  79 #include <sys/resource.h> 
  80 #include <sys/proc_internal.h> 
  82 #include <sys/sysctl.h> 
  88 #include <kern/thread.h> 
  90 #include <kern/assert.h> 
  91 #include <mach/boolean.h> 
  93 #include <kern/thread_call.h> 
  95 void bsd_uprofil(struct time_value 
*syst
, user_addr_t pc
); 
  96 void get_procrustime(time_value_t 
*tv
); 
  97 int sysctl_clockrate(user_addr_t where
, size_t *sizep
); 
  98 int tvtohz(struct timeval 
*tv
); 
  99 extern void psignal_sigprof(struct proc 
*); 
 100 extern void psignal_vtalarm(struct proc 
*); 
 101 extern void psignal_xcpu(struct proc 
*); 
 104  * Clock handling routines. 
 106  * This code is written to operate with two timers which run 
 107  * independently of each other. The main clock, running at hz 
 108  * times per second, is used to do scheduling and timeout calculations. 
 109  * The second timer does resource utilization estimation statistically 
 110  * based on the state of the machine phz times a second. Both functions 
 111  * can be performed by a single clock (ie hz == phz), however the  
 112  * statistics will be much more prone to errors. Ideally a machine 
 113  * would have separate clocks measuring time spent in user state, system 
 114  * state, interrupt state, and idle state. These clocks would allow a non- 
 115  * approximate measure of resource utilization. 
 119  * The hz hardware interval timer. 
 120  * We update the events relating to real time. 
 121  * If this timer is also being used to gather statistics, 
 122  * we run through the statistics gathering routine as well. 
 125 int             hz 
= 100;                /* GET RID OF THIS !!! */ 
 126 int             tick 
= (1000000 / 100);  /* GET RID OF THIS !!! */ 
 128 int bsd_hardclockinit 
= 0; 
 141         register struct proc 
*p
; 
 142         register thread_t       thread
; 
 143         int nusecs 
= numticks 
* tick
; 
 146         if (!bsd_hardclockinit
) 
 149         if (bsd_hardclockinit 
< 0) { 
 153         thread 
= current_thread(); 
 155          * Charge the time out based on the mode the cpu is in. 
 156          * Here again we fudge for the lack of proper interval timers 
 157          * assuming that the current state has been around at least 
 160         p 
= (struct proc 
*)current_proc(); 
 161         if (p 
&& ((p
->p_flag 
& P_WEXIT
) == 0)) { 
 163                         if (p
->p_stats 
&& p
->p_stats
->p_prof
.pr_scale
) { 
 164                                 p
->p_flag 
|= P_OWEUPC
; 
 169                          * CPU was in user state.  Increment 
 170                          * user time counter, and process process-virtual time 
 174                                 timerisset(&p
->p_stats
->p_timer
[ITIMER_VIRTUAL
].it_value
) && 
 175                                 !itimerdecr(&p
->p_stats
->p_timer
[ITIMER_VIRTUAL
], nusecs
)) { 
 177                                 /* does psignal(p, SIGVTALRM) in a thread context */ 
 178                                 thread_call_func((thread_call_func_t
)psignal_vtalarm
, p
, FALSE
); 
 183                  * If the cpu is currently scheduled to a process, then 
 184                  * charge it with resource utilization for a tick, updating 
 185                  * statistics which run in (user+system) virtual time, 
 186                  * such as the cpu time limit and profiling timers. 
 187                  * This assumes that the current process has been running 
 188                  * the entire last tick. 
 190                 if (!is_thread_idle(thread
)) {           
 192                                 p
->p_limit
->pl_rlimit
[RLIMIT_CPU
].rlim_cur 
!= RLIM_INFINITY
) { 
 193                                 time_value_t    sys_time
, user_time
; 
 195                                 thread_read_times(thread
, &user_time
, &sys_time
); 
 196                                 if ((sys_time
.seconds 
+ user_time
.seconds 
+ 1) > 
 197                                         p
->p_limit
->pl_rlimit
[RLIMIT_CPU
].rlim_cur
) { 
 199                                         /* does psignal(p, SIGXCPU) in a thread context */ 
 200                                         thread_call_func((thread_call_func_t
)psignal_xcpu
, p
, FALSE
); 
 202                                         if (p
->p_limit
->pl_rlimit
[RLIMIT_CPU
].rlim_cur 
< 
 203                                                 p
->p_limit
->pl_rlimit
[RLIMIT_CPU
].rlim_max
) 
 204                                                 p
->p_limit
->pl_rlimit
[RLIMIT_CPU
].rlim_cur 
+= 5; 
 207                         if (timerisset(&p
->p_stats
->p_timer
[ITIMER_PROF
].it_value
) && 
 208                                 !itimerdecr(&p
->p_stats
->p_timer
[ITIMER_PROF
], nusecs
)) { 
 210                                 /* does psignal(p, SIGPROF) in a thread context */ 
 211                                 thread_call_func((thread_call_func_t
)psignal_sigprof
, p
, FALSE
); 
 218          * Gather some statistics. 
 220         gatherstats(usermode
, pc
); 
 225  * Gather some statistics. 
 234                 __unused boolean_t      usermode
, 
 242                 struct gmonparam 
*p 
= &_gmonparam
; 
 244                 if (p
->state 
== GMON_PROF_ON
) { 
 248                         if (s 
< p
->textsize
) { 
 249                                 s 
/= (HISTFRACTION 
* sizeof(*p
->kcount
)); 
 259  * Kernel timeout services. 
 265  *      fcn:            function to call 
 266  *      param:          parameter to pass to function 
 267  *      interval:       timeout interval, in hz. 
 277         clock_interval_to_deadline(interval
, NSEC_PER_SEC 
/ hz
, &deadline
); 
 278         thread_call_func_delayed((thread_call_func_t
)fcn
, param
, deadline
); 
 286         register timeout_fcn_t          fcn
, 
 287         register void                           *param
) 
 289         thread_call_func_cancel((thread_call_func_t
)fcn
, param
, FALSE
); 
 296  *      fcn:            function to call 
 297  *      param:          parameter to pass to function 
 298  *      ts:             timeout interval, in timespec 
 306         uint64_t                deadline 
= 0; 
 308         if (ts 
&& (ts
->tv_sec 
|| ts
->tv_nsec
)) { 
 309                 nanoseconds_to_absolutetime((uint64_t)ts
->tv_sec 
* NSEC_PER_SEC 
+ ts
->tv_nsec
,  &deadline 
); 
 310                 clock_absolutetime_interval_to_deadline( deadline
, &deadline 
); 
 312         thread_call_func_delayed((thread_call_func_t
)fcn
, param
, deadline
); 
 320         register timeout_fcn_t          fcn
, 
 321         register void                           *param
) 
 323         thread_call_func_cancel((thread_call_func_t
)fcn
, param
, FALSE
); 
 328  * Compute number of hz until specified time. 
 329  * Used to compute third argument to timeout() from an 
 342          * If number of milliseconds will fit in 32 bit arithmetic, 
 343          * then compute number of milliseconds to time and scale to 
 344          * ticks.  Otherwise just compute number of hz in time, rounding 
 345          * times greater than representible to maximum value. 
 347          * Delta times less than 25 days can be computed ``exactly''. 
 348          * Maximum value for any timeout in 10ms ticks is 250 days. 
 350         sec 
= tv
->tv_sec 
- now
.tv_sec
; 
 351         if (sec 
<= 0x7fffffff / 1000 - 1000) 
 352                 ticks 
= ((tv
->tv_sec 
- now
.tv_sec
) * 1000 + 
 353                         (tv
->tv_usec 
- now
.tv_usec
) / 1000) 
 355         else if (sec 
<= 0x7fffffff / hz
) 
 364  * Return information about system clocks. 
 367 sysctl_clockrate(user_addr_t where
, size_t *sizep
) 
 369         struct clockinfo clkinfo
; 
 372          * Construct clockinfo structure. 
 378         return sysctl_rdstruct(where
, sizep
, USER_ADDR_NULL
, &clkinfo
, sizeof(clkinfo
)); 
 383  * Compute number of ticks in the specified amount of time. 
 386 tvtohz(struct timeval 
*tv
) 
 388         register unsigned long ticks
; 
 389         register long sec
, usec
; 
 392          * If the number of usecs in the whole seconds part of the time 
 393          * difference fits in a long, then the total number of usecs will 
 394          * fit in an unsigned long.  Compute the total and convert it to 
 395          * ticks, rounding up and adding 1 to allow for the current tick 
 396          * to expire.  Rounding also depends on unsigned long arithmetic 
 399          * Otherwise, if the number of ticks in the whole seconds part of 
 400          * the time difference fits in a long, then convert the parts to 
 401          * ticks separately and add, using similar rounding methods and 
 402          * overflow avoidance.  This method would work in the previous 
 403          * case but it is slightly slower and assumes that hz is integral. 
 405          * Otherwise, round the time difference down to the maximum 
 406          * representable value. 
 408          * If ints have 32 bits, then the maximum value for any timeout in 
 409          * 10ms ticks is 248 days. 
 423                 printf("tvotohz: negative time difference %ld sec %ld usec\n", 
 427         } else if (sec 
<= LONG_MAX 
/ 1000000) 
 428                 ticks 
= (sec 
* 1000000 + (unsigned long)usec 
+ (tick 
- 1)) 
 430         else if (sec 
<= LONG_MAX 
/ hz
) 
 432                         + ((unsigned long)usec 
+ (tick 
- 1)) / tick 
+ 1; 
 442  * Start profiling on a process. 
 444  * Kernel profiling passes kernel_proc which never exits and hence 
 445  * keeps the profile clock running constantly. 
 449         register struct proc 
*p
; 
 451         if ((p
->p_flag 
& P_PROFIL
) == 0) 
 452                 p
->p_flag 
|= P_PROFIL
; 
 456  * Stop profiling on a process. 
 460         register struct proc 
*p
; 
 462         if (p
->p_flag 
& P_PROFIL
) 
 463                 p
->p_flag 
&= ~P_PROFIL
; 
 467 bsd_uprofil(struct time_value 
*syst
, user_addr_t pc
) 
 469 struct proc 
*p 
= current_proc(); 
 476         if ( !(p
->p_flag 
& P_PROFIL
)) 
 479         st
.tv_sec 
= syst
->seconds
; 
 480         st
.tv_usec 
= syst
->microseconds
; 
 482         tv 
= &(p
->p_stats
->p_ru
.ru_stime
); 
 484         ticks 
= ((tv
->tv_sec 
- st
.tv_sec
) * 1000 + 
 485                 (tv
->tv_usec 
- st
.tv_usec
) / 1000) / 
 488                 addupc_task(p
, pc
, ticks
); 
 492 get_procrustime(time_value_t 
*tv
) 
 494         struct proc 
*p 
= current_proc(); 
 499         if ( !(p
->p_flag 
& P_PROFIL
)) 
 502         st 
= p
->p_stats
->p_ru
.ru_stime
; 
 504         tv
->seconds 
= st
.tv_sec
; 
 505         tv
->microseconds 
= st
.tv_usec
;