1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** rpcclock.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** Routines for manipulating the time entities understood by the rpc_timer 90** services. 91** 92** 93*/ 94 95#include <commonp.h> 96 97 98/* ========================================================================= */ 99 100GLOBAL rpc_clock_t rpc_g_clock_curr; 101GLOBAL rpc_clock_unix_t rpc_g_clock_unix_curr; 102 103EXTERNAL boolean32 rpc_g_long_sleep; 104 105INTERNAL struct timeval start_time = { 0, 0 }; 106INTERNAL rpc_clock_t rpc_clock_skew = 0; 107 108/* ========================================================================= */ 109 110/* 111 * R P C _ _ C L O C K _ S T A M P 112 * 113 * Timestamp a data structure with the current approximate tick count. 114 * The tick count returned is only updated by the rpc_timer routines 115 * once each time through the select listen loop. This degree of accuracy 116 * should be adequate for the purpose of tracking the age of a data 117 * structure. 118 */ 119 120PRIVATE rpc_clock_t rpc__clock_stamp(void) 121{ 122 if (rpc_g_long_sleep) 123 rpc__clock_update(); 124 125 return( rpc_g_clock_curr ); 126} 127 128/* 129 * R P C _ _ C L O C K _ A G E D 130 * 131 * A routine to determine whether a specified timestamp has aged. 132 */ 133 134PRIVATE boolean rpc__clock_aged 135( 136 rpc_clock_t time, 137 rpc_clock_t interval 138) 139{ 140 return( rpc_g_clock_curr >= (time + interval) ); 141} 142 143/* 144 * R P C _ _ C L O C K _ U N I X _ E X P I R E D 145 * 146 * Determine whether a specified UNIX timestamp is in the past. 147 */ 148 149PRIVATE boolean rpc__clock_unix_expired 150( 151 rpc_clock_unix_t time 152) 153{ 154 return( rpc_g_clock_unix_curr >= time ); 155} 156 157/* 158 * R P C _ _ C L O C K _ U P D A T E 159 * 160 * Update the current tick count. This routine is the only one that 161 * actually makes system calls to obtain the time. 162 */ 163 164PRIVATE void rpc__clock_update(void) 165{ 166 167 struct timeval tp; 168 time_t ticks; 169 170 /* 171 * On startup, just initialize start time. Arrange for the initial 172 * time to be '1' tick (0 can be confusing in some cases). 173 */ 174 if (start_time.tv_sec == 0) 175 { 176 gettimeofday( &start_time, (struct timezone *) 0 ); 177 rpc_g_clock_unix_curr = start_time.tv_sec; 178 start_time.tv_usec -= (1000000L/RPC_C_CLOCK_HZ); 179 if (start_time.tv_usec < 0) 180 { 181 start_time.tv_usec += 1000000L; 182 start_time.tv_sec --; 183 } 184 rpc_g_clock_curr = (rpc_clock_t) 1; 185 } 186 else 187 { 188 /* 189 * Get the time of day from the system, and convert it to the 190 * tick count format we're using (RPC_C_CLOCK_HZ ticks per second). 191 * For now, just use 1 second accuracy. 192 */ 193 gettimeofday(&tp, (struct timezone *) 0 ); 194 rpc_g_clock_unix_curr = tp.tv_sec; 195 196 ticks = (tp.tv_sec - start_time.tv_sec) * RPC_C_CLOCK_HZ + 197 rpc_clock_skew; 198 199 if (tp.tv_usec < start_time.tv_usec) 200 { 201 ticks -= RPC_C_CLOCK_HZ; 202 tp.tv_usec += 1000000L; 203 } 204 ticks += (tp.tv_usec - start_time.tv_usec) / (1000000L/RPC_C_CLOCK_HZ); 205 206 /* 207 * We need to watch out for changes to the system time after we 208 * have stored away our starting time value. This situation is 209 * handled by maintaining a static variable containing the amount of 210 * RPC_C_CLOCK_HZ's we believe that the current time has been altered. 211 * This variable gets updated each time we detect that the system time 212 * has been modified. 213 * 214 * This scheme takes into account the fact that there are data 215 * structures that have been timestamped with tick counts; it is 216 * not possible to simply start the tick count over, of to just 217 * update the trigger counts in the list of periodic funtions. 218 * 219 * We determine that the system time has been modified if 1) the 220 * tick count has gone backward, or 2) if we notice that we haven't 221 * been called in 60 seconds. This last condition is based on the 222 * assumption that the listen loop will never intentionally wait 223 * that long before calling us. It would also be possible (tho more 224 * complicated) to look at the trigger count of the next periodic 225 * routine and assume that if we've gone a couple of seconds past 226 * that then something's wrong. 227 */ 228 if ( (ticks < rpc_g_clock_curr) || 229 (ticks > (rpc_g_clock_curr + RPC_CLOCK_SEC(60)))) 230 { 231 rpc_clock_skew += rpc_g_clock_curr - ticks + RPC_C_CLOCK_HZ; 232 rpc_g_clock_curr += RPC_C_CLOCK_HZ; 233 } 234 else 235 { 236 rpc_g_clock_curr = (rpc_clock_t) ticks; 237 } 238 } 239} 240 241/* 242 * R P C _ _ C L O C K _ T I M E S P E C 243 * 244 * Return a "struct timespec" equivalent to a given rpc_clock_t. 245 */ 246 247PRIVATE void rpc__clock_timespec 248( 249 rpc_clock_t clock, 250 struct timespec *ts 251) 252{ 253 int whole_secs; 254 int remaining_ticks; 255 256 clock -= rpc_clock_skew; 257 258 whole_secs = (int)clock / RPC_C_CLOCK_HZ; 259 remaining_ticks = (int)clock % RPC_C_CLOCK_HZ; 260 if (remaining_ticks < 0) 261 { 262 whole_secs--; 263 remaining_ticks += RPC_C_CLOCK_HZ; 264 } 265 266 ts->tv_sec = start_time.tv_sec + whole_secs; 267 ts->tv_nsec = (1000 * start_time.tv_usec) + 268 remaining_ticks * (1000000000 / RPC_C_CLOCK_HZ); 269 if (ts->tv_nsec >= 1000000000) 270 { 271 ts->tv_nsec -= 1000000000; 272 ts->tv_sec += 1; 273 } 274} 275