Re-install F_[GS]ETOWN_EX changes
[glibc.git] / sysdeps / unix / sysv / linux / getsysstats.c
blob97e20d249bd262658c2b20b16f9ea67d340c5f56
1 /* Determine various system internal values, Linux version.
2 Copyright (C) 1996-2003, 2006, 2007, 2009 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <alloca.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <mntent.h>
28 #include <paths.h>
29 #include <stdio.h>
30 #include <stdio_ext.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/sysinfo.h>
36 #include <atomic.h>
37 #include <not-cancel.h>
40 /* How we can determine the number of available processors depends on
41 the configuration. There is currently (as of version 2.0.21) no
42 system call to determine the number. It is planned for the 2.1.x
43 series to add this, though.
45 One possibility to implement it for systems using Linux 2.0 is to
46 examine the pseudo file /proc/cpuinfo. Here we have one entry for
47 each processor.
49 But not all systems have support for the /proc filesystem. If it
50 is not available we simply return 1 since there is no way. */
52 #include <not-cancel.h>
55 /* Other architectures use different formats for /proc/cpuinfo. This
56 provides a hook for alternative parsers. */
57 #ifndef GET_NPROCS_PARSER
58 # define GET_NPROCS_PARSER(FD, BUFFER, CP, RE, BUFFER_END, RESULT) \
59 do \
60 { \
61 (RESULT) = 0; \
62 /* Read all lines and count the lines starting with the string \
63 "processor". We don't have to fear extremely long lines since \
64 the kernel will not generate them. 8192 bytes are really \
65 enough. */ \
66 char *l; \
67 while ((l = next_line (FD, BUFFER, &CP, &RE, BUFFER_END)) != NULL) \
68 if (strncmp (l, "processor", 9) == 0) \
69 ++(RESULT); \
70 } \
71 while (0)
72 #endif
75 static char *
76 next_line (int fd, char *const buffer, char **cp, char **re,
77 char *const buffer_end)
79 char *res = *cp;
80 char *nl = memchr (*cp, '\n', *re - *cp);
81 if (nl == NULL)
83 if (*cp != buffer)
85 if (*re == buffer_end)
87 memmove (buffer, *cp, *re - *cp);
88 *re = buffer + (*re - *cp);
89 *cp = buffer;
91 ssize_t n = read_not_cancel (fd, *re, buffer_end - *re);
92 if (n < 0)
93 return NULL;
95 *re += n;
97 nl = memchr (*cp, '\n', *re - *cp);
98 while (nl == NULL && *re == buffer_end)
100 /* Truncate too long lines. */
101 *re = buffer + 3 * (buffer_end - buffer) / 4;
102 n = read_not_cancel (fd, *re, buffer_end - *re);
103 if (n < 0)
104 return NULL;
106 nl = memchr (*re, '\n', n);
107 **re = '\n';
108 *re += n;
111 else
112 nl = memchr (*cp, '\n', *re - *cp);
114 res = *cp;
117 if (nl == NULL)
118 nl = *re - 1;
120 else if (nl + 5 >= *re)
122 memmove (buffer, nl, *re - nl);
123 *re = buffer + (*re - nl);
124 nl = *cp = buffer;
126 ssize_t n = read_not_cancel (fd, *re, buffer_end - *re);
127 if (n < 0)
128 return NULL;
130 *re += n;
133 *cp = nl + 1;
134 assert (*cp <= *re);
136 return res == *re ? NULL : res;
141 __get_nprocs ()
143 /* XXX Here will come a test for the new system call. */
145 const size_t buffer_size = __libc_use_alloca (8192) ? 8192 : 512;
146 char *buffer = alloca (buffer_size);
147 char *buffer_end = buffer + buffer_size;
148 char *cp = buffer_end;
149 char *re = buffer_end;
150 int result = 1;
152 #ifdef O_CLOEXEC
153 const int flags = O_RDONLY | O_CLOEXEC;
154 #else
155 const int flags = O_RDONLY;
156 #endif
157 /* The /proc/stat format is more uniform, use it by default. */
158 int fd = open_not_cancel_2 ("/proc/stat", flags);
159 if (fd != -1)
161 result = 0;
163 char *l;
164 while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
165 /* The current format of /proc/stat has all the cpu* entries
166 at the front. We assume here that stays this way. */
167 if (strncmp (l, "cpu", 3) != 0)
168 break;
169 else if (isdigit (l[3]))
170 ++result;
172 close_not_cancel_no_status (fd);
174 else
176 fd = open_not_cancel_2 ("/proc/cpuinfo", flags);
177 if (fd != -1)
179 GET_NPROCS_PARSER (fd, buffer, cp, re, buffer_end, result);
180 close_not_cancel_no_status (fd);
184 return result;
186 weak_alias (__get_nprocs, get_nprocs)
189 /* On some architectures it is possible to distinguish between configured
190 and active cpus. */
192 __get_nprocs_conf ()
194 /* XXX Here will come a test for the new system call. */
196 /* Try to use the sysfs filesystem. It has actual information about
197 online processors. */
198 DIR *dir = __opendir ("/sys/devices/system/cpu");
199 if (dir != NULL)
201 int count = 0;
202 struct dirent64 *d;
204 while ((d = __readdir64 (dir)) != NULL)
205 /* NB: the sysfs has d_type support. */
206 if (d->d_type == DT_DIR && strncmp (d->d_name, "cpu", 3) == 0)
208 char *endp;
209 unsigned long int nr = strtoul (d->d_name + 3, &endp, 10);
210 if (nr != ULONG_MAX && endp != d->d_name + 3 && *endp == '\0')
211 ++count;
214 __closedir (dir);
216 return count;
219 int result = 1;
221 #ifdef GET_NPROCS_CONF_PARSER
222 /* If we haven't found an appropriate entry return 1. */
223 FILE *fp = fopen ("/proc/cpuinfo", "rce");
224 if (fp != NULL)
226 char buffer[8192];
228 /* No threads use this stream. */
229 __fsetlocking (fp, FSETLOCKING_BYCALLER);
230 GET_NPROCS_CONF_PARSER (fp, buffer, result);
231 fclose (fp);
233 #else
234 result = __get_nprocs ();
235 #endif
237 return result;
239 weak_alias (__get_nprocs_conf, get_nprocs_conf)
241 /* General function to get information about memory status from proc
242 filesystem. */
243 static long int
244 internal_function
245 phys_pages_info (const char *format)
247 char buffer[8192];
248 long int result = -1;
250 /* If we haven't found an appropriate entry return 1. */
251 FILE *fp = fopen ("/proc/meminfo", "rc");
252 if (fp != NULL)
254 /* No threads use this stream. */
255 __fsetlocking (fp, FSETLOCKING_BYCALLER);
257 result = 0;
258 /* Read all lines and count the lines starting with the
259 string "processor". We don't have to fear extremely long
260 lines since the kernel will not generate them. 8192
261 bytes are really enough. */
262 while (fgets_unlocked (buffer, sizeof buffer, fp) != NULL)
263 if (sscanf (buffer, format, &result) == 1)
265 result /= (__getpagesize () / 1024);
266 break;
269 fclose (fp);
272 if (result == -1)
273 /* We cannot get the needed value: signal an error. */
274 __set_errno (ENOSYS);
276 return result;
280 /* Return the number of pages of physical memory in the system. There
281 is currently (as of version 2.0.21) no system call to determine the
282 number. It is planned for the 2.1.x series to add this, though.
284 One possibility to implement it for systems using Linux 2.0 is to
285 examine the pseudo file /proc/cpuinfo. Here we have one entry for
286 each processor.
288 But not all systems have support for the /proc filesystem. If it
289 is not available we return -1 as an error signal. */
290 long int
291 __get_phys_pages ()
293 /* XXX Here will come a test for the new system call. */
295 return phys_pages_info ("MemTotal: %ld kB");
297 weak_alias (__get_phys_pages, get_phys_pages)
300 /* Return the number of available pages of physical memory in the
301 system. There is currently (as of version 2.0.21) no system call
302 to determine the number. It is planned for the 2.1.x series to add
303 this, though.
305 One possibility to implement it for systems using Linux 2.0 is to
306 examine the pseudo file /proc/cpuinfo. Here we have one entry for
307 each processor.
309 But not all systems have support for the /proc filesystem. If it
310 is not available we return -1 as an error signal. */
311 long int
312 __get_avphys_pages ()
314 /* XXX Here will come a test for the new system call. */
316 return phys_pages_info ("MemFree: %ld kB");
318 weak_alias (__get_avphys_pages, get_avphys_pages)