waf: configure option for enforcing autostart method
[jackdbus.git] / linux / JackLinuxTime.c
blob3c3a9c2500fc2af413f2639e00d3dda08dc3bb73
1 /*
2 Copyright (C) 2001-2003 Paul Davis
3 Copyright (C) 2005 Jussi Laako
4 Copyright (C) 2004-2008 Grame
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser 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.
22 #include "JackConstants.h"
23 #include "JackTime.h"
24 #include "JackTypes.h"
25 #include "JackError.h"
26 #include "cycles.h"
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <sys/mman.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <inttypes.h>
41 static jack_time_t __jack_cpu_mhz = 0;
42 jack_time_t (*_jack_get_microseconds)(void) = 0;
44 #if defined(__gnu_linux__) && (defined(__i386__) || defined(__x86_64__))
45 #define HPET_SUPPORT
46 #define HPET_MMAP_SIZE 1024
47 #define HPET_CAPS 0x000
48 #define HPET_PERIOD 0x004
49 #define HPET_COUNTER 0x0f0
50 #define HPET_CAPS_COUNTER_64BIT (1 << 13)
51 #if defined(__x86_64__)
52 typedef uint64_t hpet_counter_t;
53 #else
54 typedef uint32_t hpet_counter_t;
55 #endif
56 static int hpet_fd;
57 static unsigned char *hpet_ptr;
58 static uint32_t hpet_period; /* period length in femto secs */
59 static uint64_t hpet_offset = 0;
60 static uint64_t hpet_wrap;
61 static hpet_counter_t hpet_previous = 0;
62 #endif /* defined(__gnu_linux__) && (__i386__ || __x86_64__) */
64 #ifdef HPET_SUPPORT
66 static int jack_hpet_init ()
68 uint32_t hpet_caps;
70 hpet_fd = open("/dev/hpet", O_RDONLY);
71 if (hpet_fd < 0) {
72 jack_error ("This system has no accessible HPET device (%s)", strerror (errno));
73 return -1;
76 hpet_ptr = (unsigned char *) mmap(NULL, HPET_MMAP_SIZE,
77 PROT_READ, MAP_SHARED, hpet_fd, 0);
78 if (hpet_ptr == MAP_FAILED) {
79 jack_error ("This system has no mappable HPET device (%s)", strerror (errno));
80 close (hpet_fd);
81 return -1;
84 /* this assumes period to be constant. if needed,
85 it can be moved to the clock access function
87 hpet_period = *((uint32_t *) (hpet_ptr + HPET_PERIOD));
88 hpet_caps = *((uint32_t *) (hpet_ptr + HPET_CAPS));
89 hpet_wrap = ((hpet_caps & HPET_CAPS_COUNTER_64BIT) &&
90 (sizeof(hpet_counter_t) == sizeof(uint64_t))) ?
91 0 : ((uint64_t) 1 << 32);
93 return 0;
96 static jack_time_t jack_get_microseconds_from_hpet (void)
98 hpet_counter_t hpet_counter;
99 long double hpet_time;
101 hpet_counter = *((hpet_counter_t *) (hpet_ptr + HPET_COUNTER));
102 if (hpet_counter < hpet_previous)
103 hpet_offset += hpet_wrap;
104 hpet_previous = hpet_counter;
105 hpet_time = (long double) (hpet_offset + hpet_counter) *
106 (long double) hpet_period * (long double) 1e-9;
107 return ((jack_time_t) (hpet_time + 0.5));
110 #else
112 static int jack_hpet_init ()
114 jack_error ("This version of JACK or this computer does not have HPET support.\n"
115 "Please choose a different clock source.");
116 return -1;
119 static jack_time_t jack_get_microseconds_from_hpet (void)
121 /* never called */
122 return 0;
125 #endif /* HPET_SUPPORT */
127 static jack_time_t jack_get_microseconds_from_cycles (void) {
128 return get_cycles() / __jack_cpu_mhz;
132 * This is another kludge. It looks CPU-dependent, but actually it
133 * reflects the lack of standards for the Linux kernel formatting of
134 * /proc/cpuinfo.
137 static jack_time_t jack_get_mhz (void)
139 FILE *f = fopen("/proc/cpuinfo", "r");
140 if (f == 0)
142 perror("can't open /proc/cpuinfo\n");
143 exit(1);
146 for (;;)
148 jack_time_t mhz;
149 int ret;
150 char buf[1000];
152 if (fgets(buf, sizeof(buf), f) == NULL) {
153 jack_error ("FATAL: cannot locate cpu MHz in "
154 "/proc/cpuinfo\n");
155 exit(1);
158 #if defined(__powerpc__)
159 ret = sscanf(buf, "clock\t: %" SCNu64 "MHz", &mhz);
160 #elif defined( __i386__ ) || defined (__hppa__) || defined (__ia64__) || \
161 defined(__x86_64__)
162 ret = sscanf(buf, "cpu MHz : %" SCNu64, &mhz);
163 #elif defined( __sparc__ )
164 ret = sscanf(buf, "Cpu0Bogo : %" SCNu64, &mhz);
165 #elif defined( __mc68000__ )
166 ret = sscanf(buf, "Clocking: %" SCNu64, &mhz);
167 #elif defined( __s390__ )
168 ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz);
169 #elif defined( __sh__ )
170 ret = sscanf(buf, "bogomips : %" SCNu64, &mhz);
171 #else /* MIPS, ARM, alpha */
172 ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz);
173 #endif
175 if (ret == 1)
177 fclose(f);
178 return (jack_time_t)mhz;
183 #define HAVE_CLOCK_GETTIME 1
185 #ifndef HAVE_CLOCK_GETTIME
187 static jack_time_t jack_get_microseconds_from_system (void)
189 jack_time_t jackTime;
190 struct timeval tv;
192 gettimeofday (&tv, NULL);
193 jackTime = (jack_time_t) tv.tv_sec * 1000000 + (jack_time_t) tv.tv_usec;
194 return jackTime;
197 #else
199 static jack_time_t jack_get_microseconds_from_system (void)
201 jack_time_t jackTime;
202 struct timespec time;
204 clock_gettime(CLOCK_MONOTONIC, &time);
205 jackTime = (jack_time_t) time.tv_sec * 1e6 +
206 (jack_time_t) time.tv_nsec / 1e3;
207 return jackTime;
210 #endif /* HAVE_CLOCK_GETTIME */
213 SERVER_EXPORT void JackSleep(long usec)
215 usleep(usec);
218 SERVER_EXPORT void InitTime()
220 __jack_cpu_mhz = jack_get_mhz ();
223 SERVER_EXPORT void EndTime()
226 void SetClockSource(jack_timer_type_t source)
228 jack_log("Clock source : %s", ClockSourceName(source));
230 switch (source)
232 case JACK_TIMER_CYCLE_COUNTER:
233 _jack_get_microseconds = jack_get_microseconds_from_cycles;
234 break;
236 case JACK_TIMER_HPET:
237 if (jack_hpet_init () == 0) {
238 _jack_get_microseconds = jack_get_microseconds_from_hpet;
239 } else {
240 _jack_get_microseconds = jack_get_microseconds_from_system;
242 break;
244 case JACK_TIMER_SYSTEM_CLOCK:
245 default:
246 _jack_get_microseconds = jack_get_microseconds_from_system;
247 break;
251 const char* ClockSourceName(jack_timer_type_t source)
253 switch (source) {
254 case JACK_TIMER_CYCLE_COUNTER:
255 return "cycle counter";
256 case JACK_TIMER_HPET:
257 return "hpet";
258 case JACK_TIMER_SYSTEM_CLOCK:
259 #ifdef HAVE_CLOCK_GETTIME
260 return "system clock via clock_gettime";
261 #else
262 return "system clock via gettimeofday";
263 #endif
266 /* what is wrong with gcc ? */
267 return "unknown";
270 SERVER_EXPORT jack_time_t GetMicroSeconds()
272 return _jack_get_microseconds();
275 SERVER_EXPORT jack_time_t jack_get_microseconds()
277 return _jack_get_microseconds();