diff --git a/libc/unistd/sysconf.c b/libc/unistd/sysconf.c index 9377802bd..7caa4e93c 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 -#include -#include -#include + #include -#include /* for FOPEN_MAX */ +#include +#include +#include #include #include +#include +#include +#include // For FOPEN_MAX. #include -#include +#include +#include /* 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 @@ sysconf( int name ) 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; -}