Add getloadavg(3).
Lets us build ninja with bionic.
Bug: N/A
Test: ran tests
Change-Id: I97eef1247d794b58a2b9aee4851551632e5a4e48
diff --git a/docs/status.md b/docs/status.md
index 0106ccd..54385a4 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -42,6 +42,7 @@
* `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 1fc3062..681394f 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1314,6 +1314,7 @@
"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 0000000..28d316c
--- /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 6888e8c..96a77a7 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -147,6 +147,15 @@
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 a22a8df..bd39d42 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1432,6 +1432,7 @@
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 55fd587..81ff00d 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1353,6 +1353,7 @@
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 304dbb7..934ad1f 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1457,6 +1457,7 @@
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 397ff72..dc184a6 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1416,6 +1416,7 @@
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 55fd587..81ff00d 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1353,6 +1353,7 @@
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 a18657c..f360dbf 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1414,6 +1414,7 @@
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 55fd587..81ff00d 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1353,6 +1353,7 @@
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 6e41555..1c3e1d1 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -816,3 +816,35 @@
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]));
+}