| /* |
| * This code is derived from uClibc (original license follows). |
| * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c |
| */ |
| /* mmap() replacement for Windows |
| * |
| * Author: Mike Frysinger <vapier@gentoo.org> |
| * Placed into the public domain |
| */ |
| |
| /* References: |
| * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx |
| * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx |
| * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx |
| * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx |
| */ |
| |
| #if defined(_WIN32) |
| |
| #include "WindowsMMap.h" |
| |
| #define WIN32_LEAN_AND_MEAN |
| #include <windows.h> |
| |
| #include "InstrProfiling.h" |
| |
| #ifdef __USE_FILE_OFFSET64 |
| # define DWORD_HI(x) (x >> 32) |
| # define DWORD_LO(x) ((x) & 0xffffffff) |
| #else |
| # define DWORD_HI(x) (0) |
| # define DWORD_LO(x) (x) |
| #endif |
| |
| COMPILER_RT_VISIBILITY |
| void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) |
| { |
| if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) |
| return MAP_FAILED; |
| if (fd == -1) { |
| if (!(flags & MAP_ANON) || offset) |
| return MAP_FAILED; |
| } else if (flags & MAP_ANON) |
| return MAP_FAILED; |
| |
| DWORD flProtect; |
| if (prot & PROT_WRITE) { |
| if (prot & PROT_EXEC) |
| flProtect = PAGE_EXECUTE_READWRITE; |
| else |
| flProtect = PAGE_READWRITE; |
| } else if (prot & PROT_EXEC) { |
| if (prot & PROT_READ) |
| flProtect = PAGE_EXECUTE_READ; |
| else if (prot & PROT_EXEC) |
| flProtect = PAGE_EXECUTE; |
| } else |
| flProtect = PAGE_READONLY; |
| |
| off_t end = length + offset; |
| HANDLE mmap_fd, h; |
| if (fd == -1) |
| mmap_fd = INVALID_HANDLE_VALUE; |
| else |
| mmap_fd = (HANDLE)_get_osfhandle(fd); |
| h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); |
| if (h == NULL) |
| return MAP_FAILED; |
| |
| DWORD dwDesiredAccess; |
| if (prot & PROT_WRITE) |
| dwDesiredAccess = FILE_MAP_WRITE; |
| else |
| dwDesiredAccess = FILE_MAP_READ; |
| if (prot & PROT_EXEC) |
| dwDesiredAccess |= FILE_MAP_EXECUTE; |
| if (flags & MAP_PRIVATE) |
| dwDesiredAccess |= FILE_MAP_COPY; |
| void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); |
| if (ret == NULL) { |
| CloseHandle(h); |
| ret = MAP_FAILED; |
| } |
| return ret; |
| } |
| |
| COMPILER_RT_VISIBILITY |
| void munmap(void *addr, size_t length) |
| { |
| UnmapViewOfFile(addr); |
| /* ruh-ro, we leaked handle from CreateFileMapping() ... */ |
| } |
| |
| COMPILER_RT_VISIBILITY |
| int msync(void *addr, size_t length, int flags) |
| { |
| if (flags & MS_INVALIDATE) |
| return -1; /* Not supported. */ |
| |
| /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */ |
| switch (flags & (MS_ASYNC | MS_SYNC)) { |
| case MS_SYNC: |
| case MS_ASYNC: |
| break; |
| default: |
| return -1; |
| } |
| |
| if (!FlushViewOfFile(addr, length)) |
| return -1; |
| |
| if (flags & MS_SYNC) { |
| /* FIXME: No longer have access to handle from CreateFileMapping(). */ |
| /* |
| * if (!FlushFileBuffers(h)) |
| * return -1; |
| */ |
| } |
| |
| return 0; |
| } |
| |
| COMPILER_RT_VISIBILITY |
| int lock(HANDLE handle, DWORD lockType, BOOL blocking) { |
| DWORD flags = lockType; |
| if (!blocking) |
| flags |= LOCKFILE_FAIL_IMMEDIATELY; |
| |
| OVERLAPPED overlapped; |
| ZeroMemory(&overlapped, sizeof(OVERLAPPED)); |
| overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); |
| BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped); |
| if (!result) { |
| DWORD dw = GetLastError(); |
| |
| // In non-blocking mode, return an error if the file is locked. |
| if (!blocking && dw == ERROR_LOCK_VIOLATION) |
| return -1; // EWOULDBLOCK |
| |
| // If the error is ERROR_IO_PENDING, we need to wait until the operation |
| // finishes. Otherwise, we return an error. |
| if (dw != ERROR_IO_PENDING) |
| return -1; |
| |
| DWORD dwNumBytes; |
| if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE)) |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| COMPILER_RT_VISIBILITY |
| int flock(int fd, int operation) { |
| HANDLE handle = (HANDLE)_get_osfhandle(fd); |
| if (handle == INVALID_HANDLE_VALUE) |
| return -1; |
| |
| BOOL blocking = (operation & LOCK_NB) == 0; |
| int op = operation & ~LOCK_NB; |
| |
| switch (op) { |
| case LOCK_EX: |
| return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking); |
| |
| case LOCK_SH: |
| return lock(handle, 0, blocking); |
| |
| case LOCK_UN: |
| if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD)) |
| return -1; |
| break; |
| |
| default: |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| #undef DWORD_HI |
| #undef DWORD_LO |
| |
| #endif /* _WIN32 */ |