Merge "Remove SIZE_MAX definition in limits.h"
diff --git a/libc/Android.mk b/libc/Android.mk
index 3faa47f..44bf388 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -292,6 +292,7 @@
upstream-netbsd/lib/libc/stdlib/ldiv.c \
upstream-netbsd/lib/libc/stdlib/lldiv.c \
upstream-netbsd/lib/libc/stdlib/lrand48.c \
+ upstream-netbsd/lib/libc/stdlib/lsearch.c \
upstream-netbsd/lib/libc/stdlib/mrand48.c \
upstream-netbsd/lib/libc/stdlib/nrand48.c \
upstream-netbsd/lib/libc/stdlib/_rand48.c \
diff --git a/libc/arch-x86/string/cache.h b/libc/arch-x86/string/cache.h
index d9aff5c..9d0a563 100644
--- a/libc/arch-x86/string/cache.h
+++ b/libc/arch-x86/string/cache.h
@@ -28,8 +28,15 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(__slm__)
+/* Values are optimized for Silvermont */
+#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */
+#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */
+#else
/* Values are optimized for Atom */
#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */
#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */
+#endif
+
#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2)
#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2)
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index 85f7791..4fa4b6e 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -379,7 +379,7 @@
if (gMallocDebugBacklog == 0) {
gMallocDebugBacklog = BACKLOG_DEFAULT_LEN;
}
- so_name = "/system/lib/libc_malloc_debug_leak.so";
+ so_name = "libc_malloc_debug_leak.so";
break;
}
case 20:
@@ -395,7 +395,7 @@
__progname);
return;
}
- so_name = "/system/lib/libc_malloc_debug_qemu.so";
+ so_name = "libc_malloc_debug_qemu.so";
break;
default:
error_log("%s: Debug level %d is unknown\n", __progname, gMallocDebugLevel);
diff --git a/libc/include/search.h b/libc/include/search.h
index 1301a08..b2c0e6b 100644
--- a/libc/include/search.h
+++ b/libc/include/search.h
@@ -10,29 +10,34 @@
#define _SEARCH_H_
#include <sys/cdefs.h>
+#include <sys/types.h>
-typedef enum {
- preorder,
- postorder,
- endorder,
- leaf
+typedef enum {
+ preorder,
+ postorder,
+ endorder,
+ leaf
} VISIT;
#ifdef _SEARCH_PRIVATE
-typedef struct node {
- char *key;
- struct node *llink, *rlink;
+typedef struct node {
+ char* key;
+ struct node* llink;
+ struct node* rlink;
} node_t;
#endif
__BEGIN_DECLS
-void *tdelete(const void * __restrict, void ** __restrict,
- int (*)(const void *, const void *));
-void *tfind(const void *, void * const *,
- int (*)(const void *, const void *));
-void *tsearch(const void *, void **, int (*)(const void *, const void *));
-void twalk(const void *, void (*)(const void *, VISIT, int));
-void tdestroy(void *, void (*)(void *));
+
+void* lfind(const void*, const void*, size_t*, size_t, int (*)(const void*, const void*));
+void* lsearch(const void*, void*, size_t*, size_t, int (*)(const void*, const void*));
+
+void* tdelete(const void* __restrict, void** __restrict, int (*)(const void*, const void*));
+void tdestroy(void*, void (*)(void*));
+void* tfind(const void*, void* const*, int (*)(const void*, const void*));
+void* tsearch(const void*, void**, int (*)(const void*, const void*));
+void twalk(const void*, void (*)(const void*, VISIT, int));
+
__END_DECLS
#endif /* !_SEARCH_H_ */
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index 5001b2e..86fd3cf 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -284,6 +284,7 @@
#endif
__socketcall int accept(int, struct sockaddr*, socklen_t*);
+__socketcall int accept4(int, struct sockaddr*, socklen_t*, int);
__socketcall int bind(int, const struct sockaddr*, int);
__socketcall int connect(int, const struct sockaddr*, socklen_t);
__socketcall int getpeername(int, struct sockaddr*, socklen_t*);
@@ -298,7 +299,6 @@
__socketcall int shutdown(int, int);
__socketcall int socket(int, int, int);
__socketcall int socketpair(int, int, int, int*);
-__socketcall int accept4(int, struct sockaddr*, socklen_t*, int);
extern ssize_t send(int, const void*, size_t, int);
extern ssize_t recv(int, void*, size_t, int);
diff --git a/libc/include/sys/socketcalls.h b/libc/include/sys/socketcalls.h
index 09c079f..131e0bb 100644
--- a/libc/include/sys/socketcalls.h
+++ b/libc/include/sys/socketcalls.h
@@ -48,5 +48,7 @@
#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
#define SYS_ACCEPT4 18 /* sys_accept4(2) */
+#define SYS_RECVMMSG 19 /* sys_recvmmsg(2) */
+#define SYS_SENDMMSG 20 /* sys_sendmmsg(2) */
#endif /* _SYS_SOCKETCALLS_H_ */
diff --git a/libc/upstream-netbsd/lib/libc/stdlib/lsearch.c b/libc/upstream-netbsd/lib/libc/stdlib/lsearch.c
new file mode 100644
index 0000000..e17130b
--- /dev/null
+++ b/libc/upstream-netbsd/lib/libc/stdlib/lsearch.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Roger L. Snyder.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)lsearch.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: lsearch.c,v 1.7 2012/06/25 22:32:45 abs Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <search.h>
+
+typedef int (*cmp_fn_t)(const void *, const void *);
+static void *linear_base(const void *, void *, size_t *, size_t,
+ cmp_fn_t, int);
+
+void *
+lsearch(const void *key, void *base, size_t *nelp, size_t width,
+ cmp_fn_t compar)
+{
+
+ _DIAGASSERT(key != NULL);
+ _DIAGASSERT(base != NULL);
+ _DIAGASSERT(compar != NULL);
+
+ return(linear_base(key, base, nelp, width, compar, 1));
+}
+
+void *
+lfind(const void *key, const void *base, size_t *nelp, size_t width,
+ cmp_fn_t compar)
+{
+
+ _DIAGASSERT(key != NULL);
+ _DIAGASSERT(base != NULL);
+ _DIAGASSERT(compar != NULL);
+
+ return(linear_base(key, __UNCONST(base), nelp, width, compar, 0));
+}
+
+static void *
+linear_base(const void *key, void *base, size_t *nelp, size_t width,
+ cmp_fn_t compar, int add_flag)
+{
+ char *element, *end;
+
+ _DIAGASSERT(key != NULL);
+ _DIAGASSERT(base != NULL);
+ _DIAGASSERT(compar != NULL);
+
+ end = (char *)base + *nelp * width;
+ for (element = (char *)base; element < end; element += width)
+ if (!compar(element, key)) /* key found */
+ return element;
+
+ if (!add_flag) /* key not found */
+ return(NULL);
+
+ /*
+ * The UNIX System User's Manual, 1986 edition claims that
+ * a NULL pointer is returned by lsearch with errno set
+ * appropriately, if there is not enough room in the table
+ * to add a new item. This can't be done as none of these
+ * routines have any method of determining the size of the
+ * table. This comment isn't in the 1986-87 System V
+ * manual.
+ */
+ ++*nelp;
+ memcpy(end, key, width);
+ return end;
+}
diff --git a/linker/Android.mk b/linker/Android.mk
index c517a30..f0e6c13 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -1,6 +1,5 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
-LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
diff --git a/tests/Android.mk b/tests/Android.mk
index 788dbcf..7482ebc 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -82,7 +82,6 @@
system_properties_test.cpp \
time_test.cpp \
unistd_test.cpp \
- accept4_test.cpp \
libBionicStandardTests_cflags := \
$(test_cflags) \
diff --git a/tests/accept4_test.cpp b/tests/accept4_test.cpp
deleted file mode 100644
index 2e6c808..0000000
--- a/tests/accept4_test.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Contributed by: Intel Corporation, 2014
- */
-
-#include <gtest/gtest.h>
-
-#if defined(__BIONIC__)
- #define SOCK_CLOEXEC_SUPPORTED 1
-#elif defined(__GLIBC_PREREQ)
- #if __GLIBC_PREREQ(2, 9)
- #define SOCK_CLOEXEC_SUPPORTED 1
- #endif
-#endif
-
-#if defined(SOCK_CLOEXEC_SUPPORTED)
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <fcntl.h>
-
-#define SOCK_PATH "test"
-
-static void* ConnectFn(void*) {
- int fd = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (fd < 0) {
- GTEST_LOG_(ERROR) << "socket call failed: " << strerror(errno);
- return reinterpret_cast<void*>(-1);
- }
-
- struct sockaddr_un addr;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- addr.sun_path[0] = '\0';
- strcpy(addr.sun_path + 1, SOCK_PATH);
-
- if (connect(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
- GTEST_LOG_(ERROR) << "connect call failed: " << strerror(errno);
- close(fd);
- return reinterpret_cast<void*>(-1);
- }
-
- close(fd);
-
- return NULL;
-}
-#endif
-
-TEST(accept4, smoke) {
-#if defined(SOCK_CLOEXEC_SUPPORTED)
- int fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
- ASSERT_NE(fd, -1) << strerror(errno);
-
- struct sockaddr_un addr;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- addr.sun_path[0] = '\0';
- strcpy(addr.sun_path + 1, SOCK_PATH);
-
- ASSERT_NE(-1, bind(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) << strerror(errno);
-
- ASSERT_NE(-1, listen(fd, 1)) << strerror(errno);
-
- pthread_t thread;
- ASSERT_EQ(0, pthread_create(&thread, NULL, ConnectFn, NULL));
-
- fd_set read_set;
- FD_ZERO(&read_set);
- FD_SET(fd, &read_set);
- timeval tv;
- tv.tv_sec = 5;
- tv.tv_usec = 0;
- ASSERT_LT(0, select(fd+1, &read_set, NULL, NULL, &tv));
-
- socklen_t len = sizeof(addr);
- int fd_acc = accept4(fd, reinterpret_cast<struct sockaddr*>(&addr), &len, SOCK_CLOEXEC);
- ASSERT_NE(fd_acc, -1) << strerror(errno);
-
- // Check that the flag was set properly.
- ASSERT_EQ(FD_CLOEXEC, fcntl(fd_acc, F_GETFD) & FD_CLOEXEC);
-
- void* ret_val;
- pthread_join(thread, &ret_val);
- ASSERT_EQ(NULL, ret_val);
-
- close(fd_acc);
- close(fd);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/tests/math_test.cpp b/tests/math_test.cpp
index 80083fa..c1a9f4f 100644
--- a/tests/math_test.cpp
+++ b/tests/math_test.cpp
@@ -1226,6 +1226,11 @@
double di;
double df = modf(123.456, &di);
ASSERT_DOUBLE_EQ(123.0, di);
+ // ASSERT_DOUBLE uses more decimals than the double precision when performing
+ // the comparison which can result in false failures. And it seems that modf
+ // results are not 100% precise as expected but within the acceptable delta.
+ // Work around this by tweaking the expected value (taken) from the result of
+ // glibc modf).
ASSERT_DOUBLE_EQ(0.45600000000000307, df);
}
@@ -1233,6 +1238,7 @@
float fi;
float ff = modff(123.456f, &fi);
ASSERT_FLOAT_EQ(123.0f, fi);
+ // See modf comment on why we don't use 0.456f as an excepted value.
ASSERT_FLOAT_EQ(0.45600128f, ff);
}
@@ -1240,7 +1246,14 @@
long double ldi;
long double ldf = modfl(123.456l, &ldi);
ASSERT_DOUBLE_EQ(123.0l, ldi);
- ASSERT_DOUBLE_EQ(0.45600000000000002l, ldf);
+ // See modf comment on why we don't use 0.456l as an excepted value when the
+ // modf == modfl. For LP64, where long double != double, modfl algorithm
+ // gives precise results and thus we don't need to tweak the expected value.
+#if defined(__LP64__) || !defined(__BIONIC__)
+ ASSERT_DOUBLE_EQ(0.456l, ldf);
+#else
+ ASSERT_DOUBLE_EQ(0.45600000000000307, ldf);
+#endif // __LP64__ || !__BIONIC__
}
TEST(math, remquo) {
diff --git a/tests/sys_select_test.cpp b/tests/sys_select_test.cpp
index 4bb2d18..5252e6b 100644
--- a/tests/sys_select_test.cpp
+++ b/tests/sys_select_test.cpp
@@ -43,6 +43,32 @@
EXPECT_FALSE(FD_ISSET(1, &fds));
}
+#define DELAY_MSG "1234"
+
+static void DelayedWrite(int* pid, int* fd) {
+ int fds[2];
+ ASSERT_EQ(0, pipe(fds));
+
+ if ((*pid = fork()) == 0) {
+ close(fds[0]);
+ usleep(5000);
+ EXPECT_EQ(5, write(fds[1], DELAY_MSG, sizeof(DELAY_MSG)));
+ close(fds[1]);
+ exit(0);
+ }
+ ASSERT_LT(0, *pid);
+ close(fds[1]);
+
+ *fd = fds[0];
+}
+
+static void DelayedWriteCleanup(int pid, int fd) {
+ char buf[sizeof(DELAY_MSG)];
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(DELAY_MSG)), read(fd, buf, sizeof(DELAY_MSG)));
+ ASSERT_STREQ(DELAY_MSG, buf);
+ ASSERT_EQ(pid, waitpid(pid, NULL, 0));
+}
+
TEST(sys_select, select_smoke) {
fd_set r;
FD_ZERO(&r);
@@ -72,8 +98,17 @@
// Valid timeout...
tv.tv_sec = 1;
- ASSERT_EQ(2, select(max, &r, &w, &e, &tv));
- ASSERT_NE(0, tv.tv_usec); // ...which got updated.
+ int pid, fd;
+ DelayedWrite(&pid, &fd);
+
+ FD_ZERO(&r);
+ FD_SET(fd, &r);
+ ASSERT_EQ(1, select(fd+1, &r, NULL, NULL, &tv));
+ // Both tv_sec and tv_nsec should have been updated.
+ ASSERT_EQ(0, tv.tv_sec);
+ ASSERT_NE(0, tv.tv_usec);
+
+ DelayedWriteCleanup(pid, fd);
}
TEST(sys_select, pselect_smoke) {
@@ -109,6 +144,15 @@
// Valid timeout...
tv.tv_sec = 1;
- ASSERT_EQ(2, pselect(max, &r, &w, &e, &tv, &ss));
- ASSERT_EQ(0, tv.tv_nsec); // ...which did _not_ get updated.
+ int pid, fd;
+ DelayedWrite(&pid, &fd);
+
+ FD_ZERO(&r);
+ FD_SET(fd, &r);
+ ASSERT_EQ(1, pselect(fd+1, &r, NULL, NULL, &tv, NULL));
+ // Neither tv_sec nor tv_nsec should have been updated.
+ ASSERT_EQ(1, tv.tv_sec);
+ ASSERT_EQ(0, tv.tv_nsec);
+
+ DelayedWriteCleanup(pid, fd);
}
diff --git a/tests/sys_socket_test.cpp b/tests/sys_socket_test.cpp
index 901ac17..018889a 100644
--- a/tests/sys_socket_test.cpp
+++ b/tests/sys_socket_test.cpp
@@ -17,18 +17,257 @@
#include <gtest/gtest.h>
#include <errno.h>
+#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
-TEST(sys_socket, recvmmsg) {
-#if !defined(__GLIBC__) // TODO: Android's prebuilt gcc is too old for recvmmsg/sendmmsg.
- ASSERT_EQ(-1, recvmmsg(-1, NULL, 0, 0, NULL));
+#if defined(__BIONIC__)
+ #define ACCEPT4_SUPPORTED 1
+ #define RECVMMSG_SUPPORTED 1
+ #define SENDMMSG_SUPPORTED 1
+#elif defined(__GLIBC_PREREQ)
+ #if __GLIBC_PREREQ(2, 9)
+ #define ACCEPT4_SUPPORTED 1
+ #endif
+ #if __GLIBC_PREREQ(2, 12)
+ #define RECVMMSG_SUPPORTED 1
+ #endif
+ #if __GLIBC_PREREQ(2, 14)
+ #define SENDMMSG_SUPPORTED 1
+ #endif
+#endif
+
+#if defined(ACCEPT4_SUPPORTED) || defined(RECVMMSG_SUPPORTED) || defined(SENDMMSG_SUPPORTED)
+
+#define SOCK_PATH "test"
+
+static void* ConnectFn(void* data) {
+ bool (*callback_fn)(int) = reinterpret_cast<bool (*)(int)>(data);
+ void* return_value = NULL;
+
+ int fd = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+ if (fd < 0) {
+ GTEST_LOG_(ERROR) << "socket call failed: " << strerror(errno);
+ return reinterpret_cast<void*>(-1);
+ }
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = '\0';
+ strcpy(addr.sun_path + 1, SOCK_PATH);
+
+ if (connect(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
+ GTEST_LOG_(ERROR) << "connect call failed: " << strerror(errno);
+ return_value = reinterpret_cast<void*>(-1);
+ }
+ else if (callback_fn != NULL && !callback_fn(fd)) {
+ return_value = reinterpret_cast<void*>(-1);
+ }
+
+ close(fd);
+
+ return return_value;
+}
+
+static void RunTest(void (*test_fn)(struct sockaddr_un*, int),
+ bool (*callback_fn)(int fd)) {
+ int fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
+ ASSERT_NE(fd, -1) << strerror(errno);
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = '\0';
+ strcpy(addr.sun_path + 1, SOCK_PATH);
+
+ ASSERT_NE(-1, bind(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) << strerror(errno);
+
+ ASSERT_NE(-1, listen(fd, 1)) << strerror(errno);
+
+ pthread_t thread;
+ ASSERT_EQ(0, pthread_create(&thread, NULL, ConnectFn, reinterpret_cast<void*>(callback_fn)));
+
+ fd_set read_set;
+ FD_ZERO(&read_set);
+ FD_SET(fd, &read_set);
+ timeval tv;
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ ASSERT_LT(0, select(fd+1, &read_set, NULL, NULL, &tv));
+
+ test_fn(&addr, fd);
+
+ void* ret_val;
+ ASSERT_EQ(0, pthread_join(thread, &ret_val));
+ ASSERT_EQ(NULL, ret_val);
+
+ close(fd);
+}
+#endif
+
+TEST(sys_socket, accept4_error) {
+#if defined(ACCEPT4_SUPPORTED)
+ ASSERT_EQ(-1, accept4(-1, NULL, NULL, 0));
ASSERT_EQ(EBADF, errno);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-TEST(sys_socket, sendmmsg) {
-#if !defined(__GLIBC__) // TODO: Android's prebuilt gcc is too old for recvmmsg/sendmmsg.
+#if defined(ACCEPT4_SUPPORTED)
+static void TestAccept4(struct sockaddr_un* addr, int fd) {
+ socklen_t len = sizeof(*addr);
+ int fd_acc = accept4(fd, reinterpret_cast<struct sockaddr*>(addr), &len, SOCK_CLOEXEC);
+ ASSERT_NE(fd_acc, -1) << strerror(errno);
+
+ // Check that the flag was set properly.
+ ASSERT_EQ(FD_CLOEXEC, fcntl(fd_acc, F_GETFD) & FD_CLOEXEC);
+
+ close(fd_acc);
+}
+#endif
+
+TEST(sys_socket, accept4_smoke) {
+#if defined(ACCEPT4_SUPPORTED)
+ RunTest(TestAccept4, NULL);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+#if defined(RECVMMSG_SUPPORTED)
+const char* g_RecvMsgs[] = {
+ "RECVMMSG_ONE",
+ "RECVMMSG_TWO",
+ "RECVMMSG_THREE",
+};
+#define NUM_RECV_MSGS (sizeof(g_RecvMsgs)/sizeof(const char*))
+
+static bool SendMultiple(int fd) {
+ for (size_t i = 0; i < NUM_RECV_MSGS; i++) {
+ if (send(fd, g_RecvMsgs[i], strlen(g_RecvMsgs[i]) + 1, 0) < 0) {
+ GTEST_LOG_(ERROR) << "send call failed: " << strerror(errno);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void TestRecvMMsg(struct sockaddr_un *addr, int fd) {
+ socklen_t len = sizeof(*addr);
+ int fd_acc = accept(fd, reinterpret_cast<struct sockaddr*>(addr), &len);
+ ASSERT_NE(fd_acc, -1) << strerror(errno);
+
+ struct mmsghdr msgs[NUM_RECV_MSGS];
+ memset(msgs, 0, sizeof(struct mmsghdr)*NUM_RECV_MSGS);
+
+ struct iovec io[NUM_RECV_MSGS];
+ char bufs[NUM_RECV_MSGS][100];
+ for (size_t i = 0; i < NUM_RECV_MSGS; i++) {
+ io[i].iov_base = reinterpret_cast<void*>(bufs[i]);
+ io[i].iov_len = strlen(g_RecvMsgs[i]) + 1;
+
+ msgs[i].msg_hdr.msg_iov = &io[i];
+ msgs[i].msg_hdr.msg_iovlen = 1;
+ msgs[i].msg_len = sizeof(struct msghdr);
+ }
+
+ struct timespec ts;
+ memset(&ts, 0, sizeof(ts));
+ ts.tv_sec = 5;
+ ts.tv_nsec = 0;
+ ASSERT_EQ(NUM_RECV_MSGS, recvmmsg(fd_acc, msgs, NUM_RECV_MSGS, 0, &ts)) << strerror(errno);
+ for (size_t i = 0; i < NUM_RECV_MSGS; i++) {
+ ASSERT_STREQ(g_RecvMsgs[i], bufs[i]);
+ }
+
+ close(fd_acc);
+}
+#endif
+
+TEST(sys_socket, recvmmsg_smoke) {
+#if defined(RECVMMSG_SUPPORTED)
+ RunTest(TestRecvMMsg, SendMultiple);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(sys_socket, recvmmsg_error) {
+#if defined(RECVMMSG_SUPPORTED)
+ ASSERT_EQ(-1, recvmmsg(-1, NULL, 0, 0, NULL));
+ ASSERT_EQ(EBADF, errno);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+#if defined(SENDMMSG_SUPPORTED)
+const char* g_SendMsgs[] = {
+ "MSG_ONE",
+ "MSG_TWO",
+ "MSG_THREE"
+};
+#define NUM_SEND_MSGS (sizeof(g_SendMsgs)/sizeof(const char*))
+
+static bool SendMMsg(int fd) {
+ struct mmsghdr msgs[NUM_SEND_MSGS];
+ memset(msgs, 0, sizeof(struct mmsghdr)*NUM_SEND_MSGS);
+ struct iovec io[NUM_SEND_MSGS];
+ for (size_t i = 0; i < NUM_SEND_MSGS; i++) {
+ io[i].iov_base = reinterpret_cast<void*>(const_cast<char*>(g_SendMsgs[i]));
+ io[i].iov_len = strlen(g_SendMsgs[i]) + 1;
+ msgs[i].msg_hdr.msg_iov = &io[i];
+ msgs[i].msg_hdr.msg_iovlen = 1;
+ msgs[i].msg_len = sizeof(struct msghdr);
+ }
+
+ if (sendmmsg(fd, msgs, NUM_SEND_MSGS, 0) < 0) {
+ GTEST_LOG_(ERROR) << "sendmmsg call failed: " << strerror(errno);
+ return false;
+ }
+ return true;
+}
+
+static void TestSendMMsg(struct sockaddr_un *addr, int fd) {
+ socklen_t len = sizeof(*addr);
+ int fd_acc = accept(fd, reinterpret_cast<struct sockaddr*>(addr), &len);
+ ASSERT_NE(fd_acc, -1) << strerror(errno);
+
+ fd_set read_set;
+ FD_ZERO(&read_set);
+ FD_SET(fd_acc, &read_set);
+
+ for (size_t i = 0; i < NUM_SEND_MSGS; i++) {
+ timeval tv;
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ ASSERT_LT(0, select(fd_acc+1, &read_set, NULL, NULL, &tv));
+ char buffer[100];
+ ASSERT_EQ(strlen(g_SendMsgs[i]) + 1, recv(fd_acc, buffer, sizeof(buffer), 0));
+ ASSERT_STREQ(g_SendMsgs[i], buffer);
+ }
+
+ close(fd_acc);
+}
+#endif
+
+TEST(sys_socket, sendmmsg_smoke) {
+#if defined(SENDMMSG_SUPPORTED)
+ RunTest(TestSendMMsg, SendMMsg);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(sys_socket, sendmmsg_error) {
+#if defined(SENDMMSG_SUPPORTED)
ASSERT_EQ(-1, sendmmsg(-1, NULL, 0, 0));
ASSERT_EQ(EBADF, errno);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}