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
 }