summaryrefslogtreecommitdiff
path: root/lib/common/BoxTime.cpp
blob: 77daae6dcf8d415ed67ea47b0c48cadbb9f6546f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// --------------------------------------------------------------------------
//
// File
//		Name:    BoxTime.cpp
//		Purpose: Time for the box
//		Created: 2003/10/08
//
// --------------------------------------------------------------------------

#include "Box.h"

#ifdef HAVE_SYS_TIME_H
	#include <sys/time.h>
#endif

#ifdef HAVE_TIME_H
	#include <time.h>
#endif

#include <errno.h>
#include <string.h>

#include "BoxTime.h"

#include "MemLeakFindOn.h"

// --------------------------------------------------------------------------
//
// Function
//		Name:    GetCurrentBoxTime()
//		Purpose: Returns the current time as a box time. 
//			 (1 sec precision, or better if supported by system)
//		Created: 2003/10/08
//
// --------------------------------------------------------------------------
box_time_t GetCurrentBoxTime()
{
#ifdef HAVE_GETTIMEOFDAY
	struct timeval tv;
	if (gettimeofday(&tv, NULL) != 0)
	{
		BOX_LOG_SYS_ERROR("Failed to gettimeofday(), "
			"dropping precision");
	}
	else
	{
		box_time_t time_now = (tv.tv_sec * MICRO_SEC_IN_SEC_LL) + tv.tv_usec;
		return time_now;
	}
#elif WIN32
	// There's no Win32 API function that returns the current time as a UNIX timestamp with
	// sub-second precision. So we use time(0) and add the fractional part from
	// GetSystemTime() in the hope that the difference between these two (if any) is a whole
	// number of seconds.
	box_time_t time_now = SecondsToBoxTime(time(0));
	SYSTEMTIME system_time;
	GetSystemTime(&system_time);
	time_now += MilliSecondsToBoxTime(system_time.wMilliseconds);
	return time_now;
#endif

	return SecondsToBoxTime(time(0));
}

std::string FormatTime(box_time_t time, bool includeDate, bool showMicros)
{
	std::ostringstream buf;

	time_t seconds = BoxTimeToSeconds(time);
	int micros = BoxTimeToMicroSeconds(time) % MICRO_SEC_IN_SEC;

	struct tm tm_now, *tm_ptr = &tm_now;

	#ifdef WIN32
		if ((tm_ptr = localtime(&seconds)) != NULL)
	#else
		if (localtime_r(&seconds, &tm_now) != NULL)
	#endif
	{
		buf << std::setfill('0');

		if (includeDate)
		{
			buf << 	std::setw(4) << (tm_ptr->tm_year + 1900) << "-" <<
				std::setw(2) << (tm_ptr->tm_mon  + 1) << "-" <<
				std::setw(2) << (tm_ptr->tm_mday) << " ";
		}

		buf <<	std::setw(2) << tm_ptr->tm_hour << ":" << 
			std::setw(2) << tm_ptr->tm_min  << ":" <<
			std::setw(2) << tm_ptr->tm_sec;

		if (showMicros)
		{
			buf << "." << std::setw(3) << (int)(micros / 1000);
		}
	}
	else
	{
		buf << strerror(errno);
	}

	return buf.str();
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    ShortSleep(box_time_t duration)
//		Purpose: Sleeps for the specified duration as accurately
//			 and efficiently as possible.
//		Created: 2011/01/11
//
// --------------------------------------------------------------------------

void ShortSleep(box_time_t duration, bool logDuration)
{
	if(logDuration)
	{
		BOX_TRACE("Sleeping for " << BOX_FORMAT_MICROSECONDS(duration));
	}

#ifdef WIN32
	Sleep(BoxTimeToMilliSeconds(duration));
#else
	struct timespec ts;
	memset(&ts, 0, sizeof(ts));
	ts.tv_sec  = duration / MICRO_SEC_IN_SEC;
	ts.tv_nsec = (duration % MICRO_SEC_IN_SEC) * 1000;

	box_time_t start_time = GetCurrentBoxTime();

	while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
	{
		// FIXME evil hack for OSX, where ts.tv_sec contains
		// a negative number interpreted as unsigned 32-bit
		// when nanosleep() returns later than expected.

		int32_t secs = (int32_t) ts.tv_sec;
		int64_t remain_ns = ((int64_t)secs * 1000000000) + ts.tv_nsec;

		if (remain_ns < 0)
		{
			BOX_WARNING("nanosleep interrupted " <<
				((float)(0 - remain_ns) / 1000000000) <<
				" secs late");
			return;
		}

		BOX_TRACE("nanosleep interrupted with " << remain_ns <<
			" nanosecs remaining, sleeping again");
	}

	box_time_t sleep_time = GetCurrentBoxTime() - start_time;	
	BOX_TRACE("Actually slept for " << BOX_FORMAT_MICROSECONDS(sleep_time) <<
		", was aiming for " << BOX_FORMAT_MICROSECONDS(duration));
#endif
}