@@ -135,6 +135,69 @@ int Win32NumCPUs() {
135135
136136#endif
137137
138+ #if defined(__linux__)
139+ // Kinda like perror, but without allocating. At least, mostly...
140+ void PerrorNoAlloc (const char * msg) {
141+ // strerror might allocate, theoretically. In practice, it doesn't do so on
142+ // glibc unless you provide an invalid errno, and never allocates on musl.
143+ char *errmsg = strerror (errno);
144+
145+ // snprintf isn't technically on the async-signal-safe list, but, in practice,
146+ // it doesn't allocate.
147+ char buf[1024 ];
148+ int len = snprintf (buf, sizeof (buf), " %s: %s\n " , msg, errmsg);
149+ if (len > 0 ) {
150+ if ((unsigned )len > sizeof (buf)) len = sizeof (buf);
151+ ABSL_ATTRIBUTE_UNUSED auto ret = write (2 , buf, static_cast <size_t >(len));
152+ }
153+ }
154+
155+ // Returns the number of possible cpus by parsing a sysfs string.
156+ int ParseSysFsPossibleCPUs (const char * str, size_t len) {
157+ if (len == 0 ) return 1 ;
158+ // Find the last number in the line and parse that -- that'll be the highest
159+ // cpu number.
160+ for (int i = static_cast <int >(len - 1 ); i >= 0 ; --i) {
161+ if (!isdigit (str[i])) return atoi (&str[i+1 ]) + 1 ; // NOLINT
162+ }
163+ return atoi (str) + 1 ; // NOLINT
164+ }
165+
166+ int GetNumPossibleCpusFromSysfs () {
167+ // The "possible" file exists since Linux 2.6.26.
168+ //
169+ // It contains a value such as "0-127" (meaning you have 128 CPUs, numbered 0
170+ // through 127). The format used here also supports strings like: "0,2,4-7" to
171+ // describe discontiguous ids, but that cannot actually happen here, since
172+ // "possible" CPU numbers are always contiguous from 0 to the maximum.
173+ int fd;
174+ do {
175+ fd = open (" /sys/devices/system/cpu/possible" , O_RDONLY | O_CLOEXEC);
176+ } while (fd < 0 && errno == EINTR);
177+
178+ if (fd < 0 ) {
179+ PerrorNoAlloc (" GetNumPossibleCpusFromSysfs: open() failed" );
180+ abort ();
181+ }
182+
183+ char buf[1024 ];
184+ ssize_t len;
185+ do {
186+ len = read (fd, buf, sizeof (buf) - 1 );
187+ } while (len < 0 && errno == EINTR);
188+
189+ if (len <= 0 ) {
190+ PerrorNoAlloc (" GetNumPossibleCpusFromSysfs: read() failed" );
191+ abort ();
192+ }
193+ close (fd);
194+
195+ if (buf[len - 1 ] == ' \n ' ) --len;
196+ buf[len] = ' \0 ' ;
197+ return ParseSysFsPossibleCPUs (buf, static_cast <size_t >(len));
198+ }
199+ #endif
200+
138201} // namespace
139202
140203static int GetNumCPUs () {
@@ -145,6 +208,8 @@ static int GetNumCPUs() {
145208 return hardware_concurrency ? hardware_concurrency : 1 ;
146209#elif defined(_AIX)
147210 return sysconf (_SC_NPROCESSORS_ONLN);
211+ #elif defined(__linux__)
212+ return GetNumPossibleCpusFromSysfs ();
148213#else
149214 // Other possibilities:
150215 // - Read /sys/devices/system/cpu/online and use cpumask_parse()
0 commit comments