Implement POSIX_MADV_WILLNEED/POSIX_MADV_DONTNEED for newer OSes

* autoload.cc (DiscardVirtualMemory): Import.
        (PrefetchVirtualMemory): Import.
        * mmap.cc (posix_madvise): Actually implement POSIX_MADV_WILLNEED
        utilizing PrefetchVirtualMemory and POSIX_MADV_DONTNEED utilizing
        DiscardVirtualMemory on systems supporting them.
        * wincap.h (wincaps::has_broken_prefetchvm): New element.
        * wincap.cc: Implement above element throughout.
        (wincapc::init): Make sure has_broken_prefetchvm is only true on
        W10 under WOW64.
        * include/cygwin/version.h (CYGWIN_VERSION_DLL_MAJOR): Bump to 2003.
        (CYGWIN_VERSION_API_MINOR): Reset to 0.

        * new-features.xml (ov-new2.3): New section, document posix_madvise
        POSIX_MADV_WILLNEED/POSIX_MADV_DONTNEED change.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen
2015-08-27 13:34:10 +02:00
parent e6d9af11f1
commit 35d5d87540
9 changed files with 149 additions and 21 deletions

View File

@@ -1531,35 +1531,111 @@ munlock (const void *addr, size_t len)
return ret;
}
/* This is required until Mingw-w64 catches up with newer functions. */
extern "C" WINAPI DWORD DiscardVirtualMemory (PVOID, SIZE_T);
extern "C" int
posix_madvise (void *addr, size_t len, int advice)
{
int ret;
int ret = 0;
/* Check parameters. */
if (advice < POSIX_MADV_NORMAL || advice > POSIX_MADV_DONTNEED
|| !len)
ret = EINVAL;
else
{
/* Check requested memory area. */
MEMORY_BASIC_INFORMATION m;
char *p = (char *) addr;
char *endp = p + len;
while (p < endp)
{
if (!VirtualQuery (p, &m, sizeof m) || m.State == MEM_FREE)
{
ret = ENOMEM;
break;
}
p = (char *) m.BaseAddress + m.RegionSize;
}
ret = 0;
ret = EINVAL;
goto out;
}
/* Check requested memory area. */
MEMORY_BASIC_INFORMATION m;
char *p, *endp;
for (p = (char *) addr, endp = p + len;
p < endp;
p = (char *) m.BaseAddress + m.RegionSize)
{
if (!VirtualQuery (p, &m, sizeof m) || m.State == MEM_FREE)
{
ret = ENOMEM;
break;
}
}
if (ret)
goto out;
switch (advice)
{
case POSIX_MADV_WILLNEED:
{
/* Align address and length values to page size. */
size_t pagesize = wincap.allocation_granularity ();
PVOID base = (PVOID) rounddown ((uintptr_t) addr, pagesize);
SIZE_T size = roundup2 (((uintptr_t) addr - (uintptr_t) base)
+ len, pagesize);
WIN32_MEMORY_RANGE_ENTRY me = { base, size };
if (!PrefetchVirtualMemory (GetCurrentProcess (), 1, &me, 0)
&& GetLastError () != ERROR_PROC_NOT_FOUND)
{
/* FIXME 2015-08-27: On W10 build 10240 under WOW64,
PrefetchVirtualMemory always returns ERROR_INVALID_PARAMETER
for some reason. If we're running on W10 WOW64, ignore this
error for now. There's an open case at Microsoft for this. */
if (!wincap.has_broken_prefetchvm ()
|| GetLastError () != ERROR_INVALID_PARAMETER)
ret = EINVAL;
}
}
break;
case POSIX_MADV_DONTNEED:
{
/* Align address and length values to page size. */
size_t pagesize = wincap.allocation_granularity ();
PVOID base = (PVOID) rounddown ((uintptr_t) addr, pagesize);
SIZE_T size = roundup2 (((uintptr_t) addr - (uintptr_t) base)
+ len, pagesize);
DWORD err = DiscardVirtualMemory (base, size);
/* DiscardVirtualMemory is unfortunately pretty crippled:
On copy-on-write pages it returns ERROR_INVALID_PARAMETER, on
any file-backed memory map it returns ERROR_USER_MAPPED_FILE.
Since POSIX_MADV_DONTNEED is advisory only anyway, let them
slip through. */
switch (err)
{
case ERROR_PROC_NOT_FOUND:
case ERROR_USER_MAPPED_FILE:
case 0:
break;
case ERROR_INVALID_PARAMETER:
{
ret = EINVAL;
/* Check if the region contains copy-on-write pages.*/
for (p = (char *) addr, endp = p + len;
p < endp;
p = (char *) m.BaseAddress + m.RegionSize)
{
if (VirtualQuery (p, &m, sizeof m)
&& m.State == MEM_COMMIT
&& m.Protect
& (PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY))
{
/* Yes, let this slip. */
ret = 0;
break;
}
}
}
break;
default:
ret = geterrno_from_win_error (err);
break;
}
}
break;
default:
break;
}
out:
syscall_printf ("%d = posix_madvise(%p, %lu, %d)", ret, addr, len, advice);
/* Eventually do nothing. */
return 0;
return ret;
}
/*