mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-21 15:19:34 -05:00
ITS#8295 fix Windows microsecond timer
Also add ldap_pvt_gettimeofday() to emulate gettimeofday on Windows
This commit is contained in:
parent
291b6a1a22
commit
597ce61000
2 changed files with 153 additions and 44 deletions
|
|
@ -127,6 +127,12 @@ struct lutil_tm;
|
||||||
LDAP_F( void )
|
LDAP_F( void )
|
||||||
ldap_pvt_gettime LDAP_P(( struct lutil_tm * ));
|
ldap_pvt_gettime LDAP_P(( struct lutil_tm * ));
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define gettimeofday(tv,tz) ldap_pvt_gettimeofday(tv,tz)
|
||||||
|
LDAP_F( int )
|
||||||
|
ldap_pvt_gettimeofday LDAP_P(( struct timeval *tv, void *unused ));
|
||||||
|
#endif
|
||||||
|
|
||||||
/* use this macro to allocate buffer for ldap_pvt_csnstr */
|
/* use this macro to allocate buffer for ldap_pvt_csnstr */
|
||||||
#define LDAP_PVT_CSNSTR_BUFSIZE 64
|
#define LDAP_PVT_CSNSTR_BUFSIZE 64
|
||||||
LDAP_F( size_t )
|
LDAP_F( size_t )
|
||||||
|
|
|
||||||
|
|
@ -174,93 +174,195 @@ ldap_pvt_localtime( const time_t *timep, struct tm *result )
|
||||||
}
|
}
|
||||||
#endif /* !USE_LOCALTIME_R */
|
#endif /* !USE_LOCALTIME_R */
|
||||||
|
|
||||||
/* return a broken out time, with microseconds
|
static int _ldap_pvt_gt_subs;
|
||||||
*/
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* Windows SYSTEMTIME only has 10 millisecond resolution, so we
|
/* Windows SYSTEMTIME only has 10 millisecond resolution, so we
|
||||||
* also need to use a high resolution timer to get microseconds.
|
* also need to use a high resolution timer to get microseconds.
|
||||||
* This is pretty clunky.
|
* This is pretty clunky.
|
||||||
*/
|
*/
|
||||||
void
|
static LARGE_INTEGER _ldap_pvt_gt_freq;
|
||||||
ldap_pvt_gettime( struct lutil_tm *tm )
|
static LARGE_INTEGER _ldap_pvt_gt_prev;
|
||||||
{
|
static int _ldap_pvt_gt_offset;
|
||||||
static LARGE_INTEGER cFreq;
|
|
||||||
static LARGE_INTEGER prevCount;
|
#define SEC_TO_UNIX_EPOCH 11644473600LL
|
||||||
static int subs;
|
#define TICKS_PER_SECOND 10000000
|
||||||
static int offset;
|
|
||||||
LARGE_INTEGER count;
|
static int
|
||||||
SYSTEMTIME st;
|
ldap_pvt_gettimeusec(int *sec)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER count;
|
||||||
|
|
||||||
GetSystemTime( &st );
|
|
||||||
QueryPerformanceCounter( &count );
|
QueryPerformanceCounter( &count );
|
||||||
|
|
||||||
/* It shouldn't ever go backwards, but multiple CPUs might
|
/* It shouldn't ever go backwards, but multiple CPUs might
|
||||||
* be able to hit in the same tick.
|
* be able to hit in the same tick.
|
||||||
*/
|
*/
|
||||||
LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
|
LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
|
||||||
if ( count.QuadPart <= prevCount.QuadPart ) {
|
|
||||||
subs++;
|
|
||||||
} else {
|
|
||||||
subs = 0;
|
|
||||||
prevCount = count;
|
|
||||||
}
|
|
||||||
LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
|
|
||||||
|
|
||||||
/* We assume Windows has at least a vague idea of
|
/* We assume Windows has at least a vague idea of
|
||||||
* when a second begins. So we align our microsecond count
|
* when a second begins. So we align our microsecond count
|
||||||
* with the Windows millisecond count using this offset.
|
* with the Windows millisecond count using this offset.
|
||||||
* We retain the submillisecond portion of our own count.
|
* We retain the submillisecond portion of our own count.
|
||||||
*
|
*
|
||||||
* Note - this also assumes that the relationship between
|
* Note - this also assumes that the relationship between
|
||||||
* the PerformanceCouunter and SystemTime stays constant;
|
* the PerformanceCounter and SystemTime stays constant;
|
||||||
* that assumption breaks if the SystemTime is adjusted by
|
* that assumption breaks if the SystemTime is adjusted by
|
||||||
* an external action.
|
* an external action.
|
||||||
*/
|
*/
|
||||||
if ( !cFreq.QuadPart ) {
|
if ( !_ldap_pvt_gt_freq.QuadPart ) {
|
||||||
|
LARGE_INTEGER c2;
|
||||||
|
ULARGE_INTEGER ut;
|
||||||
|
FILETIME ft0, ft1;
|
||||||
long long t;
|
long long t;
|
||||||
int usec;
|
int usec;
|
||||||
QueryPerformanceFrequency( &cFreq );
|
|
||||||
|
|
||||||
/* just get sub-second portion of counter */
|
/* Initialize our offset */
|
||||||
t = count.QuadPart % cFreq.QuadPart;
|
QueryPerformanceFrequency( &_ldap_pvt_gt_freq );
|
||||||
|
|
||||||
|
/* Wait for a tick of the system time: 10-15ms */
|
||||||
|
GetSystemTimeAsFileTime( &ft0 );
|
||||||
|
do {
|
||||||
|
GetSystemTimeAsFileTime( &ft1 );
|
||||||
|
} while ( ft1.dwLowDateTime == ft0.dwLowDateTime );
|
||||||
|
|
||||||
|
ut.LowPart = ft1.dwLowDateTime;
|
||||||
|
ut.HighPart = ft1.dwHighDateTime;
|
||||||
|
QueryPerformanceCounter( &c2 );
|
||||||
|
|
||||||
|
/* get second and fraction portion of counter */
|
||||||
|
t = c2.QuadPart % (_ldap_pvt_gt_freq.QuadPart*10);
|
||||||
|
|
||||||
/* convert to microseconds */
|
/* convert to microseconds */
|
||||||
t *= 1000000;
|
t *= 1000000;
|
||||||
usec = t / cFreq.QuadPart;
|
usec = t / _ldap_pvt_gt_freq.QuadPart;
|
||||||
|
|
||||||
offset = usec - st.wMilliseconds * 1000;
|
ut.QuadPart /= 10;
|
||||||
|
ut.QuadPart %= 10000000;
|
||||||
|
_ldap_pvt_gt_offset = usec - ut.QuadPart;
|
||||||
|
count = c2;
|
||||||
}
|
}
|
||||||
|
if ( count.QuadPart <= _ldap_pvt_gt_prev.QuadPart ) {
|
||||||
tm->tm_usub = subs;
|
_ldap_pvt_gt_subs++;
|
||||||
|
} else {
|
||||||
|
_ldap_pvt_gt_subs = 0;
|
||||||
|
_ldap_pvt_gt_prev = count;
|
||||||
|
}
|
||||||
|
LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
|
||||||
|
|
||||||
/* convert to microseconds */
|
/* convert to microseconds */
|
||||||
count.QuadPart %= cFreq.QuadPart;
|
count.QuadPart %= _ldap_pvt_gt_freq.QuadPart*10;
|
||||||
count.QuadPart *= 1000000;
|
count.QuadPart *= 1000000;
|
||||||
count.QuadPart /= cFreq.QuadPart;
|
count.QuadPart /= _ldap_pvt_gt_freq.QuadPart;
|
||||||
count.QuadPart -= offset;
|
count.QuadPart -= _ldap_pvt_gt_offset;
|
||||||
|
|
||||||
tm->tm_usec = count.QuadPart % 1000000;
|
/* We've extracted the 1s and microseconds.
|
||||||
if ( tm->tm_usec < 0 )
|
* The 1sec digit is used to detect wraparound in microsecnds.
|
||||||
tm->tm_usec += 1000000;
|
*/
|
||||||
|
if (count.QuadPart < 0)
|
||||||
|
count.QuadPart += 10000000;
|
||||||
|
else if (count.QuadPart >= 10000000)
|
||||||
|
count.QuadPart -= 10000000;
|
||||||
|
|
||||||
|
*sec = count.QuadPart / 1000000;
|
||||||
|
return count.QuadPart % 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* emulate POSIX gettimeofday */
|
||||||
|
int
|
||||||
|
ldap_pvt_gettimeofday( struct timeval *tv, void *unused )
|
||||||
|
{
|
||||||
|
FILETIME ft;
|
||||||
|
ULARGE_INTEGER ut;
|
||||||
|
int sec, sec0;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime( &ft );
|
||||||
|
ut.LowPart = ft.dwLowDateTime;
|
||||||
|
ut.HighPart = ft.dwHighDateTime;
|
||||||
|
|
||||||
|
/* convert to usec */
|
||||||
|
ut.QuadPart /= (TICKS_PER_SECOND / 1000000);
|
||||||
|
|
||||||
|
tv->tv_usec = ldap_pvt_gettimeusec(&sec);
|
||||||
|
tv->tv_sec = ut.QuadPart / 1000000 - SEC_TO_UNIX_EPOCH;
|
||||||
|
|
||||||
|
/* check for carry from microseconds */
|
||||||
|
sec0 = tv->tv_sec % 10;
|
||||||
|
if (sec0 < sec || (sec0 == 9 && !sec))
|
||||||
|
tv->tv_sec++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return a broken out time, with microseconds
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ldap_pvt_gettime( struct lutil_tm *tm )
|
||||||
|
{
|
||||||
|
SYSTEMTIME st;
|
||||||
|
int sec, sec0;
|
||||||
|
static const char daysPerMonth[] = {
|
||||||
|
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
GetSystemTime( &st );
|
||||||
|
tm->tm_usec = ldap_pvt_gettimeusec(&sec);
|
||||||
|
tm->tm_usub = _ldap_pvt_gt_subs;
|
||||||
|
|
||||||
/* any difference larger than microseconds is
|
/* any difference larger than microseconds is
|
||||||
* already reflected in st
|
* already reflected in st
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tm->tm_sec = st.wSecond;
|
tm->tm_sec = st.wSecond;
|
||||||
tm->tm_min = st.wMinute;
|
tm->tm_min = st.wMinute;
|
||||||
tm->tm_hour = st.wHour;
|
tm->tm_hour = st.wHour;
|
||||||
tm->tm_mday = st.wDay;
|
tm->tm_mday = st.wDay;
|
||||||
tm->tm_mon = st.wMonth - 1;
|
tm->tm_mon = st.wMonth - 1;
|
||||||
tm->tm_year = st.wYear - 1900;
|
tm->tm_year = st.wYear - 1900;
|
||||||
|
|
||||||
|
/* check for carry from microseconds */
|
||||||
|
sec0 = tm->tm_sec % 10;
|
||||||
|
if (sec0 < sec || (sec0 == 9 && !sec)) {
|
||||||
|
tm->tm_sec++;
|
||||||
|
/* FIXME: we don't handle leap seconds */
|
||||||
|
if (tm->tm_sec > 59) {
|
||||||
|
tm->tm_sec = 0;
|
||||||
|
tm->tm_min++;
|
||||||
|
if (tm->tm_min > 59) {
|
||||||
|
tm->tm_min = 0;
|
||||||
|
tm->tm_hour++;
|
||||||
|
if (tm->tm_hour > 23) {
|
||||||
|
int days = daysPerMonth[tm->tm_mon];
|
||||||
|
tm->tm_hour = 0;
|
||||||
|
tm->tm_mday++;
|
||||||
|
|
||||||
|
/* if it's February of a leap year,
|
||||||
|
* add 1 day to this month
|
||||||
|
*/
|
||||||
|
if (tm->tm_mon == 1 &&
|
||||||
|
((!(st.wYear % 4) && (st.wYear % 100)) ||
|
||||||
|
!(st.wYear % 400)))
|
||||||
|
days++;
|
||||||
|
|
||||||
|
if (tm->tm_mday > days) {
|
||||||
|
tm->tm_mday = 1;
|
||||||
|
tm->tm_mon++;
|
||||||
|
if (tm->tm_mon > 11) {
|
||||||
|
tm->tm_mon = 0;
|
||||||
|
tm->tm_year++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
static struct timeval _ldap_pvt_gt_prevTv;
|
||||||
|
|
||||||
void
|
void
|
||||||
ldap_pvt_gettime( struct lutil_tm *ltm )
|
ldap_pvt_gettime( struct lutil_tm *ltm )
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
static struct timeval prevTv;
|
|
||||||
static int subs;
|
|
||||||
|
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
time_t t;
|
time_t t;
|
||||||
|
|
@ -269,16 +371,17 @@ ldap_pvt_gettime( struct lutil_tm *ltm )
|
||||||
t = tv.tv_sec;
|
t = tv.tv_sec;
|
||||||
|
|
||||||
LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
|
LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
|
||||||
if ( tv.tv_sec < prevTv.tv_sec
|
if ( tv.tv_sec < _ldap_pvt_gt_prevTv.tv_sec
|
||||||
|| ( tv.tv_sec == prevTv.tv_sec && tv.tv_usec <= prevTv.tv_usec )) {
|
|| ( tv.tv_sec == _ldap_pvt_gt_prevTv.tv_sec
|
||||||
subs++;
|
&& tv.tv_usec <= _ldap_pvt_gt_prevTv.tv_usec )) {
|
||||||
|
_ldap_pvt_gt_subs++;
|
||||||
} else {
|
} else {
|
||||||
subs = 0;
|
_ldap_pvt_gt_subs = 0;
|
||||||
prevTv = tv;
|
_ldap_pvt_gt_prevTv = tv;
|
||||||
}
|
}
|
||||||
LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
|
LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
|
||||||
|
|
||||||
ltm->tm_usub = subs;
|
ltm->tm_usub = _ldap_pvt_gt_subs;
|
||||||
|
|
||||||
ldap_pvt_gmtime( &t, &tm );
|
ldap_pvt_gmtime( &t, &tm );
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue