Home | History | Annotate | Download | only in bionic
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <asm/page.h>
     30 #include <bionic_tls.h>
     31 #include <ctype.h>
     32 #include <dirent.h>
     33 #include <errno.h>
     34 #include <fcntl.h>
     35 #include <limits.h>
     36 #include <pthread.h>
     37 #include <stdio.h>  // For FOPEN_MAX.
     38 #include <string.h>
     39 #include <sys/sysconf.h>
     40 #include <time.h>
     41 #include <unistd.h>
     42 
     43 #include "private/ScopedReaddir.h"
     44 
     45 /* seems to be the default on Linux, per the GLibc sources and my own digging */
     46 
     47 #define  SYSTEM_CLK_TCK         100
     48 #define  SYSTEM_IOV_MAX         1024
     49 #define  SYSTEM_DELAYTIMER_MAX  2147483647
     50 #define  SYSTEM_MQ_OPEN_MAX     8
     51 #define  SYSTEM_MQ_PRIO_MAX     32768
     52 #define  SYSTEM_SEM_NSEMS_MAX   256
     53 #define  SYSTEM_SEM_VALUE_MAX   0x3fffffff  /* see bionic/semaphore.c */
     54 #define  SYSTEM_SIGQUEUE_MAX    32
     55 #define  SYSTEM_TIMER_MAX       32
     56 #define  SYSTEM_LOGIN_NAME_MAX  256
     57 #define  SYSTEM_TTY_NAME_MAX    32
     58 
     59 /* the following depends on our implementation */
     60 #define  SYSTEM_ATEXIT_MAX          65536    /* our implementation is unlimited */
     61 #define  SYSTEM_THREAD_THREADS_MAX  2048     /* really unlimited */
     62 
     63 #define  SYSTEM_2_C_BIND     _POSIX_VERSION  /* Posix C binding version */
     64 #define  SYSTEM_2_C_VER      _POSIX2_C_VERSION
     65 #define  SYSTEM_2_C_DEV      -1       /* Posix C development tools unsupported on the device */
     66 #define  SYSTEM_2_FORT_DEV   -1       /* Fortran development unsupported */
     67 #define  SYSTEM_2_FORT_RUN   -1       /* Fortran runtime unsupported */
     68 #define  SYSTEM_2_SW_DEV     -1       /* posix software dev utilities unsupported */
     69 #define  SYSTEM_2_LOCALEDEF  -1       /* localedef() unimplemented */
     70 #define  SYSTEM_2_UPE        -1       /* No UPE for you ! (User Portability Utilities) */
     71 #define  SYSTEM_2_VERSION    -1       /* No posix command-line tools */
     72 
     73 static bool __matches_cpuN(const char* s) {
     74   // The %c trick is to ensure that we have the anchored match "^cpu[0-9]+$".
     75   unsigned cpu;
     76   char dummy;
     77   return (sscanf(s, "cpu%u%c", &cpu, &dummy) == 1);
     78 }
     79 
     80 static int __sysconf_nprocessors_conf() {
     81   // On x86 kernels you can use /proc/cpuinfo for this, but on ARM kernels offline CPUs disappear
     82   // from there. This method works on both.
     83   ScopedReaddir reader("/sys/devices/system/cpu");
     84   if (reader.IsBad()) {
     85     return 1;
     86   }
     87 
     88   int result = 0;
     89   dirent* entry;
     90   while ((entry = reader.ReadEntry()) != NULL) {
     91     if (entry->d_type == DT_DIR && __matches_cpuN(entry->d_name)) {
     92       ++result;
     93     }
     94   }
     95   return result;
     96 }
     97 
     98 static int __sysconf_nprocessors_onln() {
     99   FILE* fp = fopen("/proc/stat", "r");
    100   if (fp == NULL) {
    101     return 1;
    102   }
    103 
    104   int result = 0;
    105   char buf[256];
    106   while (fgets(buf, sizeof(buf), fp) != NULL) {
    107     // Extract just the first word from the line.
    108     // 'cpu0 7976751 1364388 3116842 469770388 8629405 0 49047 0 0 0'
    109     char* p = strchr(buf, ' ');
    110     if (p != NULL) {
    111       *p = 0;
    112     }
    113     if (__matches_cpuN(buf)) {
    114       ++result;
    115     }
    116   }
    117   fclose(fp);
    118   return result;
    119 }
    120 
    121 static int __get_meminfo(const char* pattern) {
    122   FILE* fp = fopen("/proc/meminfo", "r");
    123   if (fp == NULL) {
    124     return -1;
    125   }
    126 
    127   int result = -1;
    128   char buf[256];
    129   while (fgets(buf, sizeof(buf), fp) != NULL) {
    130     long total;
    131     if (sscanf(buf, pattern, &total) == 1) {
    132       result = (int) (total / (PAGE_SIZE/1024));
    133       break;
    134     }
    135   }
    136   fclose(fp);
    137   return result;
    138 }
    139 
    140 static int __sysconf_phys_pages() {
    141   return __get_meminfo("MemTotal: %ld kB");
    142 }
    143 
    144 static int __sysconf_avphys_pages() {
    145   return __get_meminfo("MemFree: %ld kB");
    146 }
    147 
    148 static int __sysconf_monotonic_clock() {
    149   timespec t;
    150   int rc = clock_getres(CLOCK_MONOTONIC, &t);
    151   return (rc == -1) ? -1 : _POSIX_VERSION;
    152 }
    153 
    154 int sysconf(int name) {
    155     switch (name) {
    156 #ifdef _POSIX_ARG_MAX
    157     case _SC_ARG_MAX:           return _POSIX_ARG_MAX;
    158 #endif
    159 #ifdef _POSIX2_BC_BASE_MAX
    160     case _SC_BC_BASE_MAX:       return _POSIX2_BC_BASE_MAX;
    161 #endif
    162 #ifdef _POSIX2_BC_DIM_MAX
    163     case _SC_BC_DIM_MAX:        return _POSIX2_BC_DIM_MAX;
    164 #endif
    165 #ifdef _POSIX2_BC_SCALE_MAX
    166     case _SC_BC_SCALE_MAX:      return _POSIX2_BC_SCALE_MAX;
    167 #endif
    168 #ifdef _POSIX2_BC_STRING_MAX
    169     case _SC_BC_STRING_MAX:     return _POSIX2_BC_STRING_MAX;
    170 #endif
    171     case _SC_CHILD_MAX:         return CHILD_MAX;
    172     case _SC_CLK_TCK:           return SYSTEM_CLK_TCK;
    173 #ifdef _POSIX2_COLL_WEIGHTS_MASK
    174     case _SC_COLL_WEIGHTS_MAX:  return _POSIX2_COLL_WEIGHTS_MASK;
    175 #endif
    176 #ifdef _POSIX2_EXPR_NEST_MAX
    177     case _SC_EXPR_NEST_MAX:    return _POSIX2_EXPR_NEST_MAX;
    178 #endif
    179 #ifdef _POSIX2_LINE_MAX
    180     case _SC_LINE_MAX:          return _POSIX2_LINE_MAX;
    181 #endif
    182     case _SC_NGROUPS_MAX:       return NGROUPS_MAX;
    183     case _SC_OPEN_MAX:          return OPEN_MAX;
    184     //case _SC_PASS_MAX:          return PASS_MAX;
    185     case _SC_2_C_BIND:          return SYSTEM_2_C_BIND;
    186     case _SC_2_C_DEV:           return SYSTEM_2_C_DEV;
    187     case _SC_2_C_VERSION:       return SYSTEM_2_C_VER;
    188     //case _SC_2_CHAR_TERM:         return ;
    189     case _SC_2_FORT_DEV:        return SYSTEM_2_FORT_DEV;
    190     case _SC_2_FORT_RUN:        return SYSTEM_2_FORT_RUN;
    191     case _SC_2_LOCALEDEF:       return SYSTEM_2_LOCALEDEF;
    192     case _SC_2_SW_DEV:          return SYSTEM_2_SW_DEV;
    193     case _SC_2_UPE:             return SYSTEM_2_UPE;
    194     case _SC_2_VERSION:         return SYSTEM_2_VERSION;
    195 #ifdef _POSIX_JOB_CONTROL
    196     case _SC_JOB_CONTROL:       return _POSIX_JOB_CONTROL;
    197 #endif
    198 #ifdef _POSIX_SAVED_IDS
    199     case _SC_SAVED_IDS:         return _POSIX_SAVED_IDS;
    200 #endif
    201 #ifdef _POSIX_VERSION
    202     case _SC_VERSION:           return _POSIX_VERSION;
    203 #endif
    204     //case _SC_RE_DUP_<AX:        return ;
    205     case _SC_STREAM_MAX:        return FOPEN_MAX;
    206     //case _SC_TZNAME_MAX:        return ;
    207 #if _XOPEN_CRYPT
    208     case _SC_XOPEN_CRYPT:       return _XOPEN_CRYPT;
    209 #endif
    210 #ifdef _XOPEN_ENH_I18N
    211     case _SC_XOPEN_ENH_I18N:    return _XOPEN_ENH_I18N;
    212 #endif
    213 #ifdef _XOPEN_SHM
    214     case _SC_XOPEN_SHM:         return _XOPEN_SHM;
    215 #endif
    216 #ifdef _XOPEN_VERSION
    217     case _SC_XOPEN_VERSION:     return _XOPEN_VERSION;
    218 #endif
    219 #ifdef _XOPEN_XCU_VERSION
    220     case _SC_XOPEN_XCU_VERSION: return _XOPEN_XCU_VERSION;
    221 #endif
    222 #ifdef _XOPEN_REALTIME
    223     case _SC_XOPEN_REALTIME:    return _XOPEN_REALTIME;
    224 #endif
    225 #ifdef _XOPEN_REALTIME_THREADS
    226     case _SC_XOPEN_REALTIME_THREADS: return _XOPEN_REALTIME_THREADS;
    227 #endif
    228 #ifdef _XOPEN_LEGACY
    229     case _SC_XOPEN_LEGACY:      return _XOPEN_LEGACY;
    230 #endif
    231     case _SC_ATEXIT_MAX:        return SYSTEM_ATEXIT_MAX;
    232     case _SC_IOV_MAX:           return SYSTEM_IOV_MAX;
    233     case _SC_PAGESIZE:          return PAGE_SIZE;
    234     case _SC_PAGE_SIZE:         return PAGE_SIZE;
    235 #ifdef _XOPEN_UNIX
    236     case _SC_XOPEN_UNIX:        return _XOPEN_UNIX;
    237 #endif
    238 
    239     // XXX: TODO: XBS5 nonsense
    240 
    241 #ifdef AIO_LISTIO_MAX
    242     case _SC_AIO_LISTIO_MAX:       return AIO_LISTIO_MAX;
    243 #endif
    244 #ifdef AIO_MAX
    245     case _SC_AIO_MAX:              return AIO_MAX;
    246 #endif
    247 #ifdef AIO_PRIO_DELTA_MAX
    248     case _SC_AIO_PRIO_DELTA_MAX:   return AIO_PRIO_DELTA_MAX;
    249 #endif
    250     case _SC_DELAYTIMER_MAX:    return SYSTEM_DELAYTIMER_MAX;
    251     case _SC_MQ_OPEN_MAX:       return SYSTEM_MQ_OPEN_MAX;
    252     case _SC_MQ_PRIO_MAX:       return SYSTEM_MQ_PRIO_MAX;
    253     case _SC_RTSIG_MAX:         return RTSIG_MAX;
    254     case _SC_SEM_NSEMS_MAX:     return SYSTEM_SEM_NSEMS_MAX;
    255     case _SC_SEM_VALUE_MAX:     return SYSTEM_SEM_VALUE_MAX;
    256     case _SC_SIGQUEUE_MAX:      return SYSTEM_SIGQUEUE_MAX;
    257     case _SC_TIMER_MAX:         return SYSTEM_TIMER_MAX;
    258 #ifdef _POSIX_ASYNCHRONOUS_IO
    259     case _SC_ASYNCHRONOUS_IO:   return _POSIX_ASYNCHRONOUS_IO;
    260 #endif
    261 #ifdef _POSIX_FSYNC
    262     case _SC_FSYNC:             return _POSIX_FSYNC;
    263 #endif
    264 #ifdef _POSIX_MAPPED_FILES
    265     case _SC_MAPPED_FILES:      return _POSIX_MAPPED_FILES;
    266 #endif
    267 #ifdef _POSIX_MEMLOCK
    268     case _SC_MEMLOCK:           return _POSIX_MEMLOCK;
    269 #endif
    270 #ifdef _POSIX_MEMLOCK_RANGE
    271     case _SC_MEMLOCK_RANGE:     return _POSIX_MEMLOCK_RANGE
    272 #endif
    273 #ifdef _POSIX_MEMORY_PROTECTION
    274     case _SC_MEMORY_PROTECTION: return _POSIX_MEMORY_PROTECTION;
    275 #endif
    276 #ifdef _POSIX_MESSAGE_PASSING
    277     case _SC_MESSAGE_PASSING:   return _POSIX_MESSAGE_PASSING;
    278 #endif
    279 #ifdef _POSIX_PRIORITIZED_IO
    280     case _SC_PRIORITIZED_IO:    return _POSIX_PRIORITIZED_IO;
    281 #endif
    282 #ifdef _POSIX_PRIORITY_SCHEDULING
    283     case _SC_PRIORITY_SCHEDULING:  return _POSIX_PRIORITY_SCHEDULING;
    284 #endif
    285 #ifdef _POSIX_REALTIME_SIGNALS
    286     case _SC_REALTIME_SIGNALS:  return _POSIX_REALTIME_SIGNALS;
    287 #endif
    288 #ifdef _POSIX_SEMAPHORES
    289     case _SC_SEMAPHORES:        return _POSIX_SEMAPHORES;
    290 #endif
    291 #ifdef _POSIX_SHARED_MEMORY_OBJECTS
    292     case _SC_SHARED_MEMORY_OBJECTS:  return _POSIX_SHARED_MEMORY_OBJECTS;
    293 #endif
    294 #ifdef _POSIX_SYNCHRONIZED_IO
    295     case _SC_SYNCHRONIZED_IO:   return _POSIX_SYNCHRONIZED_IO;
    296 #endif
    297 #ifdef _POSIX_TIMERS
    298     case _SC_TIMERS:            return _POSIX_TIMERS;
    299 #endif
    300 
    301     case _SC_GETGR_R_SIZE_MAX: return 1024;
    302     case _SC_GETPW_R_SIZE_MAX: return 1024;
    303 
    304     case _SC_LOGIN_NAME_MAX:    return SYSTEM_LOGIN_NAME_MAX;
    305 
    306     case _SC_THREAD_DESTRUCTOR_ITERATIONS:
    307       return _POSIX_THREAD_DESTRUCTOR_ITERATIONS;
    308 
    309     case _SC_THREAD_KEYS_MAX:
    310       return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT - GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT);
    311 
    312     case _SC_THREAD_STACK_MIN:    return PTHREAD_STACK_MIN;
    313     case _SC_THREAD_THREADS_MAX:  return SYSTEM_THREAD_THREADS_MAX;
    314     case _SC_TTY_NAME_MAX:        return SYSTEM_TTY_NAME_MAX;
    315 #ifdef _POSIX_THREADS
    316     case _SC_THREADS:             return _POSIX_THREADS;
    317 #endif
    318 #ifdef _POSIX_THREAD_ATTR_STACKADDR
    319     case _SC_THREAD_ATTR_STACKADDR:   return _POSIX_THREAD_ATTR_STACKADDR;
    320 #endif
    321 #ifdef _POSIX_THREAD_ATTR_STACKSIZE
    322     case _SC_THREAD_ATTR_STACKSIZE:   return _POSIX_THREAD_ATTR_STACKSIZE;
    323 #endif
    324 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
    325     case _SC_THREAD_PRIORITY_SCHEDULING:  return _POSIX_THREAD_PRIORITY_SCHEDULING;
    326 #endif
    327 #ifdef _POSIX_THREAD_PRIO_INHERIT
    328     case _SC_THREAD_PRIO_INHERIT:         return _POSIX_THREAD_PRIO_INHERIT;
    329 #endif
    330 #ifdef _POSIX_THREAD_PRIO_PROTECT
    331     case _SC_THREAD_PRIO_PROTECT: return _POSIX_THREAD_PRIO_PROTECT;
    332 #endif
    333 #ifdef _POSIX_THREAD_SAFE_FUNCTIONS
    334     case _SC_THREAD_SAFE_FUNCTIONS:  return _POSIX_THREAD_SAFE_FUNCTIONS
    335 #endif
    336 
    337     case _SC_MONOTONIC_CLOCK:   return __sysconf_monotonic_clock();
    338     case _SC_NPROCESSORS_CONF:  return __sysconf_nprocessors_conf();
    339     case _SC_NPROCESSORS_ONLN:  return __sysconf_nprocessors_onln();
    340     case _SC_PHYS_PAGES:        return __sysconf_phys_pages();
    341     case _SC_AVPHYS_PAGES:      return __sysconf_avphys_pages();
    342 
    343     default:
    344        /* Posix says EINVAL is the only error that shall be returned,
    345         * but GLibc uses ENOSYS */
    346         errno = ENOSYS;
    347         return -1;
    348     }
    349 }
    350