Maintain stack alignment in ____longjmp_chk on x86_64
[glibc.git] / sysdeps / unix / sysv / linux / getsysstats.c
blobaf454b650de92e4910a5196c283ae04050e6e07f
1 /* Determine various system internal values, Linux version.
2 Copyright (C) 1996-2003,2006,2007,2009,2010 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;
121 *cp = nl + 1;
122 assert (*cp <= *re);
124 return res == *re ? NULL : res;
129 __get_nprocs ()
131 /* XXX Here will come a test for the new system call. */
133 const size_t buffer_size = __libc_use_alloca (8192) ? 8192 : 512;
134 char *buffer = alloca (buffer_size);
135 char *buffer_end = buffer + buffer_size;
136 char *cp = buffer_end;
137 char *re = buffer_end;
138 int result = 1;
140 #ifdef O_CLOEXEC
141 const int flags = O_RDONLY | O_CLOEXEC;
142 #else
143 const int flags = O_RDONLY;
144 #endif
145 /* The /proc/stat format is more uniform, use it by default. */
146 int fd = open_not_cancel_2 ("/proc/stat", flags);
147 if (fd != -1)
149 result = 0;
151 char *l;
152 while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
153 /* The current format of /proc/stat has all the cpu* entries
154 at the front. We assume here that stays this way. */
155 if (strncmp (l, "cpu", 3) != 0)
156 break;
157 else if (isdigit (l[3]))
158 ++result;
160 close_not_cancel_no_status (fd);
162 else
164 fd = open_not_cancel_2 ("/proc/cpuinfo", flags);
165 if (fd != -1)
167 GET_NPROCS_PARSER (fd, buffer, cp, re, buffer_end, result);
168 close_not_cancel_no_status (fd);
172 return result;
174 weak_alias (__get_nprocs, get_nprocs)
177 /* On some architectures it is possible to distinguish between configured
178 and active cpus. */
180 __get_nprocs_conf ()
182 /* XXX Here will come a test for the new system call. */
184 /* Try to use the sysfs filesystem. It has actual information about
185 online processors. */
186 DIR *dir = __opendir ("/sys/devices/system/cpu");
187 if (dir != NULL)
189 int count = 0;
190 struct dirent64 *d;
192 while ((d = __readdir64 (dir)) != NULL)
193 /* NB: the sysfs has d_type support. */
194 if (d->d_type == DT_DIR && strncmp (d->d_name, "cpu", 3) == 0)
196 char *endp;
197 unsigned long int nr = strtoul (d->d_name + 3, &endp, 10);
198 if (nr != ULONG_MAX && endp != d->d_name + 3 && *endp == '\0')
199 ++count;
202 __closedir (dir);
204 return count;
207 int result = 1;
209 #ifdef GET_NPROCS_CONF_PARSER
210 /* If we haven't found an appropriate entry return 1. */
211 FILE *fp = fopen ("/proc/cpuinfo", "rce");
212 if (fp != NULL)
214 char buffer[8192];
216 /* No threads use this stream. */
217 __fsetlocking (fp, FSETLOCKING_BYCALLER);
218 GET_NPROCS_CONF_PARSER (fp, buffer, result);
219 fclose (fp);
221 #else
222 result = __get_nprocs ();
223 #endif
225 return result;
227 weak_alias (__get_nprocs_conf, get_nprocs_conf)
229 /* General function to get information about memory status from proc
230 filesystem. */
231 static long int
232 internal_function
233 phys_pages_info (const char *format)
235 char buffer[8192];
236 long int result = -1;
238 /* If we haven't found an appropriate entry return 1. */
239 FILE *fp = fopen ("/proc/meminfo", "rc");
240 if (fp != NULL)
242 /* No threads use this stream. */
243 __fsetlocking (fp, FSETLOCKING_BYCALLER);
245 result = 0;
246 /* Read all lines and count the lines starting with the
247 string "processor". We don't have to fear extremely long
248 lines since the kernel will not generate them. 8192
249 bytes are really enough. */
250 while (fgets_unlocked (buffer, sizeof buffer, fp) != NULL)
251 if (sscanf (buffer, format, &result) == 1)
253 result /= (__getpagesize () / 1024);
254 break;
257 fclose (fp);
260 if (result == -1)
261 /* We cannot get the needed value: signal an error. */
262 __set_errno (ENOSYS);
264 return result;
268 /* Return the number of pages of physical memory in the system. There
269 is currently (as of version 2.0.21) no system call to determine the
270 number. It is planned for the 2.1.x series to add this, though.
272 One possibility to implement it for systems using Linux 2.0 is to
273 examine the pseudo file /proc/cpuinfo. Here we have one entry for
274 each processor.
276 But not all systems have support for the /proc filesystem. If it
277 is not available we return -1 as an error signal. */
278 long int
279 __get_phys_pages ()
281 /* XXX Here will come a test for the new system call. */
283 return phys_pages_info ("MemTotal: %ld kB");
285 weak_alias (__get_phys_pages, get_phys_pages)
288 /* Return the number of available pages of physical memory in the
289 system. There is currently (as of version 2.0.21) no system call
290 to determine the number. It is planned for the 2.1.x series to add
291 this, though.
293 One possibility to implement it for systems using Linux 2.0 is to
294 examine the pseudo file /proc/cpuinfo. Here we have one entry for
295 each processor.
297 But not all systems have support for the /proc filesystem. If it
298 is not available we return -1 as an error signal. */
299 long int
300 __get_avphys_pages ()
302 /* XXX Here will come a test for the new system call. */
304 return phys_pages_info ("MemFree: %ld kB");
306 weak_alias (__get_avphys_pages, get_avphys_pages)