kern_tc.c (29179) | kern_tc.c (29680) |
---|---|
1/*- 2 * Copyright (c) 1982, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. --- 22 unchanged lines hidden (view full) --- 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 | 1/*- 2 * Copyright (c) 1982, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. --- 22 unchanged lines hidden (view full) --- 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 |
39 * $Id: kern_clock.c,v 1.39 1997/09/02 20:05:37 bde Exp $ | 39 * $Id: kern_clock.c,v 1.40 1997/09/07 05:25:43 bde Exp $ |
40 */ 41 42/* Portions of this software are covered by the following: */ 43/****************************************************************************** 44 * * 45 * Copyright (c) David L. Mills 1993, 1994 * 46 * * 47 * Permission to use, copy, modify, and distribute this software and its * --- 33 unchanged lines hidden (view full) --- 81#ifdef GPROF 82#include <sys/gmon.h> 83#endif 84 85static void initclocks __P((void *dummy)); 86SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL) 87 88/* Exported to machdep.c. */ | 40 */ 41 42/* Portions of this software are covered by the following: */ 43/****************************************************************************** 44 * * 45 * Copyright (c) David L. Mills 1993, 1994 * 46 * * 47 * Permission to use, copy, modify, and distribute this software and its * --- 33 unchanged lines hidden (view full) --- 81#ifdef GPROF 82#include <sys/gmon.h> 83#endif 84 85static void initclocks __P((void *dummy)); 86SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL) 87 88/* Exported to machdep.c. */ |
89struct callout *callfree, *callout; | 89struct callout *callout; 90struct callout_list callfree; 91int callwheelsize, callwheelbits, callwheelmask; 92struct callout_tailq *callwheel; |
90 | 93 |
91static struct callout calltodo; | |
92 93/* Some of these don't belong here, but it's easiest to concentrate them. */ 94static long cp_time[CPUSTATES]; 95long dk_seek[DK_NDRIVE]; 96static long dk_time[DK_NDRIVE]; /* time busy (in statclock ticks) */ 97long dk_wds[DK_NDRIVE]; 98long dk_wpms[DK_NDRIVE]; 99long dk_xfer[DK_NDRIVE]; --- 49 unchanged lines hidden (view full) --- 149 tp->tv_sec++; \ 150 } \ 151} 152 153int stathz; 154int profhz; 155static int profprocs; 156int ticks; | 94 95/* Some of these don't belong here, but it's easiest to concentrate them. */ 96static long cp_time[CPUSTATES]; 97long dk_seek[DK_NDRIVE]; 98static long dk_time[DK_NDRIVE]; /* time busy (in statclock ticks) */ 99long dk_wds[DK_NDRIVE]; 100long dk_wpms[DK_NDRIVE]; 101long dk_xfer[DK_NDRIVE]; --- 49 unchanged lines hidden (view full) --- 151 tp->tv_sec++; \ 152 } \ 153} 154 155int stathz; 156int profhz; 157static int profprocs; 158int ticks; |
157static int psdiv, pscnt; /* prof => stat divider */ 158int psratio; /* ratio: prof / stat */ | 159static int softticks; /* Like ticks, but for softclock(). */ 160static struct callout *nextsoftcheck; /* Next callout to be checked. */ 161static int psdiv, pscnt; /* prof => stat divider */ 162int psratio; /* ratio: prof / stat */ |
159 160volatile struct timeval time; 161volatile struct timeval mono_time; 162 163/* 164 * Phase/frequency-lock loop (PLL/FLL) definitions 165 * 166 * The following variables are read and set by the ntp_adjtime() system --- 280 unchanged lines hidden (view full) --- 447 * The real-time timer, interrupting hz times per second. 448 */ 449void 450hardclock(frame) 451 register struct clockframe *frame; 452{ 453 register struct callout *p1; 454 register struct proc *p; | 163 164volatile struct timeval time; 165volatile struct timeval mono_time; 166 167/* 168 * Phase/frequency-lock loop (PLL/FLL) definitions 169 * 170 * The following variables are read and set by the ntp_adjtime() system --- 280 unchanged lines hidden (view full) --- 451 * The real-time timer, interrupting hz times per second. 452 */ 453void 454hardclock(frame) 455 register struct clockframe *frame; 456{ 457 register struct callout *p1; 458 register struct proc *p; |
455 register int needsoft; | |
456 | 459 |
457 /* 458 * Update real-time timeout queue. 459 * At front of queue are some number of events which are ``due''. 460 * The time to these is <= 0 and if negative represents the 461 * number of ticks which have passed since it was supposed to happen. 462 * The rest of the q elements (times > 0) are events yet to happen, 463 * where the time for each is given as a delta from the previous. 464 * Decrementing just the first of these serves to decrement the time 465 * to all events. 466 */ 467 needsoft = 0; 468 for (p1 = calltodo.c_next; p1 != NULL; p1 = p1->c_next) { 469 if (--p1->c_time > 0) 470 break; 471 needsoft = 1; 472 if (p1->c_time == 0) 473 break; 474 } 475 | |
476 p = curproc; 477 if (p) { 478 register struct pstats *pstats; 479 480 /* 481 * Run current process's virtual and profile time, as needed. 482 */ 483 pstats = p->p_stats; --- 188 unchanged lines hidden (view full) --- 672 } 673 CPU_CLOCKUPDATE(&time, &newtime); 674 } 675 676 /* 677 * Process callouts at a very low cpu priority, so we don't keep the 678 * relatively high clock interrupt priority any longer than necessary. 679 */ | 460 p = curproc; 461 if (p) { 462 register struct pstats *pstats; 463 464 /* 465 * Run current process's virtual and profile time, as needed. 466 */ 467 pstats = p->p_stats; --- 188 unchanged lines hidden (view full) --- 656 } 657 CPU_CLOCKUPDATE(&time, &newtime); 658 } 659 660 /* 661 * Process callouts at a very low cpu priority, so we don't keep the 662 * relatively high clock interrupt priority any longer than necessary. 663 */ |
680 if (needsoft) { | 664 if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) { |
681 if (CLKF_BASEPRI(frame)) { 682 /* 683 * Save the overhead of a software interrupt; 684 * it will happen as soon as we return, so do it now. 685 */ 686 (void)splsoftclock(); 687 softclock(); 688 } else 689 setsoftclock(); | 665 if (CLKF_BASEPRI(frame)) { 666 /* 667 * Save the overhead of a software interrupt; 668 * it will happen as soon as we return, so do it now. 669 */ 670 (void)splsoftclock(); 671 softclock(); 672 } else 673 setsoftclock(); |
674 } else if (softticks + 1 == ticks) { 675 ++softticks; |
|
690 } 691} 692 693/* | 676 } 677} 678 679/* |
680 * The callout mechanism is based on the work of Adam M. Costello and 681 * George Varghese, published in a technical report entitled "Redesigning 682 * the BSD Callout and Timer Facilities" and modified slightly for inclusion 683 * in FreeBSD by Justin T. Gibbs. The original work on the data structures 684 * used in this implementation was published by G.Varghese and A. Lauck in 685 * the paper "Hashed and Hierarchical Timing Wheels: Data Structures for 686 * the Efficient Implementation of a Timer Facility" in the Proceedings of 687 * the 11th ACM Annual Symposium on Operating Systems Principles, 688 * Austin, Texas Nov 1987. 689 */ 690/* |
|
694 * Software (low priority) clock interrupt. 695 * Run periodic events from timeout queue. 696 */ 697/*ARGSUSED*/ 698void 699softclock() 700{ 701 register struct callout *c; | 691 * Software (low priority) clock interrupt. 692 * Run periodic events from timeout queue. 693 */ 694/*ARGSUSED*/ 695void 696softclock() 697{ 698 register struct callout *c; |
702 register void *arg; 703 register void (*func) __P((void *)); | |
704 register int s; | 699 register int s; |
700 register int steps; /* 701 * Number of steps taken since 702 * we last allowed interrupts. 703 */ |
|
705 | 704 |
705 #ifndef MAX_SOFTCLOCK_STEPS 706 #define MAX_SOFTCLOCK_STEPS 100 /* Maximum allowed value of steps. */ 707 #endif /* MAX_SOFTCLOCK_STEPS */ 708 709 steps = 0; |
|
706 s = splhigh(); | 710 s = splhigh(); |
707 while ((c = calltodo.c_next) != NULL && c->c_time <= 0) { 708 func = c->c_func; 709 arg = c->c_arg; 710 calltodo.c_next = c->c_next; 711 c->c_next = callfree; 712 callfree = c; 713 splx(s); 714 (*func)(arg); 715 (void) splhigh(); | 711 while (softticks != ticks) { 712 c = TAILQ_FIRST(&callwheel[++softticks & callwheelmask]); 713 while (c) { 714 if (c->c_time > 0) { 715 c->c_time--; 716 c = TAILQ_NEXT(c, c_links.tqe); 717 ++steps; 718 if (steps >= MAX_SOFTCLOCK_STEPS) { 719 nextsoftcheck = c; 720 splx(s); 721 /* Give hardclock() a chance. */ 722 s = splhigh(); 723 c = nextsoftcheck; 724 steps = 0; 725 } 726 } else { 727 void (*c_func)(void *); 728 void *c_arg; 729 730 nextsoftcheck = TAILQ_NEXT(c, c_links.tqe); 731 TAILQ_REMOVE(c->c_bucket, c, c_links.tqe); 732 c_func = c->c_func; 733 c_arg = c->c_arg; 734 c->c_func = NULL; 735 SLIST_INSERT_HEAD(&callfree, c, c_links.sle); 736 splx(s); 737 c_func(c_arg); 738 s = splhigh(); 739 steps = 0; 740 c = nextsoftcheck; 741 } 742 } |
716 } | 743 } |
744 nextsoftcheck = NULL; |
|
717 splx(s); 718} 719 720/* 721 * timeout -- 722 * Execute a function after a specified length of time. 723 * 724 * untimeout -- 725 * Cancel previous timeout function call. 726 * | 745 splx(s); 746} 747 748/* 749 * timeout -- 750 * Execute a function after a specified length of time. 751 * 752 * untimeout -- 753 * Cancel previous timeout function call. 754 * |
755 * callout_handle_init -- 756 * Initialize a handle so that using it with untimeout is benign. 757 * |
|
727 * See AT&T BCI Driver Reference Manual for specification. This | 758 * See AT&T BCI Driver Reference Manual for specification. This |
728 * implementation differs from that one in that no identification 729 * value is returned from timeout, rather, the original arguments 730 * to timeout are used to identify entries for untimeout. | 759 * implementation differs from that one in that although an 760 * identification value is returned from timeout, the original 761 * arguments to timeout as well as the identifier are used to 762 * identify entries for untimeout. |
731 */ | 763 */ |
732void 733timeout(ftn, arg, ticks) | 764struct callout_handle 765timeout(ftn, arg, to_ticks) |
734 timeout_t ftn; 735 void *arg; | 766 timeout_t ftn; 767 void *arg; |
736 register int ticks; | 768 register int to_ticks; |
737{ | 769{ |
738 register struct callout *new, *p, *t; 739 register int s; | 770 int s; 771 struct callout *new; 772 struct callout_handle handle; |
740 | 773 |
741 if (ticks <= 0) 742 ticks = 1; | 774 if (to_ticks <= 0) 775 to_ticks = 1; |
743 744 /* Lock out the clock. */ 745 s = splhigh(); 746 747 /* Fill in the next free callout structure. */ | 776 777 /* Lock out the clock. */ 778 s = splhigh(); 779 780 /* Fill in the next free callout structure. */ |
748 if (callfree == NULL) | 781 new = SLIST_FIRST(&callfree); 782 if (new == NULL) 783 /* XXX Attempt to malloc first */ |
749 panic("timeout table full"); | 784 panic("timeout table full"); |
750 new = callfree; 751 callfree = new->c_next; | 785 786 SLIST_REMOVE_HEAD(&callfree, c_links.sle); |
752 new->c_arg = arg; 753 new->c_func = ftn; | 787 new->c_arg = arg; 788 new->c_func = ftn; |
789 new->c_time = to_ticks >> callwheelbits; 790 new->c_bucket = &callwheel[(ticks + to_ticks) & callwheelmask]; 791 TAILQ_INSERT_TAIL(new->c_bucket, new, c_links.tqe); |
|
754 | 792 |
755 /* 756 * The time for each event is stored as a difference from the time 757 * of the previous event on the queue. Walk the queue, correcting 758 * the ticks argument for queue entries passed. Correct the ticks 759 * value for the queue entry immediately after the insertion point 760 * as well. Watch out for negative c_time values; these represent 761 * overdue events. 762 */ 763 for (p = &calltodo; 764 (t = p->c_next) != NULL && ticks > t->c_time; p = t) 765 if (t->c_time > 0) 766 ticks -= t->c_time; 767 new->c_time = ticks; 768 if (t != NULL) 769 t->c_time -= ticks; 770 771 /* Insert the new entry into the queue. */ 772 p->c_next = new; 773 new->c_next = t; | |
774 splx(s); | 793 splx(s); |
794 handle.callout = new; 795 return (handle); |
|
775} 776 777void | 796} 797 798void |
778untimeout(ftn, arg) | 799untimeout(ftn, arg, handle) |
779 timeout_t ftn; 780 void *arg; | 800 timeout_t ftn; 801 void *arg; |
802 struct callout_handle handle; |
|
781{ 782 register struct callout *p, *t; 783 register int s; 784 | 803{ 804 register struct callout *p, *t; 805 register int s; 806 |
785 s = splhigh(); 786 for (p = &calltodo; (t = p->c_next) != NULL; p = t) 787 if (t->c_func == ftn && t->c_arg == arg) { 788 /* Increment next entry's tick count. */ 789 if (t->c_next && t->c_time > 0) 790 t->c_next->c_time += t->c_time; | 807 /* 808 * Check for a handle that was initialized 809 * by callout_handle_init, but never used 810 * for a real timeout. 811 */ 812 if (handle.callout == NULL) 813 return; |
791 | 814 |
792 /* Move entry from callout queue to callfree queue. */ 793 p->c_next = t->c_next; 794 t->c_next = callfree; 795 callfree = t; 796 break; | 815 s = splhigh(); 816 if ((handle.callout->c_func == ftn) 817 && (handle.callout->c_arg == arg)) { 818 if (nextsoftcheck == handle.callout) { 819 nextsoftcheck = TAILQ_NEXT(handle.callout, c_links.tqe); |
797 } | 820 } |
821 TAILQ_REMOVE(handle.callout->c_bucket, 822 handle.callout, c_links.tqe); 823 handle.callout->c_func = NULL; 824 SLIST_INSERT_HEAD(&callfree, handle.callout, c_links.sle); 825 } |
|
798 splx(s); 799} 800 801void | 826 splx(s); 827} 828 829void |
830callout_handle_init(struct callout_handle *handle) 831{ 832 handle->callout = NULL; 833} 834 835void |
|
802gettime(struct timeval *tvp) 803{ 804 int s; 805 806 s = splclock(); 807 /* XXX should use microtime() iff tv_usec is used. */ 808 *tvp = time; 809 splx(s); --- 494 unchanged lines hidden --- | 836gettime(struct timeval *tvp) 837{ 838 int s; 839 840 s = splclock(); 841 /* XXX should use microtime() iff tv_usec is used. */ 842 *tvp = time; 843 splx(s); --- 494 unchanged lines hidden --- |