- Timestamp:
- Apr 9, 2006 10:37:09 AM (19 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjlib/src/pj/os_timestamp_win32.c
r125 r396 18 18 */ 19 19 #include <pj/os.h> 20 #include <pj/assert.h> 20 21 #include <pj/errno.h> 22 #include <pj/log.h> 21 23 #include <windows.h> 24 25 #define THIS_FILE "os_timestamp_win32.c" 26 27 28 #if 1 29 # define TRACE_(x) PJ_LOG(3,x) 30 #else 31 # define TRACE_(x) ; 32 #endif 33 34 35 ///////////////////////////////////////////////////////////////////////////// 22 36 23 37 #if defined(PJ_TIMESTAMP_USE_RDTSC) && PJ_TIMESTAMP_USE_RDTSC!=0 && \ … … 95 109 } 96 110 111 ///////////////////////////////////////////////////////////////////////////// 112 113 #elif defined(PJ_TIMESTAMP_WIN32_USE_SAFE_QPC) && \ 114 PJ_TIMESTAMP_WIN32_USE_SAFE_QPC!=0 115 116 /* Use safe QueryPerformanceCounter. 117 * This implementation has some protection against bug in KB Q274323: 118 * Performance counter value may unexpectedly leap forward 119 * http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323 120 * 121 * THIS SHOULD NOT BE USED YET AS IT DOESN'T HANDLE SYSTEM TIME 122 * CHANGE. 123 */ 124 125 static pj_timestamp g_ts_freq; 126 static pj_timestamp g_ts_base; 127 static pj_int64_t g_time_base; 128 129 PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) 130 { 131 enum { MAX_RETRY = 10 }; 132 unsigned i; 133 134 135 /* pj_get_timestamp_freq() must have been called before. 136 * This is done when application called pj_init(). 137 */ 138 pj_assert(g_ts_freq.u64 != 0); 139 140 /* Retry QueryPerformanceCounter() until we're sure that the 141 * value returned makes sense. 142 */ 143 i = 0; 144 do { 145 LARGE_INTEGER val; 146 pj_int64_t counter64, time64, diff; 147 pj_time_val time_now; 148 149 /* Retrieve the counter */ 150 if (!QueryPerformanceCounter(&val)) 151 return PJ_RETURN_OS_ERROR(GetLastError()); 152 153 /* Regardless of the goodness of the value, we should put 154 * the counter here, because normally application wouldn't 155 * check the error result of this function. 156 */ 157 ts->u64 = val.QuadPart; 158 159 /* Retrieve time */ 160 pj_gettimeofday(&time_now); 161 162 /* Get the counter elapsed time in miliseconds */ 163 counter64 = (val.QuadPart - g_ts_base.u64) * 1000 / g_ts_freq.u64; 164 165 /* Get the time elapsed in miliseconds. 166 * We don't want to use PJ_TIME_VAL_MSEC() since it's using 167 * 32bit calculation, which limits the maximum elapsed time 168 * to around 49 days only. 169 */ 170 time64 = time_now.sec; 171 time64 = time64 * 1000 + time_now.msec; 172 //time64 = GetTickCount(); 173 174 /* It's good if the difference between two clocks are within 175 * some compile time constant (default: 20ms, which to allow 176 * context switch happen between QueryPerformanceCounter and 177 * pj_gettimeofday()). 178 */ 179 diff = (time64 - g_time_base) - counter64; 180 if (diff >= -20 && diff <= 20) { 181 /* It's good */ 182 return PJ_SUCCESS; 183 } 184 185 ++i; 186 187 } while (i < MAX_RETRY); 188 189 TRACE_((THIS_FILE, "QueryPerformanceCounter returned bad value")); 190 return PJ_ETIMEDOUT; 191 } 192 193 static pj_status_t init_performance_counter(void) 194 { 195 LARGE_INTEGER val; 196 pj_time_val time_base; 197 pj_status_t status; 198 199 /* Get the frequency */ 200 if (!QueryPerformanceFrequency(&val)) 201 return PJ_RETURN_OS_ERROR(GetLastError()); 202 203 g_ts_freq.u64 = val.QuadPart; 204 205 /* Get the base timestamp */ 206 if (!QueryPerformanceCounter(&val)) 207 return PJ_RETURN_OS_ERROR(GetLastError()); 208 209 g_ts_base.u64 = val.QuadPart; 210 211 212 /* Get the base time */ 213 status = pj_gettimeofday(&time_base); 214 if (status != PJ_SUCCESS) 215 return status; 216 217 /* Convert time base to 64bit value in msec */ 218 g_time_base = time_base.sec; 219 g_time_base = g_time_base * 1000 + time_base.msec; 220 //g_time_base = GetTickCount(); 221 222 return PJ_SUCCESS; 223 } 224 225 PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) 226 { 227 if (g_ts_freq.u64 == 0) { 228 enum { MAX_REPEAT = 10 }; 229 unsigned i; 230 pj_status_t status; 231 232 /* Make unellegant compiler happy */ 233 status = 0; 234 235 /* Repeat initializing performance counter until we're sure 236 * the base timing is correct. It is possible that the system 237 * returns bad counter during this initialization! 238 */ 239 for (i=0; i<MAX_REPEAT; ++i) { 240 241 pj_timestamp dummy; 242 243 /* Init base time */ 244 status = init_performance_counter(); 245 if (status != PJ_SUCCESS) 246 return status; 247 248 /* Try the base time */ 249 status = pj_get_timestamp(&dummy); 250 if (status == PJ_SUCCESS) 251 break; 252 } 253 254 if (status != PJ_SUCCESS) 255 return status; 256 } 257 258 freq->u64 = g_ts_freq.u64; 259 return PJ_SUCCESS; 260 } 261 262 ///////////////////////////////////////////////////////////////////////////// 263 97 264 #else 265 98 266 /* 99 267 * Use QueryPerformanceCounter and QueryPerformanceFrequency. 268 * This should be the default implementation to be used on Windows. 100 269 */ 101 270 PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) … … 121 290 } 122 291 292 123 293 #endif /* PJ_TIMESTAMP_USE_RDTSC */ 124 294
Note: See TracChangeset
for help on using the changeset viewer.