⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_timestamp_win32.c

📁 基于sip协议的网络电话源码
💻 C
字号:
/* $Id: os_timestamp_win32.c 974 2007-02-19 01:13:53Z bennylp $ *//*  * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pj/os.h>#include <pj/assert.h>#include <pj/errno.h>#include <pj/log.h>#include <windows.h>#define THIS_FILE   "os_timestamp_win32.c"#if 1#   define TRACE_(x)	    PJ_LOG(3,x)#else#   define TRACE_(x)	    ;#endif/////////////////////////////////////////////////////////////////////////////#if defined(PJ_TIMESTAMP_USE_RDTSC) && PJ_TIMESTAMP_USE_RDTSC!=0 && \    defined(PJ_M_I386) && PJ_M_I386 != 0 && \    defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0 && \    defined(_MSC_VER)/* * Use rdtsc to get the OS timestamp. */static LONG CpuMhz;static pj_int64_t CpuHz; static pj_status_t GetCpuHz(void){    HKEY key;    LONG rc;    DWORD size;#if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0    rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,		      L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",		      0, 0, &key);#else    rc = RegOpenKey( HKEY_LOCAL_MACHINE,		     "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",		     &key);#endif    if (rc != ERROR_SUCCESS)	return PJ_RETURN_OS_ERROR(rc);    size = sizeof(CpuMhz);    rc = RegQueryValueEx(key, "~MHz", NULL, NULL, (BYTE*)&CpuMhz, &size);    RegCloseKey(key);    if (rc != ERROR_SUCCESS) {	return PJ_RETURN_OS_ERROR(rc);    }    CpuHz = CpuMhz;    CpuHz = CpuHz * 1000000;    return PJ_SUCCESS;}/* __int64 is nicely returned in EDX:EAX */__declspec(naked) __int64 rdtsc() {    __asm     {	RDTSC	RET    }}PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts){    ts->u64 = rdtsc();    return PJ_SUCCESS;}PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq){    pj_status_t status;    if (CpuHz == 0) {	status = GetCpuHz();	if (status != PJ_SUCCESS)	    return status;    }    freq->u64 = CpuHz;    return PJ_SUCCESS;}/////////////////////////////////////////////////////////////////////////////#elif defined(PJ_TIMESTAMP_WIN32_USE_SAFE_QPC) && \         PJ_TIMESTAMP_WIN32_USE_SAFE_QPC!=0/* Use safe QueryPerformanceCounter. * This implementation has some protection against bug in KB Q274323: *   Performance counter value may unexpectedly leap forward *   http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323 * * THIS SHOULD NOT BE USED YET AS IT DOESN'T HANDLE SYSTEM TIME * CHANGE. */static pj_timestamp g_ts_freq;static pj_timestamp g_ts_base;static pj_int64_t   g_time_base;PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts){    enum { MAX_RETRY = 10 };    unsigned i;    /* pj_get_timestamp_freq() must have been called before.     * This is done when application called pj_init().     */    pj_assert(g_ts_freq.u64 != 0);    /* Retry QueryPerformanceCounter() until we're sure that the     * value returned makes sense.     */    i = 0;    do {	LARGE_INTEGER val;	pj_int64_t counter64, time64, diff;	pj_time_val time_now;	/* Retrieve the counter */	if (!QueryPerformanceCounter(&val))	    return PJ_RETURN_OS_ERROR(GetLastError());	/* Regardless of the goodness of the value, we should put	 * the counter here, because normally application wouldn't	 * check the error result of this function.	 */	ts->u64 = val.QuadPart;	/* Retrieve time */	pj_gettimeofday(&time_now);	/* Get the counter elapsed time in miliseconds */	counter64 = (val.QuadPart - g_ts_base.u64) * 1000 / g_ts_freq.u64;		/* Get the time elapsed in miliseconds. 	 * We don't want to use PJ_TIME_VAL_MSEC() since it's using	 * 32bit calculation, which limits the maximum elapsed time	 * to around 49 days only.	 */	time64 = time_now.sec;	time64 = time64 * 1000 + time_now.msec;	//time64 = GetTickCount();	/* It's good if the difference between two clocks are within	 * some compile time constant (default: 20ms, which to allow	 * context switch happen between QueryPerformanceCounter and	 * pj_gettimeofday()).	 */	diff = (time64 - g_time_base) - counter64;	if (diff >= -20 && diff <= 20) {	    /* It's good */	    return PJ_SUCCESS;	}	++i;    } while (i < MAX_RETRY);    TRACE_((THIS_FILE, "QueryPerformanceCounter returned bad value"));    return PJ_ETIMEDOUT;}static pj_status_t init_performance_counter(void){    LARGE_INTEGER val;    pj_time_val time_base;    pj_status_t status;    /* Get the frequency */    if (!QueryPerformanceFrequency(&val))	return PJ_RETURN_OS_ERROR(GetLastError());    g_ts_freq.u64 = val.QuadPart;    /* Get the base timestamp */    if (!QueryPerformanceCounter(&val))	return PJ_RETURN_OS_ERROR(GetLastError());    g_ts_base.u64 = val.QuadPart;    /* Get the base time */    status = pj_gettimeofday(&time_base);    if (status != PJ_SUCCESS)	return status;    /* Convert time base to 64bit value in msec */    g_time_base = time_base.sec;    g_time_base  = g_time_base * 1000 + time_base.msec;    //g_time_base = GetTickCount();    return PJ_SUCCESS;}PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq){    if (g_ts_freq.u64 == 0) {	enum { MAX_REPEAT = 10 };	unsigned i;	pj_status_t status;	/* Make unellegant compiler happy */	status = 0;	/* Repeat initializing performance counter until we're sure	 * the base timing is correct. It is possible that the system	 * returns bad counter during this initialization!	 */	for (i=0; i<MAX_REPEAT; ++i) {	    pj_timestamp dummy;	    /* Init base time */	    status = init_performance_counter();	    if (status != PJ_SUCCESS)		return status;	    /* Try the base time */	    status = pj_get_timestamp(&dummy);	    if (status == PJ_SUCCESS)		break;	}	if (status != PJ_SUCCESS)	    return status;    }    freq->u64 = g_ts_freq.u64;    return PJ_SUCCESS;}/////////////////////////////////////////////////////////////////////////////#else/* * Use QueryPerformanceCounter and QueryPerformanceFrequency. * This should be the default implementation to be used on Windows. */PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts){    LARGE_INTEGER val;    if (!QueryPerformanceCounter(&val))	return PJ_RETURN_OS_ERROR(GetLastError());    ts->u64 = val.QuadPart;    return PJ_SUCCESS;}PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq){    LARGE_INTEGER val;    if (!QueryPerformanceFrequency(&val))	return PJ_RETURN_OS_ERROR(GetLastError());    freq->u64 = val.QuadPart;    return PJ_SUCCESS;}#endif	/* PJ_TIMESTAMP_USE_RDTSC */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -