diff options
-rw-r--r-- | docs/status.md | 1 | ||||
-rw-r--r-- | libc/Android.bp | 1 | ||||
-rw-r--r-- | libc/bionic/getloadavg.cpp | 44 | ||||
-rw-r--r-- | libc/include/stdlib.h | 9 | ||||
-rw-r--r-- | libc/libc.arm.map | 1 | ||||
-rw-r--r-- | libc/libc.arm64.map | 1 | ||||
-rw-r--r-- | libc/libc.map.txt | 1 | ||||
-rw-r--r-- | libc/libc.mips.map | 1 | ||||
-rw-r--r-- | libc/libc.mips64.map | 1 | ||||
-rw-r--r-- | libc/libc.x86.map | 1 | ||||
-rw-r--r-- | libc/libc.x86_64.map | 1 | ||||
-rw-r--r-- | tests/stdlib_test.cpp | 32 |
12 files changed, 94 insertions, 0 deletions
diff --git a/docs/status.md b/docs/status.md index 0106ccd4a..54385a470 100644 --- a/docs/status.md +++ b/docs/status.md @@ -42,6 +42,7 @@ New libc functions in Q (API level 29): * `reallocarray` (BSD/GNU extension in `<malloc.h>` and `<stdlib.h>`) * `res_randomid` (in `<resolv.h>`) * `pthread_sigqueue` (GNU extension) + * `getloadavg` (BSD/GNU extension in <stdlib.h>) New libc behavior in Q (API level 29): * Whole printf family now supports the GNU `%m` extension, rather than a special-case hack in `syslog` diff --git a/libc/Android.bp b/libc/Android.bp index 1fc306295..681394f2e 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1314,6 +1314,7 @@ cc_library_static { "bionic/getdomainname.cpp", "bionic/getentropy.cpp", "bionic/gethostname.cpp", + "bionic/getloadavg.cpp", "bionic/getpagesize.cpp", "bionic/getpgrp.cpp", "bionic/getpid.cpp", diff --git a/libc/bionic/getloadavg.cpp b/libc/bionic/getloadavg.cpp new file mode 100644 index 000000000..28d316cfa --- /dev/null +++ b/libc/bionic/getloadavg.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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 <stdlib.h> + +#include <sys/sysinfo.h> + +int getloadavg(double averages[], int n) { + if (n < 0) return -1; + if (n > 3) n = 3; + + struct sysinfo si; + if (sysinfo(&si) == -1) return -1; + + for (int i = 0; i < n; ++i) { + averages[i] = static_cast<double>(si.loads[i]) / static_cast<double>(1 << SI_LOAD_SHIFT); + } + return n; +} diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 6888e8c20..96a77a790 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -147,6 +147,15 @@ typedef struct { lldiv_t lldiv(long long __numerator, long long __denominator) __attribute_const__; +/** + * [getloadavg(3)](http://man7.org/linux/man-pages/man3/getloadavg.3.html) queries the + * number of runnable processes averaged over time. The Linux kernel supports averages + * over the last 1, 5, and 15 minutes. + * + * Returns the number of samples written to `__averages` (at most 3), and returns -1 on failure. + */ +int getloadavg(double __averages[], int __n) __INTRODUCED_IN_FUTURE; + /* BSD compatibility. */ const char* getprogname(void) __INTRODUCED_IN(21); void setprogname(const char* __name) __INTRODUCED_IN(21); diff --git a/libc/libc.arm.map b/libc/libc.arm.map index a22a8df77..bd39d4299 100644 --- a/libc/libc.arm.map +++ b/libc/libc.arm.map @@ -1432,6 +1432,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_error_level; android_fdsan_set_error_level; android_get_device_api_level; + getloadavg; pthread_sigqueue; reallocarray; timespec_get; diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map index 55fd5875c..81ff00ddc 100644 --- a/libc/libc.arm64.map +++ b/libc/libc.arm64.map @@ -1353,6 +1353,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_error_level; android_fdsan_set_error_level; android_get_device_api_level; + getloadavg; pthread_sigqueue; reallocarray; timespec_get; diff --git a/libc/libc.map.txt b/libc/libc.map.txt index 304dbb7a9..934ad1ff1 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1457,6 +1457,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_error_level; android_fdsan_set_error_level; android_get_device_api_level; + getloadavg; pthread_sigqueue; reallocarray; timespec_get; diff --git a/libc/libc.mips.map b/libc/libc.mips.map index 397ff72e1..dc184a692 100644 --- a/libc/libc.mips.map +++ b/libc/libc.mips.map @@ -1416,6 +1416,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_error_level; android_fdsan_set_error_level; android_get_device_api_level; + getloadavg; pthread_sigqueue; reallocarray; timespec_get; diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map index 55fd5875c..81ff00ddc 100644 --- a/libc/libc.mips64.map +++ b/libc/libc.mips64.map @@ -1353,6 +1353,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_error_level; android_fdsan_set_error_level; android_get_device_api_level; + getloadavg; pthread_sigqueue; reallocarray; timespec_get; diff --git a/libc/libc.x86.map b/libc/libc.x86.map index a18657c5b..f360dbf31 100644 --- a/libc/libc.x86.map +++ b/libc/libc.x86.map @@ -1414,6 +1414,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_error_level; android_fdsan_set_error_level; android_get_device_api_level; + getloadavg; pthread_sigqueue; reallocarray; timespec_get; diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map index 55fd5875c..81ff00ddc 100644 --- a/libc/libc.x86_64.map +++ b/libc/libc.x86_64.map @@ -1353,6 +1353,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_error_level; android_fdsan_set_error_level; android_get_device_api_level; + getloadavg; pthread_sigqueue; reallocarray; timespec_get; diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp index 6e41555b5..1c3e1d1ee 100644 --- a/tests/stdlib_test.cpp +++ b/tests/stdlib_test.cpp @@ -816,3 +816,35 @@ TEST(stdlib, llabs) { ASSERT_EQ(LLONG_MAX, llabs(-LLONG_MAX)); ASSERT_EQ(LLONG_MAX, llabs(LLONG_MAX)); } + +TEST(stdlib, getloadavg) { + double load[3]; + + // The second argument should have been size_t. + ASSERT_EQ(-1, getloadavg(load, -1)); + ASSERT_EQ(-1, getloadavg(load, INT_MIN)); + + // Zero is a no-op. + ASSERT_EQ(0, getloadavg(load, 0)); + + // The Linux kernel doesn't support more than 3 (but you can ask for fewer). + ASSERT_EQ(1, getloadavg(load, 1)); + ASSERT_EQ(2, getloadavg(load, 2)); + ASSERT_EQ(3, getloadavg(load, 3)); + ASSERT_EQ(3, getloadavg(load, 4)); + ASSERT_EQ(3, getloadavg(load, INT_MAX)); + + // Read /proc/loadavg and check that it's "close enough". + load[0] = nan(""); + double expected[3]; + std::unique_ptr<FILE, decltype(&fclose)> fp{fopen("/proc/loadavg", "re"), fclose}; + ASSERT_EQ(3, fscanf(fp.get(), "%lf %lf %lf", &expected[0], &expected[1], &expected[2])); + ASSERT_EQ(3, getloadavg(load, 3)); + + // It's probably too flaky if we look at the 1-minute average, so we just place a NaN there + // and check that it's overwritten with _something_. + ASSERT_FALSE(isnan(load[0])); + // For the others, rounding to an integer is pessimistic but at least gives us a sanity check. + ASSERT_DOUBLE_EQ(rint(expected[1]), rint(load[1])); + ASSERT_DOUBLE_EQ(rint(expected[2]), rint(load[2])); +} |