Add POSIX qsort_r().
POSIX added this to issue 8, based on https://www.austingroupbugs.net/view.php?id=900.
This is an incompatibility with iOS, which is one reason why I hadn't
added this previously, but FreeBSD (upstream for both Android and iOS in
this case) already moved off their different qsort_r(), so it's possible
Apple will, and in the meantime, at least I now have the defense of
"POSIX says...".
Change-Id: Iab048a3a931010c3276a88d25eb56b38d4d608b1
diff --git a/docs/status.md b/docs/status.md
index 7ebd195..0436c40 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -55,6 +55,9 @@
Current libc symbols: https://android.googlesource.com/platform/bionic/+/main/libc/libc.map.txt
+New libc functions in API level 36:
+ * `qsort_r` (new POSIX addition).
+
New libc functions in V (API level 35):
* New `android_crash_detail_register`, `android_crash_detail_unregister`,
`android_crash_detail_replace_name`, and `android_crash_detail_replace_data`
diff --git a/libc/Android.bp b/libc/Android.bp
index 79b85c5..42ffd37 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -389,6 +389,7 @@
"upstream-freebsd/lib/libc/stdlib/hdestroy_r.c",
"upstream-freebsd/lib/libc/stdlib/hsearch_r.c",
"upstream-freebsd/lib/libc/stdlib/qsort.c",
+ "upstream-freebsd/lib/libc/stdlib/qsort_r.c",
"upstream-freebsd/lib/libc/stdlib/quick_exit.c",
"upstream-freebsd/lib/libc/string/wcpcpy.c",
"upstream-freebsd/lib/libc/string/wcpncpy.c",
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index d0efc4c..b160e6b 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -114,7 +114,20 @@
*/
__wur void* _Nullable bsearch(const void* _Nonnull __key, const void* _Nullable __base, size_t __nmemb, size_t __size, int (* _Nonnull __comparator)(const void* _Nonnull __lhs, const void* _Nonnull __rhs));
-void qsort(void* _Nullable __base, size_t __nmemb, size_t __size, int (* _Nonnull __comparator)(const void* _Nullable __lhs, const void* _Nullable __rhs));
+/**
+ * [qsort(3)](http://man7.org/linux/man-pages/man3/qsort.3.html) sorts an array
+ * of n elements each of the given size, using the given comparator.
+ */
+void qsort(void* _Nullable __array, size_t __n, size_t __size, int (* _Nonnull __comparator)(const void* _Nullable __lhs, const void* _Nullable __rhs));
+
+/**
+ * [qsort_r(3)](http://man7.org/linux/man-pages/man3/qsort_r.3.html) sorts an
+ * array of n elements each of the given size, using the given comparator,
+ * and passing the given context argument to the comparator.
+ *
+ * Available since API level 36.
+ */
+void qsort_r(void* _Nullable __array, size_t __n, size_t __size, int (* _Nonnull __comparator)(const void* _Nullable __lhs, const void* _Nullable __rhs, void* _Nullable __context), void* _Nullable __context) __INTRODUCED_IN(36);
uint32_t arc4random(void);
uint32_t arc4random_uniform(uint32_t __upper_bound);
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index cc2701b..0a4db45 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -844,6 +844,7 @@
pwrite;
pwrite64;
qsort;
+ qsort_r; # introduced=36
quick_exit;
raise;
rand;
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/qsort_r.c b/libc/upstream-freebsd/lib/libc/stdlib/qsort_r.c
new file mode 100644
index 0000000..b382b40
--- /dev/null
+++ b/libc/upstream-freebsd/lib/libc/stdlib/qsort_r.c
@@ -0,0 +1,6 @@
+/*
+ * This file is in the public domain. Originally written by Garrett
+ * A. Wollman.
+ */
+#define I_AM_QSORT_R
+#include "qsort.c"
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index f5e57a5..3216066 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -431,6 +431,31 @@
ASSERT_STREQ("charlie", entries[2].name);
}
+TEST(stdlib, qsort_r) {
+ struct s {
+ char name[16];
+ static int comparator(const void* lhs, const void* rhs, void* context) {
+ int* count_p = reinterpret_cast<int*>(context);
+ *count_p += 1;
+ return strcmp(reinterpret_cast<const s*>(lhs)->name, reinterpret_cast<const s*>(rhs)->name);
+ }
+ };
+ s entries[3];
+ strcpy(entries[0].name, "charlie");
+ strcpy(entries[1].name, "bravo");
+ strcpy(entries[2].name, "alpha");
+
+ int count;
+ void* context = &count;
+
+ count = 0;
+ qsort_r(entries, 3, sizeof(s), s::comparator, context);
+ ASSERT_STREQ("alpha", entries[0].name);
+ ASSERT_STREQ("bravo", entries[1].name);
+ ASSERT_STREQ("charlie", entries[2].name);
+ ASSERT_EQ(count, 3);
+}
+
static void* TestBug57421_child(void* arg) {
pthread_t main_thread = reinterpret_cast<pthread_t>(arg);
pthread_join(main_thread, nullptr);