]> sourceware.org Git - glibc.git/blob - sysdeps/unix/sysv/linux/getsysstats.c
* include/libc-symbols.h (__libc_freeres_fn_section, libc_freeres_fn):
[glibc.git] / sysdeps / unix / sysv / linux / getsysstats.c
1 /* Determine various system internal values, Linux version.
2 Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
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.
10
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.
15
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. */
20
21 #include <alloca.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <mntent.h>
26 #include <paths.h>
27 #include <stdio.h>
28 #include <stdio_ext.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/sysinfo.h>
33
34 #include <atomicity.h>
35
36
37 /* The default value for the /proc filesystem mount point. */
38 static const char path_proc[] = "/proc";
39
40 /* Actual mount point of /proc filesystem. */
41 libc_freeres_ptr (static char *mount_proc);
42
43 /* Determine the path to the /proc filesystem if available. */
44 static const char *
45 internal_function
46 get_proc_path (char *buffer, size_t bufsize)
47 {
48 struct mntent mount_point;
49 struct mntent *entry;
50 char *result = NULL;
51 char *copy_result;
52 FILE *fp;
53
54 /* First find the mount point of the proc filesystem. */
55 fp = __setmntent (_PATH_MOUNTED, "r");
56 if (fp == NULL)
57 fp = __setmntent (_PATH_MNTTAB, "r");
58 if (fp != NULL)
59 {
60 /* We don't need locking. */
61 (void) __fsetlocking (fp, FSETLOCKING_BYCALLER);
62
63 while ((entry = __getmntent_r (fp, &mount_point, buffer, bufsize))
64 != NULL)
65 if (strcmp (mount_point.mnt_type, "proc") == 0)
66 {
67 result = mount_point.mnt_dir;
68 break;
69 }
70 __endmntent (fp);
71 }
72
73 /* If we haven't found anything this is generally a bad sign but we
74 handle it gracefully. We return what is hopefully the right
75 answer (/proc) but we don't remember this. This will enable
76 programs which started before the system is fully running to
77 adjust themselves. */
78 if (result == NULL)
79 return path_proc;
80
81 /* Make a copy we can keep around. */
82 copy_result = __strdup (result);
83 if (copy_result == NULL)
84 return result;
85
86 /* Now store the copied value. But do it atomically. */
87 assert (sizeof (long int) == sizeof (void *__unbounded));
88 if (compare_and_swap ((long int *) &mount_proc, (long int) 0,
89 (long int) copy_result) == 0)
90 /* Replacing the value failed. This means another thread was
91 faster and we don't need the copy anymore. */
92 free (copy_result);
93 #if __BOUNDED_POINTERS__
94 else
95 {
96 /* compare_and_swap only copied the pointer value, so we must
97 now copy the bounds as well. */
98 __ptrlow (mount_proc) = __ptrlow (copy_result);
99 __ptrhigh (mount_proc) = __ptrhigh (copy_result);
100 }
101 #endif
102
103 return mount_proc;
104 }
105
106
107 /* How we can determine the number of available processors depends on
108 the configuration. There is currently (as of version 2.0.21) no
109 system call to determine the number. It is planned for the 2.1.x
110 series to add this, though.
111
112 One possibility to implement it for systems using Linux 2.0 is to
113 examine the pseudo file /proc/cpuinfo. Here we have one entry for
114 each processor.
115
116 But not all systems have support for the /proc filesystem. If it
117 is not available we simply return 1 since there is no way. */
118
119 /* Other architectures use different formats for /proc/cpuinfo. This
120 provides a hook for alternative parsers. */
121 #ifndef GET_NPROCS_PARSER
122 # define GET_NPROCS_PARSER(FP, BUFFER, RESULT) \
123 do \
124 { \
125 (RESULT) = 0; \
126 /* Read all lines and count the lines starting with the string \
127 "processor". We don't have to fear extremely long lines since \
128 the kernel will not generate them. 8192 bytes are really \
129 enough. */ \
130 while (fgets_unlocked (BUFFER, sizeof (BUFFER), FP) != NULL) \
131 if (strncmp (BUFFER, "processor", 9) == 0) \
132 ++(RESULT); \
133 } \
134 while (0)
135 #endif
136
137 int
138 __get_nprocs ()
139 {
140 FILE *fp;
141 char buffer[8192];
142 const char *proc_path;
143 int result = 1;
144
145 /* XXX Here will come a test for the new system call. */
146
147 /* Get mount point of proc filesystem. */
148 proc_path = get_proc_path (buffer, sizeof buffer);
149
150 /* If we haven't found an appropriate entry return 1. */
151 if (proc_path != NULL)
152 {
153 char *proc_fname = alloca (strlen (proc_path) + sizeof ("/cpuinfo"));
154
155 /* The /proc/stat format is more uniform, use it by default. */
156 __stpcpy (__stpcpy (proc_fname, proc_path), "/stat");
157
158 fp = fopen (proc_fname, "r");
159 if (fp != NULL)
160 {
161 /* No threads use this stream. */
162 __fsetlocking (fp, FSETLOCKING_BYCALLER);
163
164 result = 0;
165 while (fgets_unlocked (buffer, sizeof (buffer), fp) != NULL)
166 if (strncmp (buffer, "cpu", 3) == 0 && isdigit (buffer[3]))
167 ++result;
168
169 fclose (fp);
170 }
171 else
172 {
173 __stpcpy (__stpcpy (proc_fname, proc_path), "/cpuinfo");
174
175 fp = fopen (proc_fname, "r");
176 if (fp != NULL)
177 {
178 /* No threads use this stream. */
179 __fsetlocking (fp, FSETLOCKING_BYCALLER);
180 GET_NPROCS_PARSER (fp, buffer, result);
181 fclose (fp);
182 }
183 }
184 }
185
186 return result;
187 }
188 weak_alias (__get_nprocs, get_nprocs)
189
190
191 #ifdef GET_NPROCS_CONF_PARSER
192 /* On some architectures it is possible to distinguish between configured
193 and active cpus. */
194 int
195 __get_nprocs_conf ()
196 {
197 FILE *fp;
198 char buffer[8192];
199 const char *proc_path;
200 int result = 1;
201
202 /* XXX Here will come a test for the new system call. */
203
204 /* Get mount point of proc filesystem. */
205 proc_path = get_proc_path (buffer, sizeof buffer);
206
207 /* If we haven't found an appropriate entry return 1. */
208 if (proc_path != NULL)
209 {
210 char *proc_cpuinfo = alloca (strlen (proc_path) + sizeof ("/cpuinfo"));
211 __stpcpy (__stpcpy (proc_cpuinfo, proc_path), "/cpuinfo");
212
213 fp = fopen (proc_cpuinfo, "r");
214 if (fp != NULL)
215 {
216 /* No threads use this stream. */
217 __fsetlocking (fp, FSETLOCKING_BYCALLER);
218 GET_NPROCS_CONF_PARSER (fp, buffer, result);
219 fclose (fp);
220 }
221 }
222
223 return result;
224 }
225 #else
226 /* As far as I know Linux has no separate numbers for configured and
227 available processors. So make the `get_nprocs_conf' function an
228 alias. */
229 strong_alias (__get_nprocs, __get_nprocs_conf)
230 #endif
231 weak_alias (__get_nprocs_conf, get_nprocs_conf)
232
233 /* General function to get information about memory status from proc
234 filesystem. */
235 static long int
236 internal_function
237 phys_pages_info (const char *format)
238 {
239 FILE *fp;
240 char buffer[8192];
241 const char *proc_path;
242 long int result = -1;
243
244 /* Get mount point of proc filesystem. */
245 proc_path = get_proc_path (buffer, sizeof buffer);
246
247 /* If we haven't found an appropriate entry return 1. */
248 if (proc_path != NULL)
249 {
250 char *proc_meminfo = alloca (strlen (proc_path) + sizeof ("/meminfo"));
251 __stpcpy (__stpcpy (proc_meminfo, proc_path), "/meminfo");
252
253 fp = fopen (proc_meminfo, "r");
254 if (fp != NULL)
255 {
256 /* No threads use this stream. */
257 __fsetlocking (fp, FSETLOCKING_BYCALLER);
258
259 result = 0;
260 /* Read all lines and count the lines starting with the
261 string "processor". We don't have to fear extremely long
262 lines since the kernel will not generate them. 8192
263 bytes are really enough. */
264 while (fgets_unlocked (buffer, sizeof buffer, fp) != NULL)
265 if (sscanf (buffer, format, &result) == 1)
266 {
267 result /= (__getpagesize () / 1024);
268 break;
269 }
270
271 fclose (fp);
272 }
273 }
274
275 if (result == -1)
276 /* We cannot get the needed value: signal an error. */
277 __set_errno (ENOSYS);
278
279 return result;
280 }
281
282
283 /* Return the number of pages of physical memory in the system. There
284 is currently (as of version 2.0.21) no system call to determine the
285 number. It is planned for the 2.1.x series to add this, though.
286
287 One possibility to implement it for systems using Linux 2.0 is to
288 examine the pseudo file /proc/cpuinfo. Here we have one entry for
289 each processor.
290
291 But not all systems have support for the /proc filesystem. If it
292 is not available we return -1 as an error signal. */
293 long int
294 __get_phys_pages ()
295 {
296 /* XXX Here will come a test for the new system call. */
297
298 return phys_pages_info ("MemTotal: %ld kB");
299 }
300 weak_alias (__get_phys_pages, get_phys_pages)
301
302
303 /* Return the number of available pages of physical memory in the
304 system. There is currently (as of version 2.0.21) no system call
305 to determine the number. It is planned for the 2.1.x series to add
306 this, though.
307
308 One possibility to implement it for systems using Linux 2.0 is to
309 examine the pseudo file /proc/cpuinfo. Here we have one entry for
310 each processor.
311
312 But not all systems have support for the /proc filesystem. If it
313 is not available we return -1 as an error signal. */
314 long int
315 __get_avphys_pages ()
316 {
317 /* XXX Here will come a test for the new system call. */
318
319 return phys_pages_info ("MemFree: %ld kB");
320 }
321 weak_alias (__get_avphys_pages, get_avphys_pages)
This page took 0.049463 seconds and 5 git commands to generate.