Add functions in sysinfo.h.

Bug: 17703902

Change-Id: I699d12d76a8fc483c919be730c2ac63641b71a1d
This commit is contained in:
Yabin Cui 2014-11-14 15:51:58 -08:00
parent 661423a453
commit 9d93986481
6 changed files with 160 additions and 84 deletions

View File

@ -213,6 +213,7 @@ libc_bionic_src_files := \
bionic/stubs.cpp \
bionic/symlink.cpp \
bionic/sysconf.cpp \
bionic/sysinfo.cpp \
bionic/syslog.cpp \
bionic/sys_siglist.c \
bionic/sys_signame.c \

View File

@ -26,20 +26,17 @@
* SUCH DAMAGE.
*/
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <stdio.h> // For FOPEN_MAX.
#include <string.h>
#include <sys/sysconf.h>
#include <sys/sysinfo.h>
#include <time.h>
#include <unistd.h>
#include "private/bionic_tls.h"
#include "private/ScopedReaddir.h"
/* seems to be the default on Linux, per the GLibc sources and my own digging */
@ -68,81 +65,6 @@
#define SYSTEM_2_UPE -1 /* No UPE for you ! (User Portability Utilities) */
#define SYSTEM_2_VERSION -1 /* No posix command-line tools */
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);
}
static int __sysconf_nprocessors_conf() {
// On x86 kernels you can use /proc/cpuinfo for this, but on ARM kernels offline CPUs disappear
// from there. This method works on both.
ScopedReaddir reader("/sys/devices/system/cpu");
if (reader.IsBad()) {
return 1;
}
int result = 0;
dirent* entry;
while ((entry = reader.ReadEntry()) != NULL) {
if (entry->d_type == DT_DIR && __matches_cpuN(entry->d_name)) {
++result;
}
}
return result;
}
static int __sysconf_nprocessors_onln() {
FILE* fp = fopen("/proc/stat", "re");
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", "re");
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 __sysconf_phys_pages() {
return __get_meminfo("MemTotal: %ld kB");
}
static int __sysconf_avphys_pages() {
return __get_meminfo("MemFree: %ld kB");
}
static int __sysconf_monotonic_clock() {
timespec t;
int rc = clock_getres(CLOCK_MONOTONIC, &t);
@ -244,10 +166,10 @@ long sysconf(int name) {
//case _SC_THREAD_SAFE_FUNCTIONS: return _POSIX_THREAD_SAFE_FUNCTIONS
case _SC_MONOTONIC_CLOCK: return __sysconf_monotonic_clock();
case _SC_NPROCESSORS_CONF: return __sysconf_nprocessors_conf();
case _SC_NPROCESSORS_ONLN: return __sysconf_nprocessors_onln();
case _SC_PHYS_PAGES: return __sysconf_phys_pages();
case _SC_AVPHYS_PAGES: return __sysconf_avphys_pages();
case _SC_NPROCESSORS_CONF: return get_nprocs_conf();
case _SC_NPROCESSORS_ONLN: return get_nprocs();
case _SC_PHYS_PAGES: return get_phys_pages();
case _SC_AVPHYS_PAGES: return get_avphys_pages();
default:
// Posix says EINVAL is the only error that shall be returned,

111
libc/bionic/sysinfo.cpp Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/sysinfo.h>
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "private/ScopedReaddir.h"
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 get_nprocs_conf() {
// On x86 kernels you can use /proc/cpuinfo for this, but on ARM kernels offline CPUs disappear
// from there. This method works on both.
ScopedReaddir reader("/sys/devices/system/cpu");
if (reader.IsBad()) {
return 1;
}
int result = 0;
dirent* entry;
while ((entry = reader.ReadEntry()) != NULL) {
if (entry->d_type == DT_DIR && __matches_cpuN(entry->d_name)) {
++result;
}
}
return result;
}
int get_nprocs() {
FILE* fp = fopen("/proc/stat", "re");
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", "re");
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;
}
long get_phys_pages() {
return __get_meminfo("MemTotal: %ld kB");
}
long get_avphys_pages() {
return __get_meminfo("MemFree: %ld kB");
}

View File

@ -33,7 +33,15 @@
__BEGIN_DECLS
extern int sysinfo (struct sysinfo *info);
int sysinfo(struct sysinfo* info);
int get_nprocs_conf(void);
int get_nprocs(void);
long get_phys_pages(void);
long get_avphys_pages(void);
__END_DECLS

View File

@ -98,6 +98,7 @@ libBionicStandardTests_src_files := \
sys_stat_test.cpp \
sys_statvfs_test.cpp \
sys_syscall_test.cpp \
sys_sysinfo_test.cpp \
sys_time_test.cpp \
sys_types_test.cpp \
sys_vfs_test.cpp \

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <sys/sysinfo.h>
TEST(sys_sysinfo, smoke) {
int nprocessor = get_nprocs();
ASSERT_GT(nprocessor, 0);
int nprocessor_conf = get_nprocs_conf();
ASSERT_GE(nprocessor_conf, nprocessor);
long avail_phys_pages = get_avphys_pages();
ASSERT_GT(avail_phys_pages, 0);
long phys_pages = get_phys_pages();
ASSERT_GE(phys_pages, avail_phys_pages);
}