The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/kern_clock.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
   26 /*-
   27  * Copyright (c) 1982, 1986, 1991, 1993
   28  *      The Regents of the University of California.  All rights reserved.
   29  * (c) UNIX System Laboratories, Inc.
   30  * All or some portions of this file are derived from material licensed
   31  * to the University of California by American Telephone and Telegraph
   32  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   33  * the permission of UNIX System Laboratories, Inc.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 3. All advertising materials mentioning features or use of this software
   44  *    must display the following acknowledgement:
   45  *      This product includes software developed by the University of
   46  *      California, Berkeley and its contributors.
   47  * 4. Neither the name of the University nor the names of its contributors
   48  *    may be used to endorse or promote products derived from this software
   49  *    without specific prior written permission.
   50  *
   51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   61  * SUCH DAMAGE.
   62  *
   63  *      @(#)kern_clock.c        8.5 (Berkeley) 1/21/94
   64  */
   65 /*
   66  * HISTORY
   67  */
   68 
   69 #include <machine/spl.h>
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/time.h>
   74 #include <sys/resourcevar.h>
   75 #include <sys/kernel.h>
   76 #include <sys/resource.h>
   77 #include <sys/proc.h>
   78 #include <sys/vm.h>
   79 
   80 #ifdef GPROF
   81 #include <sys/gmon.h>
   82 #endif
   83 
   84 #include <kern/thread.h>
   85 #include <kern/ast.h>
   86 #include <kern/assert.h>
   87 #include <mach/boolean.h>
   88 
   89 #include <kern/thread_call.h>
   90 
   91 /*
   92  * Clock handling routines.
   93  *
   94  * This code is written to operate with two timers which run
   95  * independently of each other. The main clock, running at hz
   96  * times per second, is used to do scheduling and timeout calculations.
   97  * The second timer does resource utilization estimation statistically
   98  * based on the state of the machine phz times a second. Both functions
   99  * can be performed by a single clock (ie hz == phz), however the 
  100  * statistics will be much more prone to errors. Ideally a machine
  101  * would have separate clocks measuring time spent in user state, system
  102  * state, interrupt state, and idle state. These clocks would allow a non-
  103  * approximate measure of resource utilization.
  104  */
  105 
  106 /*
  107  * The hz hardware interval timer.
  108  * We update the events relating to real time.
  109  * If this timer is also being used to gather statistics,
  110  * we run through the statistics gathering routine as well.
  111  */
  112 
  113 int bsd_hardclockinit = 0;
  114 /*ARGSUSED*/
  115 void
  116 bsd_hardclock(usermode, pc, numticks)
  117         boolean_t usermode;
  118         caddr_t pc;
  119         int numticks;
  120 {
  121         register struct proc *p;
  122         register thread_t       thread;
  123         int nusecs = numticks * tick;
  124         struct timeval          tv;
  125 
  126         if (!bsd_hardclockinit)
  127                 return;
  128 
  129         /*
  130          * Increment the time-of-day.
  131          */
  132         microtime(&tv);
  133         time = tv;
  134 
  135         if (bsd_hardclockinit < 0) {
  136             return;
  137         }
  138 
  139         thread = current_act();
  140         /*
  141          * Charge the time out based on the mode the cpu is in.
  142          * Here again we fudge for the lack of proper interval timers
  143          * assuming that the current state has been around at least
  144          * one tick.
  145          */
  146         p = (struct proc *)current_proc();
  147         if (p && ((p->p_flag & P_WEXIT) == NULL)) {
  148                 if (usermode) {         
  149                         if (p->p_stats && p->p_stats->p_prof.pr_scale) {
  150                                 p->p_flag |= P_OWEUPC;
  151                                 astbsd_on();
  152                         }
  153 
  154                         /*
  155                          * CPU was in user state.  Increment
  156                          * user time counter, and process process-virtual time
  157                          * interval timer. 
  158                          */
  159                         if (p->p_stats && 
  160                                 timerisset(&p->p_stats->p_timer[ITIMER_VIRTUAL].it_value) &&
  161                                 !itimerdecr(&p->p_stats->p_timer[ITIMER_VIRTUAL], nusecs)) {
  162                                 extern void psignal_vtalarm(struct proc *);
  163                         
  164                                 /* does psignal(p, SIGVTALRM) in a thread context */
  165                                 thread_call_func((thread_call_func_t)psignal_vtalarm, p, FALSE);
  166                         }
  167                 }
  168 
  169                 /*
  170                  * If the cpu is currently scheduled to a process, then
  171                  * charge it with resource utilization for a tick, updating
  172                  * statistics which run in (user+system) virtual time,
  173                  * such as the cpu time limit and profiling timers.
  174                  * This assumes that the current process has been running
  175                  * the entire last tick.
  176                  */
  177                 if (!is_thread_idle(thread)) {          
  178                         if (p->p_limit &&
  179                                 p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
  180                                 time_value_t    sys_time, user_time;
  181 
  182                                 thread_read_times(thread, &user_time, &sys_time);
  183                                 if ((sys_time.seconds + user_time.seconds + 1) >
  184                                         p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur) {
  185                                         extern void psignal_xcpu(struct proc *);
  186                         
  187                                         /* does psignal(p, SIGXCPU) in a thread context */
  188                                         thread_call_func((thread_call_func_t)psignal_xcpu, p, FALSE);
  189 
  190                                         if (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur <
  191                                                 p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_max)
  192                                                 p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur += 5;
  193                                 }
  194                         }
  195                         if (timerisset(&p->p_stats->p_timer[ITIMER_PROF].it_value) &&
  196                                 !itimerdecr(&p->p_stats->p_timer[ITIMER_PROF], nusecs)) {
  197                                 extern void psignal_sigprof(struct proc *);
  198                         
  199                                 /* does psignal(p, SIGPROF) in a thread context */
  200                                 thread_call_func((thread_call_func_t)psignal_sigprof, p, FALSE);
  201                         }
  202                 }
  203         }
  204 
  205 #ifdef GPROF
  206         /*
  207          * Gather some statistics.
  208          */
  209         gatherstats(usermode, pc);
  210 #endif
  211 }
  212 
  213 /*
  214  * Gather some statistics.
  215  */
  216 /*ARGSUSED*/
  217 void
  218 gatherstats(
  219         boolean_t       usermode,
  220         caddr_t         pc)
  221 {
  222 #ifdef GPROF
  223         if (!usermode) {
  224                 struct gmonparam *p = &_gmonparam;
  225 
  226                 if (p->state == GMON_PROF_ON) {
  227                         register int s;
  228 
  229                         s = pc - p->lowpc;
  230                         if (s < p->textsize) {
  231                                 s /= (HISTFRACTION * sizeof(*p->kcount));
  232                                 p->kcount[s]++;
  233                         }
  234                 }
  235         }
  236 #endif
  237 }
  238 
  239 
  240 /*
  241  * Kernel timeout services.
  242  */
  243 
  244 /*
  245  *      Set a timeout.
  246  *
  247  *      fcn:            function to call
  248  *      param:          parameter to pass to function
  249  *      interval:       timeout interval, in hz.
  250  */
  251 void
  252 timeout(
  253         timeout_fcn_t                   fcn,
  254         void                                    *param,
  255         int                                             interval)
  256 {
  257         uint64_t                deadline;
  258 
  259         clock_interval_to_deadline(interval, NSEC_PER_SEC / hz, &deadline);
  260         thread_call_func_delayed((thread_call_func_t)fcn, param, deadline);
  261 }
  262 
  263 /*
  264  * Cancel a timeout.
  265  */
  266 void
  267 untimeout(
  268         register timeout_fcn_t          fcn,
  269         register void                           *param)
  270 {
  271         thread_call_func_cancel((thread_call_func_t)fcn, param, FALSE);
  272 }
  273 
  274 
  275 
  276 /*
  277  * Compute number of hz until specified time.
  278  * Used to compute third argument to timeout() from an
  279  * absolute time.
  280  */
  281 hzto(tv)
  282         struct timeval *tv;
  283 {
  284         struct timeval now;
  285         register long ticks;
  286         register long sec;
  287 
  288         microtime(&now);
  289         /*
  290          * If number of milliseconds will fit in 32 bit arithmetic,
  291          * then compute number of milliseconds to time and scale to
  292          * ticks.  Otherwise just compute number of hz in time, rounding
  293          * times greater than representible to maximum value.
  294          *
  295          * Delta times less than 25 days can be computed ``exactly''.
  296          * Maximum value for any timeout in 10ms ticks is 250 days.
  297          */
  298         sec = tv->tv_sec - now.tv_sec;
  299         if (sec <= 0x7fffffff / 1000 - 1000)
  300                 ticks = ((tv->tv_sec - now.tv_sec) * 1000 +
  301                         (tv->tv_usec - now.tv_usec) / 1000)
  302                                 / (tick / 1000);
  303         else if (sec <= 0x7fffffff / hz)
  304                 ticks = sec * hz;
  305         else
  306                 ticks = 0x7fffffff;
  307 
  308         return (ticks);
  309 }
  310 
  311 /*
  312  * Return information about system clocks.
  313  */
  314 int
  315 sysctl_clockrate(where, sizep)
  316         register char *where;
  317         size_t *sizep;
  318 {
  319         struct clockinfo clkinfo;
  320 
  321         /*
  322          * Construct clockinfo structure.
  323          */
  324         clkinfo.hz = hz;
  325         clkinfo.tick = tick;
  326         clkinfo.profhz = hz;
  327         clkinfo.stathz = hz;
  328         return sysctl_rdstruct(where, sizep, NULL, &clkinfo, sizeof(clkinfo));
  329 }
  330 
  331 
  332 /*
  333  * Compute number of ticks in the specified amount of time.
  334  */
  335 int
  336 tvtohz(tv)
  337         struct timeval *tv;
  338 {
  339         register unsigned long ticks;
  340         register long sec, usec;
  341 
  342         /*
  343          * If the number of usecs in the whole seconds part of the time
  344          * difference fits in a long, then the total number of usecs will
  345          * fit in an unsigned long.  Compute the total and convert it to
  346          * ticks, rounding up and adding 1 to allow for the current tick
  347          * to expire.  Rounding also depends on unsigned long arithmetic
  348          * to avoid overflow.
  349          *
  350          * Otherwise, if the number of ticks in the whole seconds part of
  351          * the time difference fits in a long, then convert the parts to
  352          * ticks separately and add, using similar rounding methods and
  353          * overflow avoidance.  This method would work in the previous
  354          * case but it is slightly slower and assumes that hz is integral.
  355          *
  356          * Otherwise, round the time difference down to the maximum
  357          * representable value.
  358          *
  359          * If ints have 32 bits, then the maximum value for any timeout in
  360          * 10ms ticks is 248 days.
  361          */
  362         sec = tv->tv_sec;
  363         usec = tv->tv_usec;
  364         if (usec < 0) {
  365                 sec--;
  366                 usec += 1000000;
  367         }
  368         if (sec < 0) {
  369 #ifdef DIAGNOSTIC
  370                 if (usec > 0) {
  371                         sec++;
  372                         usec -= 1000000;
  373                 }
  374                 printf("tvotohz: negative time difference %ld sec %ld usec\n",
  375                        sec, usec);
  376 #endif
  377                 ticks = 1;
  378         } else if (sec <= LONG_MAX / 1000000)
  379                 ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
  380                         / tick + 1;
  381         else if (sec <= LONG_MAX / hz)
  382                 ticks = sec * hz
  383                         + ((unsigned long)usec + (tick - 1)) / tick + 1;
  384         else
  385                 ticks = LONG_MAX;
  386         if (ticks > INT_MAX)
  387                 ticks = INT_MAX;
  388         return ((int)ticks);
  389 }
  390 
  391 
  392 /*
  393  * Start profiling on a process.
  394  *
  395  * Kernel profiling passes kernel_proc which never exits and hence
  396  * keeps the profile clock running constantly.
  397  */
  398 void
  399 startprofclock(p)
  400         register struct proc *p;
  401 {
  402         if ((p->p_flag & P_PROFIL) == 0)
  403                 p->p_flag |= P_PROFIL;
  404 }
  405 
  406 /*
  407  * Stop profiling on a process.
  408  */
  409 void
  410 stopprofclock(p)
  411         register struct proc *p;
  412 {
  413         if (p->p_flag & P_PROFIL)
  414                 p->p_flag &= ~P_PROFIL;
  415 }
  416 
  417 void
  418 bsd_uprofil(struct time_value *syst, unsigned int pc)
  419 {
  420 struct proc *p = current_proc();
  421 int             ticks;
  422 struct timeval  *tv;
  423 struct timeval st;
  424 
  425         if (p == NULL)
  426                 return;
  427         if ( !(p->p_flag & P_PROFIL))
  428                 return;
  429 
  430         st.tv_sec = syst->seconds;
  431         st.tv_usec = syst->microseconds;
  432 
  433         tv = &(p->p_stats->p_ru.ru_stime);
  434 
  435         ticks = ((tv->tv_sec - st.tv_sec) * 1000 +
  436                 (tv->tv_usec - st.tv_usec) / 1000) /
  437                 (tick / 1000);
  438         if (ticks)
  439                 addupc_task(p, pc, ticks);
  440 }
  441 
  442 void
  443 get_procrustime(time_value_t *tv)
  444 {
  445         struct proc *p = current_proc();
  446         struct timeval st;
  447 
  448         if (p == NULL) 
  449                 return;
  450         if ( !(p->p_flag & P_PROFIL))
  451                 return;
  452 
  453         st = p->p_stats->p_ru.ru_stime;
  454         
  455         tv->seconds = st.tv_sec;
  456         tv->microseconds = st.tv_usec;
  457 }

Cache object: 46e69762fcb21765ec1f002cc771d14c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.