1 /* Determine various system internal values, Linux version.
2 Copyright (C) 1996-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <array_length.h>
25 #include <not-cancel.h>
27 #include <stdio_ext.h>
29 #include <sys/sysinfo.h>
33 __get_nprocs_sched (void)
38 cpu_bits_size
= CPU_ALLOC_SIZE (32768)
41 /* This cannot use malloc because it is used on malloc initialization. */
42 __cpu_mask cpu_bits
[cpu_bits_size
/ sizeof (__cpu_mask
)];
43 int r
= INTERNAL_SYSCALL_CALL (sched_getaffinity
, 0, cpu_bits_size
,
46 return CPU_COUNT_S (r
, (cpu_set_t
*) cpu_bits
);
47 else if (r
== -EINVAL
)
48 /* The input buffer is still not enough to store the number of cpus. This
49 is an arbitrary values assuming such systems should be rare and there
50 is no offline cpus. */
52 /* Some other error. */
57 next_line (int fd
, char *const buffer
, char **cp
, char **re
,
58 char *const buffer_end
)
61 char *nl
= memchr (*cp
, '\n', *re
- *cp
);
66 if (*re
== buffer_end
)
68 memmove (buffer
, *cp
, *re
- *cp
);
69 *re
= buffer
+ (*re
- *cp
);
72 ssize_t n
= __read_nocancel (fd
, *re
, buffer_end
- *re
);
78 nl
= memchr (*cp
, '\n', *re
- *cp
);
79 while (nl
== NULL
&& *re
== buffer_end
)
81 /* Truncate too long lines. */
82 *re
= buffer
+ 3 * (buffer_end
- buffer
) / 4;
83 n
= __read_nocancel (fd
, *re
, buffer_end
- *re
);
87 nl
= memchr (*re
, '\n', n
);
93 nl
= memchr (*cp
, '\n', *re
- *cp
);
105 return res
== *re
? NULL
: res
;
109 get_nproc_stat (void)
111 enum { buffer_size
= 1024 };
112 char buffer
[buffer_size
];
113 char *buffer_end
= buffer
+ buffer_size
;
114 char *cp
= buffer_end
;
115 char *re
= buffer_end
;
118 const int flags
= O_RDONLY
| O_CLOEXEC
;
119 int fd
= __open_nocancel ("/proc/stat", flags
);
123 while ((l
= next_line (fd
, buffer
, &cp
, &re
, buffer_end
)) != NULL
)
124 /* The current format of /proc/stat has all the cpu* entries
125 at the front. We assume here that stays this way. */
126 if (strncmp (l
, "cpu", 3) != 0)
128 else if (isdigit (l
[3]))
131 __close_nocancel_nostatus (fd
);
138 read_sysfs_file (const char *fname
)
140 enum { buffer_size
= 1024 };
141 char buffer
[buffer_size
];
142 char *buffer_end
= buffer
+ buffer_size
;
143 char *cp
= buffer_end
;
144 char *re
= buffer_end
;
146 const int flags
= O_RDONLY
| O_CLOEXEC
;
147 /* This file contains comma-separated ranges. */
148 int fd
= __open_nocancel (fname
, flags
);
153 l
= next_line (fd
, buffer
, &cp
, &re
, buffer_end
);
158 unsigned long int n
= strtoul (l
, &endp
, 10);
165 unsigned long int m
= n
;
169 m
= strtoul (l
, &endp
, 10);
181 if (l
< re
&& *l
== ',')
184 while (l
< re
&& *l
!= '\n');
186 __close_nocancel_nostatus (fd
);
193 get_nprocs_fallback (void)
197 /* Try /proc/stat first. */
198 result
= get_nproc_stat ();
202 /* Try sched_getaffinity. */
203 result
= __get_nprocs_sched ();
207 /* We failed to obtain an accurate number. Be conservative: return
208 the smallest number meaning that this is not a uniprocessor system,
209 so atomics are needed. */
216 int result
= read_sysfs_file ("/sys/devices/system/cpu/online");
220 /* Fall back to /proc/stat and sched_getaffinity. */
221 return get_nprocs_fallback ();
223 libc_hidden_def (__get_nprocs
)
224 weak_alias (__get_nprocs
, get_nprocs
)
226 /* On some architectures it is possible to distinguish between configured
229 __get_nprocs_conf (void)
231 int result
= read_sysfs_file ("/sys/devices/system/cpu/possible");
235 /* Fall back to /proc/stat and sched_getaffinity. */
236 return get_nprocs_fallback ();
238 libc_hidden_def (__get_nprocs_conf
)
239 weak_alias (__get_nprocs_conf
, get_nprocs_conf
)
242 /* Compute (num*mem_unit)/pagesize, but avoid overflowing long int.
243 In practice, mem_unit is never bigger than the page size, so after
244 the first loop it is 1. [In the kernel, it is initialized to
245 PAGE_SIZE in mm/page_alloc.c:si_meminfo(), and then in
246 kernel.sys.c:do_sysinfo() it is set to 1 if unsigned long can
247 represent all the sizes measured in bytes]. */
249 sysinfo_mempages (unsigned long int num
, unsigned int mem_unit
)
251 unsigned long int ps
= __getpagesize ();
253 while (mem_unit
> 1 && ps
> 1)
267 /* Return the number of pages of total/available physical memory in
268 the system. This used to be done by parsing /proc/meminfo, but
269 that's unnecessarily expensive (and /proc is not always available).
270 The sysinfo syscall provides the same information, and has been
271 available at least since kernel 2.3.48. */
273 __get_phys_pages (void)
278 return sysinfo_mempages (info
.totalram
, info
.mem_unit
);
280 libc_hidden_def (__get_phys_pages
)
281 weak_alias (__get_phys_pages
, get_phys_pages
)
284 __get_avphys_pages (void)
289 return sysinfo_mempages (info
.freeram
, info
.mem_unit
);
291 libc_hidden_def (__get_avphys_pages
)
292 weak_alias (__get_avphys_pages
, get_avphys_pages
)