Line data Source code
1 : /* 2 : Mosh: the mobile shell 3 : Copyright 2012 Keith Winstein 4 : 5 : This program is free software: you can redistribute it and/or modify 6 : it under the terms of the GNU General Public License as published by 7 : the Free Software Foundation, either version 3 of the License, or 8 : (at your option) any later version. 9 : 10 : This program is distributed in the hope that it will be useful, 11 : but WITHOUT ANY WARRANTY; without even the implied warranty of 12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 : GNU General Public License for more details. 14 : 15 : You should have received a copy of the GNU General Public License 16 : along with this program. If not, see <http://www.gnu.org/licenses/>. 17 : 18 : In addition, as a special exception, the copyright holders give 19 : permission to link the code of portions of this program with the 20 : OpenSSL library under certain conditions as described in each 21 : individual source file, and distribute linked combinations including 22 : the two. 23 : 24 : You must obey the GNU General Public License in all respects for all 25 : of the code used other than OpenSSL. If you modify file(s) with this 26 : exception, you may extend this exception to your version of the 27 : file(s), but you are not obligated to do so. If you do not wish to do 28 : so, delete this exception statement from your version. If you delete 29 : this exception statement from all source files in the program, then 30 : also delete it here. 31 : */ 32 : 33 : #include "config.h" 34 : 35 : #include "timestamp.h" 36 : 37 : #include <errno.h> 38 : 39 : #if HAVE_CLOCK_GETTIME 40 : #include <time.h> 41 : #endif 42 : #if HAVE_MACH_ABSOLUTE_TIME 43 : #include <mach/error.h> 44 : #include <mach/mach_time.h> 45 : #endif 46 : #if HAVE_GETTIMEOFDAY 47 : #include <sys/time.h> 48 : #include <stdio.h> 49 : #endif 50 : 51 : // On Apple systems CLOCK_MONOTONIC is unfortunately able to go 52 : // backwards in time. This breaks mosh when system is returning from 53 : // suspend as described in ticket #1014. To avoid this issue prefer 54 : // CLOCK_MONOTONIC_RAW on Apple systems when available. 55 : #if defined(__APPLE__) && defined(CLOCK_MONOTONIC_RAW) 56 : #define CLOCKTYPE CLOCK_MONOTONIC_RAW 57 : #else 58 : #define CLOCKTYPE CLOCK_MONOTONIC 59 : #endif 60 : 61 : static uint64_t millis_cache = -1; 62 : 63 335721 : uint64_t frozen_timestamp( void ) 64 : { 65 335721 : if ( millis_cache == uint64_t( -1 ) ) { 66 900 : freeze_timestamp(); 67 : } 68 : 69 335721 : return millis_cache; 70 : } 71 : 72 34032 : void freeze_timestamp( void ) 73 : { 74 : // Try all our clock sources till we get something. This could 75 : // break if a source only sometimes works in a given process. 76 : #if HAVE_CLOCK_GETTIME 77 : // Preferred clock source-- portable, monotonic, (should be) 78 : // adjusted after system sleep 79 34032 : struct timespec tp; 80 : 81 34032 : if ( 82 : #if defined(__APPLE__) && defined(__MACH__) 83 : // Check for presence, for OS X SDK >= 10.12 and runtime < 10.12 84 : &clock_gettime != NULL && 85 : #endif 86 34032 : clock_gettime( CLOCKTYPE, &tp ) == 0 ) { 87 34032 : uint64_t millis = tp.tv_nsec / 1000000; 88 34032 : millis += uint64_t( tp.tv_sec ) * 1000; 89 : 90 34032 : millis_cache = millis; 91 34032 : return; 92 : } 93 : #endif 94 : #if HAVE_MACH_ABSOLUTE_TIME 95 : // Monotonic, not adjusted after system sleep. OS X 10.12 has 96 : // mach_continuous_time(), but also has clock_gettime(). 97 : static mach_timebase_info_data_t s_timebase_info; 98 : static double absolute_to_millis = 0.0; 99 : 100 : if (absolute_to_millis == 0.0) { 101 : if (ERR_SUCCESS == mach_timebase_info(&s_timebase_info)) { 102 : absolute_to_millis = 1e-6 * s_timebase_info.numer / s_timebase_info.denom; 103 : } else 104 : absolute_to_millis = -1.0; 105 : } 106 : 107 : // NB: mach_absolute_time() returns "absolute time units" 108 : // We need to apply a conversion to get milliseconds. 109 : if (absolute_to_millis > 0.0) { 110 : millis_cache = mach_absolute_time() * absolute_to_millis; 111 : return; 112 : } 113 : #endif 114 : #if HAVE_GETTIMEOFDAY 115 : // Not monotonic. 116 : // NOTE: If time steps backwards, timeouts may be confused. 117 0 : struct timeval tv; 118 0 : if ( gettimeofday(&tv, NULL) ) { 119 0 : perror( "gettimeofday" ); 120 : } else { 121 0 : uint64_t millis = tv.tv_usec / 1000; 122 0 : millis += uint64_t( tv.tv_sec ) * 1000; 123 : 124 0 : millis_cache = millis; 125 0 : return; 126 : } 127 : #else 128 : # error "gettimeofday() unavailable-- required as timer of last resort" 129 : #endif 130 : }