From d2428633a692d48c4c4c2e4ff677936e2bd612d8 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 8 Mar 2005 09:18:47 +0000 Subject: [PATCH] * mmap.cc (mmap64): Handle MAP_AUTOGROW flag. (fhandler_disk_file::mmap): Ditto. Clean conditional for readability. * include/sys/mman.h: Add MAP_AUTOGROW flag. * include/cygwin/version.h: Bump API minor version. --- winsup/cygwin/ChangeLog | 7 +++ winsup/cygwin/include/cygwin/version.h | 3 +- winsup/cygwin/include/sys/mman.h | 3 ++ winsup/cygwin/mmap.cc | 69 ++++++++++++++++++++++---- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a94ab0a46..eea18c3d4 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,10 @@ +2005-03-07 Corinna Vinschen + + * mmap.cc (mmap64): Handle MAP_AUTOGROW flag. + (fhandler_disk_file::mmap): Ditto. Clean conditional for readability. + * include/sys/mman.h: Add MAP_AUTOGROW flag. + * include/cygwin/version.h: Bump API minor version. + 2005-03-08 Christopher Faylor * dcrt0.cc (dll_crt0_0): Eliminate muto::init call. diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 6d965fdff..6b3ed586b 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -250,12 +250,13 @@ details. */ 120: Export basename, dirname. 122: Export statvfs, fstatvfs. 123: Export utmpxname. + 124: Add MAP_AUTOGROW flag to mmap. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 123 +#define CYGWIN_VERSION_API_MINOR 124 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/mman.h b/winsup/cygwin/include/sys/mman.h index 3264739c0..21bf6976d 100644 --- a/winsup/cygwin/include/sys/mman.h +++ b/winsup/cygwin/include/sys/mman.h @@ -30,6 +30,9 @@ extern "C" { #define MAP_FIXED 0x10 #define MAP_ANONYMOUS 0x20 #define MAP_ANON MAP_ANONYMOUS +/* Non-standard flag */ +#define MAP_AUTOGROW 0x8000 /* Grow underlying object to mapping size. + File must be opened for writing. */ #define MAP_FAILED ((void *)-1) diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index 9a34ba4d2..e1cda7b44 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -587,10 +587,12 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off) DWORD high; DWORD low = GetFileSize (fh->get_handle (), &high); _off64_t fsiz = ((_off64_t)high << 32) + low; + /* Don't allow mappings beginning beyond EOF since Windows can't - handle that POSIX like. FIXME: Still looking for a good idea - to allow that nevertheless. */ - if (gran_off >= fsiz) + handle that POSIX like, unless MAP_AUTOGROW flag is set, which + mimics Windows behaviour. FIXME: Still looking for a good idea + to allow that under POSIX rules. */ + if (gran_off >= fsiz && !(flags & MAP_AUTOGROW)) { set_errno (ENXIO); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, @@ -598,10 +600,30 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off) return MAP_FAILED; } /* Don't map beyond EOF. Windows would change the file to the - new length otherwise, in contrast to POSIX. */ + new length otherwise, in contrast to POSIX. Allow mapping + beyon EOF if MAP_AUTOGROW flag is set. */ fsiz -= gran_off; if (gran_len > fsiz) - gran_len = fsiz; + { + if ((flags & MAP_AUTOGROW) && (off - gran_off) + len > fsiz) + { + /* Check if file has been opened for writing. */ + if (!(fh->get_access () & GENERIC_WRITE)) + { + set_errno (EINVAL); + ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, + "mmap"); + return MAP_FAILED; + } + gran_len = (off - gran_off) + len; + } + else + gran_len = fsiz; + } + /* If the requested len is <= file size, drop the MAP_AUTOGROW flag. + This simplifes fhandler::mmap's job. */ + if ((flags & MAP_AUTOGROW) && gran_len <= fsiz) + flags &= ~MAP_AUTOGROW; } DWORD access = (prot & PROT_WRITE) ? FILE_MAP_WRITE : FILE_MAP_READ; @@ -1019,6 +1041,7 @@ fhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access, } HANDLE h; + DWORD high, low; /* On 9x/ME try first to open the mapping by name when opening a shared file object. This is needed since 9x/ME only shares @@ -1037,12 +1060,37 @@ fhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access, debug_printf ("named sharing"); if (!(h = OpenFileMapping (access, TRUE, namebuf))) - h = CreateFileMapping (get_handle (), &sec_none, protect, 0, 0, namebuf); + h = CreateFileMapping (get_handle (), &sec_none, protect, 0, 0, + namebuf); + } + else if (get_handle () == INVALID_HANDLE_VALUE) + { + /* Standard anonymous mapping needs non-zero len. */ + h = CreateFileMapping (get_handle (), &sec_none, protect, 0, len, NULL); + } + else if (flags & MAP_AUTOGROW) + { + high = (off + len) >> 32; + low = (off + len) & UINT32_MAX; + /* Auto-grow in CreateFileMapping only works if the protection is + PAGE_READWRITE. So, first we call CreateFileMapping with + PAGE_READWRITE, then, if the requested protection is different, we + close the mapping and reopen it again with the correct protection, + *iff* auto-grow worked. */ + h = CreateFileMapping (get_handle (), &sec_none, PAGE_READWRITE, + high, low, NULL); + if (h && protect != PAGE_READWRITE) + { + CloseHandle (h); + h = CreateFileMapping (get_handle (), &sec_none, protect, + high, low, NULL); + } } else - h = CreateFileMapping (get_handle (), &sec_none, protect, 0, - get_handle () == INVALID_HANDLE_VALUE ? len : 0, - NULL); + { + /* Zero len creates mapping for whole file. */ + h = CreateFileMapping (get_handle (), &sec_none, protect, 0, 0, NULL); + } if (!h) { __seterrno (); @@ -1050,7 +1098,8 @@ fhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access, return INVALID_HANDLE_VALUE; } - DWORD high = off >> 32, low = off & UINT32_MAX; + high = off >> 32; + low = off & UINT32_MAX; void *base = NULL; /* If a non-zero address is given, try mapping using the given address first. If it fails and flags is not MAP_FIXED, try again with NULL address. */