Merge "Fix sysconf(_SC_NPROCESSORS_CONF) on ARM."
diff --git a/libc/unistd/sysconf.c b/libc/unistd/sysconf.c
index 9377802..7caa4e9 100644
--- a/libc/unistd/sysconf.c
+++ b/libc/unistd/sysconf.c
@@ -25,16 +25,19 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <unistd.h>
-#include <sys/sysconf.h>
-#include <limits.h>
-#include <bionic_tls.h>
+
#include <asm/page.h>
-#include <stdio.h> /* for FOPEN_MAX */
+#include <bionic_tls.h>
+#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h> // For FOPEN_MAX.
#include <string.h>
-#include <ctype.h>
+#include <sys/sysconf.h>
+#include <unistd.h>
/* seems to be the default on Linux, per the GLibc sources and my own digging */
@@ -62,18 +65,88 @@
#define SYSTEM_2_FORT_DEV -1 /* Fortran development unsupported */
#define SYSTEM_2_FORT_RUN -1 /* Fortran runtime unsupported */
#define SYSTEM_2_SW_DEV -1 /* posix software dev utilities unsupported */
-#define SYSTEM_2_LOCALEDEF -1 /* localdef() unimplemented */
+#define SYSTEM_2_LOCALEDEF -1 /* localedef() unimplemented */
#define SYSTEM_2_UPE -1 /* No UPE for you ! (User Portability Utilities) */
#define SYSTEM_2_VERSION -1 /* No posix command-line tools */
-static int __get_nproc_conf(void);
-static int __get_nproc_onln(void);
-static int __get_phys_pages(void);
-static int __get_avphys_pages(void);
+static bool __matches_cpuN(const char* s) {
+ // The %c trick is to ensure that we have the anchored match "^cpu[0-9]+$".
+ unsigned cpu;
+ char dummy;
+ return (sscanf(s, "cpu%u%c", &cpu, &dummy) == 1);
+}
-int
-sysconf( int name )
-{
+static int __get_nproc_conf(void) {
+ // On x86 kernels you can use /proc/cpuinfo for this, but on ARM kernels offline CPUs disappear
+ // from there. This method works on both.
+ DIR* d = opendir("/sys/devices/system/cpu");
+ if (!d) {
+ return 1;
+ }
+
+ int result = 0;
+ struct dirent de;
+ struct dirent* e;
+ while (!readdir_r(d, &de, &e) && e != NULL) {
+ if (e->d_type == DT_DIR && __matches_cpuN(e->d_name)) {
+ ++result;
+ }
+ }
+ closedir(d);
+ return result;
+}
+
+static int __get_nproc_onln(void) {
+ FILE* fp = fopen("/proc/stat", "r");
+ if (fp == NULL) {
+ return 1;
+ }
+
+ int result = 0;
+ char buf[256];
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ // Extract just the first word from the line.
+ // 'cpu0 7976751 1364388 3116842 469770388 8629405 0 49047 0 0 0'
+ char* p = strchr(buf, ' ');
+ if (p != NULL) {
+ *p = 0;
+ }
+ if (__matches_cpuN(buf)) {
+ ++result;
+ }
+ }
+ fclose(fp);
+ return result;
+}
+
+static int __get_meminfo(const char* pattern) {
+ FILE* fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ int result = -1;
+ char buf[256];
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ long total;
+ if (sscanf(buf, pattern, &total) == 1) {
+ result = (int) (total / (PAGE_SIZE/1024));
+ break;
+ }
+ }
+ fclose(fp);
+ return result;
+}
+
+static int __get_phys_pages(void) {
+ return __get_meminfo("MemTotal: %ld kB");
+}
+
+static int __get_avphys_pages(void) {
+ return __get_meminfo("MemFree: %ld kB");
+}
+
+int sysconf(int name) {
switch (name) {
#ifdef _POSIX_ARG_MAX
case _SC_ARG_MAX: return _POSIX_ARG_MAX;
@@ -266,169 +339,3 @@
return -1;
}
}
-
-
-typedef struct {
- int rpos;
- int len;
- int overflow;
- int fd;
- int in_len;
- int in_pos;
- char buff[128];
- char input[128];
-} LineParser;
-
-static int
-line_parser_init( LineParser* p, const char* path )
-{
- p->rpos = 0;
- p->len = (int)sizeof(p->buff);
- p->overflow = 0;
-
- p->in_len = 0;
- p->in_pos = 0;
- p->fd = open( path, O_RDONLY );
-
- return p->fd;
-}
-
-
-static int
-line_parser_addc( LineParser* p, int c )
-{
- if (p->overflow) {
- p->overflow = (c == '\n');
- return 0;
- }
- if (p->rpos >= p->len) {
- p->overflow = 1;
- return 0;
- }
- if (c == '\n') {
- p->buff[p->rpos] = 0;
- p->rpos = 0;
- return 1;
- }
- p->buff[p->rpos++] = (char) c;
- return 0;
-}
-
-static int
-line_parser_getc( LineParser* p )
-{
- if (p->in_pos >= p->in_len) {
- int ret;
-
- p->in_len = p->in_pos = 0;
- do {
- ret = read(p->fd, p->input, sizeof(p->input));
- } while (ret < 0 && errno == EINTR);
-
- if (ret <= 0)
- return -1;
-
- p->in_len = ret;
- }
- return p->input[ p->in_pos++ ];
-}
-
-static const char*
-line_parser_gets( LineParser* p )
-{
- for (;;) {
- for (;;) {
- int c = line_parser_getc(p);
-
- if (c < 0) {
- close(p->fd);
- p->fd = -1;
- return NULL;
- }
- if (line_parser_addc(p, c))
- return p->buff;
- }
- }
-}
-
-static void
-line_parser_done( LineParser* p )
-{
- if (p->fd >= 0) {
- close(p->fd);
- p->fd = -1;
- }
-}
-
-static int
-__get_nproc_conf(void)
-{
- LineParser parser[1];
- const char* p;
- int count = 0;
-
- if (line_parser_init(parser, "/proc/cpuinfo") < 0)
- return 1;
-
- while ((p = line_parser_gets(parser))) {
- if ( !memcmp(p, "processor", 9) )
- count += 1;
- }
- return (count < 1) ? 1 : count;
-}
-
-
-static int
-__get_nproc_onln(void)
-{
- LineParser parser[1];
- const char* p;
- int count = 0;
-
- if (line_parser_init(parser, "/proc/stat") < 0)
- return 1;
-
- while ((p = line_parser_gets(parser))) {
- if ( !memcmp(p, "cpu", 3) && isdigit(p[3]) )
- count += 1;
- }
- return (count < 1) ? 1 : count;
-}
-
-static int
-__get_phys_pages(void)
-{
- LineParser parser[1];
- const char* p;
-
- if (line_parser_init(parser, "/proc/meminfo") < 0)
- return -2; /* what ? */
-
- while ((p = line_parser_gets(parser))) {
- long total;
- if ( sscanf(p, "MemTotal: %ld kB", &total) == 1 ) {
- line_parser_done(parser);
- return (int) (total / (PAGE_SIZE/1024));
- }
- }
- return -3;
-}
-
-static int
-__get_avphys_pages(void)
-{
- LineParser parser[1];
- const char* p;
-
- if (line_parser_init(parser, "/proc/meminfo") < 0)
- return -1; /* what ? */
-
- while ((p = line_parser_gets(parser))) {
- long total;
- if ( sscanf(p, "MemFree: %ld kB", &total) == 1 ) {
- line_parser_done(parser);
- return (int) (total / (PAGE_SIZE/1024));
- }
- }
- return -1;
-}