1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2001,2008 Oracle.  All rights reserved.
5 *
6 * $Id: os_clock.c,v 12.18 2008/05/07 12:27:35 bschmeck Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13/*
14 * __os_gettime --
15 *	Return the current time-of-day clock in seconds and nanoseconds.
16 */
17void
18__os_gettime(env, tp, monotonic)
19	ENV *env;
20	db_timespec *tp;
21	int monotonic;
22{
23	if (monotonic) {
24		/*
25		 * The elapsed time is stored as a DWORD value, so time wraps
26		 * around to zero if the system runs for 49.7 days.  Initialize
27		 * a base value with 50 days worth of seconds, and add 50 more
28		 * days every time the counter wraps.  That ensures we always
29		 * move forward.
30		 *
31		 * It's possible this code could race, but the danger is we
32		 * would increment base_seconds more than once per wrap and
33		 * eventually overflow, which is a pretty remote possibility.
34		 */
35#define	TIMER_WRAP_SECONDS	(50 * 24 * 60 * 60)
36		static DWORD last_ticks;
37		static time_t base_seconds;
38		DWORD ticks;
39
40		ticks = GetTickCount();
41		if (ticks < last_ticks)
42			base_seconds += TIMER_WRAP_SECONDS;
43		last_ticks = ticks;
44		tp->tv_sec = base_seconds + (u_int32_t)(ticks / 1000);
45		tp->tv_nsec = (u_int32_t)((ticks % 1000) * NS_PER_MS);
46	} else {
47#ifdef DB_WINCE
48		FILETIME ft;
49		LARGE_INTEGER large_int;
50		LONGLONG ns_since_epoch, utc1970;
51		SYSTEMTIME st;
52
53		(void)GetSystemTime(&st);
54		(void)SystemTimeToFileTime(&st, &ft);
55
56		/*
57		 * A FILETIME expresses time as 100 nanosecond chunks from
58		 * Jan 1, 1601; convert to a timespec where the time is
59		 * is expressed in seconds and nanoseconds from Jan 1, 1970.
60		 *
61		 * UTC_1970 is the number of 100-nano-second chunks from
62		 * 1601 to 1970.
63		 */
64#define	NS100_PER_SEC	(NS_PER_SEC / 100)
65#define	UTC_1970	(((LONGLONG)27111902 << 32) + (LONGLONG)3577643008)
66		memcpy(&large_int, &ft, sizeof(large_int));
67		utc1970 = UTC_1970;
68		ns_since_epoch = (large_int.QuadPart - utc1970);
69		tp->tv_sec = (time_t)(ns_since_epoch / NS100_PER_SEC);
70		tp->tv_nsec = (long)(ns_since_epoch % NS100_PER_SEC);
71#else
72		struct _timeb now;
73
74		_ftime(&now);
75		tp->tv_sec = now.time;
76		tp->tv_nsec = now.millitm * NS_PER_MS;
77#endif
78	}
79}
80