1 /*
2  * Copyright (C) 2002 - David W. Durham
3  *
4  * This file is part of ReZound, an audio editing application.
5  *
6  * ReZound is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * ReZound is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19  */
20 #include "clocks.h"
21 #include <stdio.h>
22 
23 #if defined(_WIN32)
24 
25 #include <windows.h>
26 #include <mmsystem.h> // timeGetTime
27 #include <tchar.h>
28 #include <climits> // CHAR_BIT
29 #include "CMutex.h" // for protecting fixed_msec fallback
30 
31 namespace clocks {
32 
time_sec()33 sec_t time_sec()
34 {
35 	return static_cast<sec_t>(time_msec() / 1000);
36 }
37 
time_msec()38 msec_t time_msec()
39 {
40 	union bigTime_t {
41 		FILETIME fTime;
42 		ULONGLONG int64time;
43 	} bigTime;
44 
45 	GetSystemTimeAsFileTime( &bigTime.fTime );
46 
47 	// Subtract the value for 1970-01-01 00:00 (UTC)
48 	bigTime.int64time -= 0x19db1ded53e8000;
49 
50 	// Convert to milliseconds
51 	bigTime.int64time /= 10000;
52 
53 	return bigTime.int64time;
54 }
55 
time_usec()56 usec_t time_usec()
57 {
58 	// Windows currently has no greater precision than 1ms
59 	return (time_msec() * 1000);
60 }
61 
fixed_sec()62 sec_t fixed_sec()
63 {
64 	return static_cast<sec_t>(fixed_msec() / 1000);
65 }
66 
fixed_msec()67 msec_t fixed_msec()
68 {
69 	return GetTickCount64();
70 }
71 
fixed_usec()72 usec_t fixed_usec()
73 {
74 	// Windows currently has no greater precision than 1ms
75 	return (fixed_msec() * 1000);
76 }
77 
sleep(const sec_t sec,const msec_t msec)78 bool sleep(const sec_t sec, const msec_t msec)
79 {
80 	Sleep(static_cast<DWORD>(sec * 1000 + msec));
81 	return true;
82 }
83 
get_timezone_offset()84 int get_timezone_offset()
85 {
86 	TIME_ZONE_INFORMATION tz;
87 	DWORD result = GetTimeZoneInformation(&tz);
88 
89 	// convert minutes to seconds
90 	int ret = (tz.Bias + tz.StandardBias) * 60;
91 
92 	// negate for our purposes
93 	ret = -ret;
94 
95 	// "clamp-and-shift" to convert values outside the appropriate
96 	// range to their correct locations within the appropriate range.
97 	// e.g. -14 hours really belongs at +10 hours
98 	// e.g. +13 hours really belongs at -11 hours
99 	if(ret < (-12*3600)) {
100 		ret = (ret % (12*3600)) + (12*3600);
101 	} else if(ret > (12*3600)) {
102 		ret = (ret % (12*3600)) - (12*3600);
103 	}
104 
105 	return ret;
106 }
107 
108 } // namespace clocks
109 
110 #else
111 
112 #include <time.h>
113 #include <sys/times.h>
114 #include <unistd.h>
115 
116 #if TARGET_OS_IPHONE
117 #import "CAHostTimeBase.h"
118 #elif defined(__APPLE__)
119 #include <sys/time.h>
120 #include <mach/mach_time.h>
121 #include <CoreServices/CoreServices.h>
122 #include <Foundation/Foundation.h>
123 #endif
124 
125 namespace clocks {
126 
127 static const long gClockTicks = sysconf(_SC_CLK_TCK);
128 
time_sec()129 sec_t time_sec()
130 {
131 #if TARGET_OS_IPHONE
132 	NSDate *d = [NSDate date];
133 	NSTimeInterval t = [d timeIntervalSince1970];
134 	return t;
135 #elif defined(__APPLE__)
136 	struct timeval t;
137 	if(gettimeofday(&t,NULL) == 0) {
138 		return (sec_t)t.tv_sec;
139 	}
140 #else
141 	struct timespec t;
142 	if(clock_gettime(CLOCK_REALTIME, &t) == 0) {
143 		return (sec_t)t.tv_sec;
144 	}
145 #endif
146 
147 	// fall back
148 	return time(NULL);
149 }
150 
time_msec()151 msec_t time_msec()
152 {
153 #if TARGET_OS_IPHONE
154 	NSDate *d = [NSDate date];
155 	NSTimeInterval t = [d timeIntervalSince1970];
156 	return (t * 1000);
157 #elif defined(__APPLE__)
158 	struct timeval t;
159 	if(gettimeofday(&t,NULL) == 0) {
160 		return ((msec_t)t.tv_sec * 1000) + (t.tv_usec / 1000);
161 	}
162 #else
163 	struct timespec t;
164 	if(clock_gettime(CLOCK_REALTIME, &t) == 0) {
165 		return ((msec_t)t.tv_sec * 1000) + (t.tv_nsec / 1000000);
166 	}
167 #endif
168 
169 	// fall back
170 	return time(NULL) * 1000;
171 }
172 
time_usec()173 usec_t time_usec()
174 {
175 #if TARGET_OS_IPHONE
176 	NSDate *d = [NSDate date];
177 	NSTimeInterval t = [d timeIntervalSince1970];
178 	return (t * 1000000);
179 #elif defined(__APPLE__)
180 	struct timeval t;
181 	if(gettimeofday(&t,NULL) == 0) {
182 		return ((msec_t)t.tv_sec * 1000000) + t.tv_usec;
183 	}
184 #else
185 	struct timespec t;
186 	if(clock_gettime(CLOCK_REALTIME, &t) == 0) {
187 		return ((usec_t)t.tv_sec * 1000000) + (t.tv_nsec / 1000);
188 	}
189 #endif
190 
191 	// fall back
192 	return time(NULL) * 1000000;
193 }
194 
fixed_sec()195 sec_t fixed_sec()
196 {
197 #if TARGET_OS_IPHONE
198 	UInt64 t = CAHostTimeBase::GetCurrentTimeInNanos();
199 	return (t / 1000000000);
200 #elif defined(__APPLE__)
201 	uint64_t t = mach_absolute_time();
202 	Nanoseconds elapsedNano = AbsoluteToNanoseconds(*(AbsoluteTime *)&t);
203 	return (*(uint64_t *) &t) / 1000000000 ;
204 #else
205 	struct timespec t;
206 	if(clock_gettime(CLOCK_MONOTONIC, &t) == 0) {
207 		return (sec_t)t.tv_sec;
208 	}
209 #endif
210 
211 	// fall back
212 	return time_sec();
213 }
214 
fixed_msec()215 msec_t fixed_msec()
216 {
217 #if TARGET_OS_IPHONE
218 	UInt64 t = CAHostTimeBase::GetCurrentTimeInNanos();
219 	return (t / 1000000);
220 #elif defined(__APPLE__)
221 	uint64_t t = mach_absolute_time();
222 	Nanoseconds elapsedNano = AbsoluteToNanoseconds(*(AbsoluteTime*)&t);
223 	return (*(uint64_t *) &t) / 1000000;
224 #else
225 	struct timespec t;
226 	if(clock_gettime(CLOCK_MONOTONIC, &t) == 0) {
227 		return ((sec_t)t.tv_sec * 1000) + (t.tv_nsec / 1000000);
228 	}
229 #endif
230 
231 	// fall back
232 	return time_msec();
233 }
234 
fixed_usec()235 usec_t fixed_usec()
236 {
237 #if TARGET_OS_IPHONE
238 	UInt64 t = CAHostTimeBase::GetCurrentTimeInNanos();
239 	return (t / 1000);
240 #elif defined(__APPLE__)
241 	uint64_t t = mach_absolute_time();
242 	Nanoseconds elapsedNano = AbsoluteToNanoseconds(*(AbsoluteTime*)&t);
243 	return (*(uint64_t *) &t) / 1000;
244 #else
245 	struct timespec t;
246 	if(clock_gettime(CLOCK_MONOTONIC, &t) == 0) {
247 		return ((usec_t)t.tv_sec * 1000000) + (t.tv_nsec / 1000);
248 	}
249 #endif
250 
251 	// fall back
252 	return time_usec();
253 }
254 
cpu_sec()255 sec_t cpu_sec()
256 {
257 	struct tms t;
258 	if(times(&t) != -1) {
259 		return (sec_t)(t.tms_utime + t.tms_stime) / gClockTicks;
260 	}
261 	return -1;
262 }
263 
cpu_msec()264 msec_t cpu_msec()
265 {
266 	struct tms t;
267 	if(times(&t) != -1) {
268 		return (msec_t)(t.tms_utime + t.tms_stime) * 1000 / gClockTicks;
269 	}
270 	return -1;
271 }
272 
cpu_usec()273 usec_t cpu_usec()
274 {
275 	struct tms t;
276 	if(times(&t) != -1) {
277 		return (usec_t)(t.tms_utime + t.tms_stime) * 1000000 / gClockTicks;
278 	}
279 	return -1;
280 }
281 
sleep(sec_t sec,msec_t msec)282 bool sleep(sec_t sec, msec_t msec)
283 {
284 	// ensure that msec is within the proper range
285 	if(msec >= 1000) {
286 		sec += (msec / 1000);
287 		msec %= 1000;
288 	}
289 
290 	struct timespec t = {
291 		static_cast<time_t>(sec),
292 		static_cast<long>(msec * 1000 * 1000)
293 	};
294 
295 	if(nanosleep(&t, 0) == -1) {
296 		// assuming errno == EINTR, but there are other rare errors (particularly with bad input to nanosleep())
297 		return false;
298 	}
299 	return true;
300 }
301 
get_timezone_offset()302 int get_timezone_offset()
303 {
304 #ifdef __APPLE__
305 	int ret = [[NSTimeZone localTimeZone] secondsFromGMT];
306 #else
307 	time_t date = time(NULL);
308 	int ret = localtime(&date)->tm_gmtoff;
309 #endif
310 
311 	// "clamp-and-shift" to convert values outside the appropriate
312 	// range to their correct locations within the appropriate range.
313 	// e.g. -14 hours really belongs at +10 hours
314 	// e.g. +13 hours really belongs at -11 hours
315 	if(ret < (-12*3600)) {
316 		ret = (ret % (12*3600)) + (12*3600);
317 	} else if(ret > (12*3600)) {
318 		ret = (ret % (12*3600)) - (12*3600);
319 	}
320 
321 	return ret;
322 }
323 
324 } // namespace clocks
325 
326 #endif
327 
328 namespace clocks {
329 
source_sec(Sources source)330 sec_t source_sec(Sources source)
331 {
332 	switch(source) {
333 	case sTime:
334 		return time_sec();
335 	case sFixed:
336 		return fixed_sec();
337 #if defined(__linux) || defined(__APPLE__)
338 	case sCPU:
339 		return cpu_sec();
340 #endif
341 	}
342 	return 0;
343 }
344 
source_msec(Sources source)345 msec_t source_msec(Sources source)
346 {
347 	switch(source) {
348 	case sTime:
349 		return time_msec();
350 	case sFixed:
351 		return fixed_msec();
352 #if defined(__linux) || defined(__APPLE__)
353 	case sCPU:
354 		return cpu_msec();
355 #endif
356 	}
357 	return 0;
358 }
359 
source_usec(Sources source)360 usec_t source_usec(Sources source)
361 {
362 	switch(source) {
363 	case sTime:
364 		return time_usec();
365 	case sFixed:
366 		return fixed_usec();
367 #if defined(__linux) || defined(__APPLE__)
368 	case sCPU:
369 		return cpu_usec();
370 #endif
371 	}
372 	return 0;
373 }
374 
convert_sec(Sources from,sec_t fromTime,Sources to)375 sec_t convert_sec(Sources from, sec_t fromTime, Sources to)
376 {
377 	if (from == to) {
378 		return fromTime;
379 	}
380 	return fromTime - source_sec(from) + source_sec(to);
381 }
382 
convert_msec(Sources from,msec_t fromTime,Sources to)383 msec_t convert_msec(Sources from, msec_t fromTime, Sources to)
384 {
385 	if (from == to) {
386 		return fromTime;
387 	}
388 	return fromTime - source_msec(from) + source_msec(to);
389 }
390 
convert_usec(Sources from,usec_t fromTime,Sources to)391 usec_t convert_usec(Sources from, usec_t fromTime, Sources to)
392 {
393 	if (from == to) {
394 		return fromTime;
395 	}
396 	return fromTime - source_usec(from) + source_usec(to);
397 }
398 
399 
400 
401 } // namespace clocks
402