]>
Commit | Line | Data |
---|---|---|
7006f757 | 1 | /* Get frequency of the system processor. powerpc/Linux version. |
b168057a | 2 | Copyright (C) 2000-2015 Free Software Foundation, Inc. |
7006f757 UD |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
7006f757 UD |
18 | |
19 | #include <ctype.h> | |
20 | #include <fcntl.h> | |
d44a052c | 21 | #include <stdint.h> |
7006f757 UD |
22 | #include <string.h> |
23 | #include <unistd.h> | |
24 | #include <libc-internal.h> | |
8c2e201b UD |
25 | #include <sysdep.h> |
26 | #include <bits/libc-vdso.h> | |
7006f757 UD |
27 | |
28 | hp_timing_t | |
29 | __get_clockfreq (void) | |
30 | { | |
31 | /* We read the information from the /proc filesystem. /proc/cpuinfo | |
32 | contains at least one line like: | |
8c2e201b | 33 | timebase : 33333333 |
7006f757 UD |
34 | We search for this line and convert the number into an integer. */ |
35 | static hp_timing_t timebase_freq; | |
36 | hp_timing_t result = 0L; | |
37 | ||
38 | /* If this function was called before, we know the result. */ | |
39 | if (timebase_freq != 0) | |
40 | return timebase_freq; | |
41 | ||
8c2e201b UD |
42 | /* If we can use the vDSO to obtain the timebase even better. */ |
43 | #ifdef SHARED | |
44 | INTERNAL_SYSCALL_DECL (err); | |
471a1672 | 45 | timebase_freq = |
d44a052c | 46 | INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK (get_tbfreq, err, uint64_t, 0); |
8c2e201b UD |
47 | if (INTERNAL_SYSCALL_ERROR_P (timebase_freq, err) |
48 | && INTERNAL_SYSCALL_ERRNO (timebase_freq, err) == ENOSYS) | |
49 | #endif | |
7006f757 | 50 | { |
ca38dc17 | 51 | int fd = __open ("/proc/cpuinfo", O_RDONLY); |
7006f757 | 52 | |
a1ffb40e | 53 | if (__glibc_likely (fd != -1)) |
7006f757 | 54 | { |
8c2e201b UD |
55 | /* The timebase will be in the 1st 1024 bytes for systems with up |
56 | to 8 processors. If the first read returns less then 1024 | |
57 | bytes read, we have the whole cpuinfo and can start the scan. | |
58 | Otherwise we will have to read more to insure we have the | |
59 | timebase value in the scan. */ | |
60 | char buf[1024]; | |
61 | ssize_t n; | |
62 | ||
ca38dc17 | 63 | n = __read (fd, buf, sizeof (buf)); |
8c2e201b | 64 | if (n == sizeof (buf)) |
7006f757 | 65 | { |
8c2e201b UD |
66 | /* We are here because the 1st read returned exactly sizeof |
67 | (buf) bytes. This implies that we are not at EOF and may | |
68 | not have read the timebase value yet. So we need to read | |
69 | more bytes until we know we have EOF. We copy the lower | |
70 | half of buf to the upper half and read sizeof (buf)/2 | |
71 | bytes into the lower half of buf and repeat until we | |
72 | reach EOF. We can assume that the timebase will be in | |
73 | the last 512 bytes of cpuinfo, so two 512 byte half_bufs | |
74 | will be sufficient to contain the timebase and will | |
75 | handle the case where the timebase spans the half_buf | |
76 | boundry. */ | |
77 | const ssize_t half_buf = sizeof (buf) / 2; | |
78 | while (n >= half_buf) | |
79 | { | |
80 | memcpy (buf, buf + half_buf, half_buf); | |
ca38dc17 | 81 | n = __read (fd, buf + half_buf, half_buf); |
8c2e201b UD |
82 | } |
83 | if (n >= 0) | |
84 | n += half_buf; | |
7006f757 | 85 | } |
7006f757 | 86 | |
8c2e201b | 87 | if (__builtin_expect (n, 1) > 0) |
7006f757 | 88 | { |
8c2e201b | 89 | char *mhz = memmem (buf, n, "timebase", 7); |
7006f757 | 90 | |
a1ffb40e | 91 | if (__glibc_likely (mhz != NULL)) |
7006f757 | 92 | { |
8c2e201b UD |
93 | char *endp = buf + n; |
94 | ||
95 | /* Search for the beginning of the string. */ | |
96 | while (mhz < endp && (*mhz < '0' || *mhz > '9') | |
97 | && *mhz != '\n') | |
98 | ++mhz; | |
99 | ||
100 | while (mhz < endp && *mhz != '\n') | |
7006f757 | 101 | { |
8c2e201b UD |
102 | if (*mhz >= '0' && *mhz <= '9') |
103 | { | |
104 | result *= 10; | |
105 | result += *mhz - '0'; | |
106 | } | |
7006f757 | 107 | |
8c2e201b UD |
108 | ++mhz; |
109 | } | |
7006f757 | 110 | } |
8c2e201b | 111 | timebase_freq = result; |
7006f757 | 112 | } |
ca38dc17 | 113 | __close (fd); |
7006f757 | 114 | } |
7006f757 UD |
115 | } |
116 | ||
117 | return timebase_freq; | |
118 | } |