From 5afae64a1bac56638c6348f0c8f5e9d61b654029 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Tue, 25 Nov 2014 20:17:27 -0800 Subject: [PATCH] implement posix_madvise Bug: 18472477 Change-Id: I8183de6c281acf69ed5f7f88351b056b9827b162 --- libc/Android.mk | 1 + libc/bionic/posix_madvise.cpp | 42 ++++++++++++++++++++++++++++ libc/include/machine/posix_limits.h | 2 +- libc/include/sys/mman.h | 8 ++++++ tests/sys_mman_test.cpp | 43 +++++++++++++++++++++++++++++ tests/unistd_test.cpp | 6 ++-- 6 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 libc/bionic/posix_madvise.cpp diff --git a/libc/Android.mk b/libc/Android.mk index 2270dc607..f04cf5cd5 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -153,6 +153,7 @@ libc_bionic_src_files := \ bionic/poll.cpp \ bionic/posix_fadvise.cpp \ bionic/posix_fallocate.cpp \ + bionic/posix_madvise.cpp \ bionic/posix_timers.cpp \ bionic/pthread_atfork.cpp \ bionic/pthread_attr.cpp \ diff --git a/libc/bionic/posix_madvise.cpp b/libc/bionic/posix_madvise.cpp new file mode 100644 index 000000000..d77be0178 --- /dev/null +++ b/libc/bionic/posix_madvise.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 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 +#include + +#include "private/ErrnoRestorer.h" + +int posix_madvise(void* addr, size_t len, int advice) { + ErrnoRestorer errno_restorer; + + // Don't call madvise() on POSIX_MADV_DONTNEED, it will make the space not available. + if (advice == POSIX_MADV_DONTNEED) { + return 0; + } + return (madvise(addr, len, advice) == 0 ? 0 : errno); +} diff --git a/libc/include/machine/posix_limits.h b/libc/include/machine/posix_limits.h index 939a1de5b..25887bef6 100644 --- a/libc/include/machine/posix_limits.h +++ b/libc/include/machine/posix_limits.h @@ -32,7 +32,7 @@ /* Any constant values here other than -1 or 200809L are explicitly specified by POSIX.1-2008. */ /* Keep it sorted. */ -#define _POSIX_ADVISORY_INFO -1 /* posix_madvise() not implemented */ +#define _POSIX_ADVISORY_INFO 200809L #define _POSIX_AIO_LISTIO_MAX 2 #define _POSIX_AIO_MAX 1 #define _POSIX_ARG_MAX 4096 diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h index 09bf0d914..166322269 100644 --- a/libc/include/sys/mman.h +++ b/libc/include/sys/mman.h @@ -43,6 +43,12 @@ __BEGIN_DECLS #define MREMAP_MAYMOVE 1 #define MREMAP_FIXED 2 +#define POSIX_MADV_NORMAL MADV_NORMAL +#define POSIX_MADV_RANDOM MADV_RANDOM +#define POSIX_MADV_SEQUENTIAL MADV_SEQUENTIAL +#define POSIX_MADV_WILLNEED MADV_WILLNEED +#define POSIX_MADV_DONTNEED MADV_DONTNEED + extern void* mmap(void*, size_t, int, int, int, off_t); extern void* mmap64(void*, size_t, int, int, int, off64_t); extern int munmap(void*, size_t); @@ -61,6 +67,8 @@ extern int munlock(const void*, size_t); extern int mincore(void*, size_t, unsigned char*); +extern int posix_madvise(void*, size_t, int); + __END_DECLS #endif /* _SYS_MMAN_H_ */ diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp index 75ccfa3b2..b0e40fdd6 100644 --- a/tests/sys_mman_test.cpp +++ b/tests/sys_mman_test.cpp @@ -172,3 +172,46 @@ TEST(sys_mman, mmap_file_write_at_offset) { ASSERT_STREQ(NEWPAGE2_MSG, buf); ASSERT_STREQ(END_MSG, buf+pagesize-sizeof(END_MSG)); } + +TEST(sys_mman, posix_madvise) { + TemporaryFile tempfile; + size_t pagesize = sysconf(_SC_PAGESIZE); + char buf[pagesize]; + + // Prepare environment. + ASSERT_EQ(static_cast(pagesize), write(tempfile.fd, buf, pagesize)); + void* map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, tempfile.fd, 0); + ASSERT_NE(MAP_FAILED, map); + + // Verify different options of posix_madvise. + ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_NORMAL)); + ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_SEQUENTIAL)); + ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_RANDOM)); + ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_WILLNEED)); + + ASSERT_EQ(0, munmap(map, pagesize)); +} + +// Verify that memory can still access after posix_madvise(POSIX_MADV_DONTNEED). +// We should test on MAP_ANONYMOUS memory to verify whether the memory is discarded, +// because the content of non MAP_ANONYMOUS memory can be reread from file. +TEST(sys_mman, posix_madvise_POSIX_MADV_DONTNEED) { + size_t pagesize = sysconf(_SC_PAGESIZE); + + void* map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, map); + + int* int_ptr = reinterpret_cast(map); + for (int i = 0; i < static_cast(pagesize / sizeof(int)); ++i) { + *int_ptr++ = i; + } + + ASSERT_EQ(0, posix_madvise(map, pagesize, POSIX_MADV_DONTNEED)); + + int_ptr = reinterpret_cast(map); + for (int i = 0; i < static_cast(pagesize / sizeof(int)); ++i) { + ASSERT_EQ(i, *int_ptr++); + } + + ASSERT_EQ(0, munmap(map, pagesize)); +} diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp index 34b7bf342..b37687f18 100644 --- a/tests/unistd_test.cpp +++ b/tests/unistd_test.cpp @@ -523,6 +523,7 @@ TEST(unistd, _POSIX_macros_smoke) { // Verify according to POSIX.1-2008. EXPECT_EQ(200809L, _POSIX_VERSION); + EXPECT_EQ(_POSIX_VERSION, _POSIX_ADVISORY_INFO); EXPECT_GT(_POSIX_AIO_LISTIO_MAX, 0); EXPECT_GT(_POSIX_AIO_MAX, 0); EXPECT_GT(_POSIX_ARG_MAX, 0); @@ -611,8 +612,7 @@ TEST(unistd, _POSIX_macros_smoke) { #if defined(__BIONIC__) // These tests only pass on bionic, as bionic and glibc has different support on these macros. - // Macros like _POSIX_ADVISORY_INFO are not supported on bionic yet. - EXPECT_EQ(-1, _POSIX_ADVISORY_INFO); + // Macros like _POSIX_ASYNCHRONOUS_IO are not supported on bionic yet. EXPECT_EQ(-1, _POSIX_ASYNCHRONOUS_IO); EXPECT_EQ(-1, _POSIX_BARRIERS); EXPECT_EQ(-1, _POSIX_MESSAGE_PASSING); @@ -658,6 +658,7 @@ static void VerifySysconf(int option, const char *option_name, bool (*verify)(lo } TEST(unistd, sysconf) { + VERIFY_SYSCONF_POSIX_VERSION(_SC_ADVISORY_INFO); VERIFY_SYSCONF_POSITIVE(_SC_ARG_MAX); VERIFY_SYSCONF_POSITIVE(_SC_BC_BASE_MAX); VERIFY_SYSCONF_POSITIVE(_SC_BC_DIM_MAX); @@ -773,7 +774,6 @@ TEST(unistd, sysconf) { #if defined(__BIONIC__) // Tests can only run on bionic, as bionic and glibc have different support for these options. // Below options are not supported on bionic yet. - VERIFY_SYSCONF_NOT_SUPPORT(_SC_ADVISORY_INFO); VERIFY_SYSCONF_NOT_SUPPORT(_SC_ASYNCHRONOUS_IO); VERIFY_SYSCONF_NOT_SUPPORT(_SC_BARRIERS); VERIFY_SYSCONF_NOT_SUPPORT(_SC_MESSAGE_PASSING);