10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric * This code is derived from uClibc (original license follows).
30b57cec5SDimitry Andric * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c
40b57cec5SDimitry Andric */
50b57cec5SDimitry Andric /* mmap() replacement for Windows
60b57cec5SDimitry Andric *
70b57cec5SDimitry Andric * Author: Mike Frysinger <vapier@gentoo.org>
80b57cec5SDimitry Andric * Placed into the public domain
90b57cec5SDimitry Andric */
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric /* References:
120b57cec5SDimitry Andric * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
130b57cec5SDimitry Andric * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
140b57cec5SDimitry Andric * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
150b57cec5SDimitry Andric * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
160b57cec5SDimitry Andric */
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric #if defined(_WIN32)
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric #include "WindowsMMap.h"
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric #define WIN32_LEAN_AND_MEAN
230b57cec5SDimitry Andric #include <windows.h>
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric #include "InstrProfiling.h"
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
mmap(void * start,size_t length,int prot,int flags,int fd,off_t offset)280b57cec5SDimitry Andric void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
290b57cec5SDimitry Andric {
300b57cec5SDimitry Andric if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
310b57cec5SDimitry Andric return MAP_FAILED;
320b57cec5SDimitry Andric if (fd == -1) {
330b57cec5SDimitry Andric if (!(flags & MAP_ANON) || offset)
340b57cec5SDimitry Andric return MAP_FAILED;
350b57cec5SDimitry Andric } else if (flags & MAP_ANON)
360b57cec5SDimitry Andric return MAP_FAILED;
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric DWORD flProtect;
390b57cec5SDimitry Andric if (prot & PROT_WRITE) {
400b57cec5SDimitry Andric if (prot & PROT_EXEC)
410b57cec5SDimitry Andric flProtect = PAGE_EXECUTE_READWRITE;
420b57cec5SDimitry Andric else
430b57cec5SDimitry Andric flProtect = PAGE_READWRITE;
440b57cec5SDimitry Andric } else if (prot & PROT_EXEC) {
450b57cec5SDimitry Andric if (prot & PROT_READ)
460b57cec5SDimitry Andric flProtect = PAGE_EXECUTE_READ;
470b57cec5SDimitry Andric else if (prot & PROT_EXEC)
480b57cec5SDimitry Andric flProtect = PAGE_EXECUTE;
490b57cec5SDimitry Andric } else
500b57cec5SDimitry Andric flProtect = PAGE_READONLY;
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric off_t end = length + offset;
530b57cec5SDimitry Andric HANDLE mmap_fd, h;
540b57cec5SDimitry Andric if (fd == -1)
550b57cec5SDimitry Andric mmap_fd = INVALID_HANDLE_VALUE;
560b57cec5SDimitry Andric else
570b57cec5SDimitry Andric mmap_fd = (HANDLE)_get_osfhandle(fd);
580b57cec5SDimitry Andric h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
590b57cec5SDimitry Andric if (h == NULL)
600b57cec5SDimitry Andric return MAP_FAILED;
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric DWORD dwDesiredAccess;
630b57cec5SDimitry Andric if (prot & PROT_WRITE)
640b57cec5SDimitry Andric dwDesiredAccess = FILE_MAP_WRITE;
650b57cec5SDimitry Andric else
660b57cec5SDimitry Andric dwDesiredAccess = FILE_MAP_READ;
670b57cec5SDimitry Andric if (prot & PROT_EXEC)
680b57cec5SDimitry Andric dwDesiredAccess |= FILE_MAP_EXECUTE;
690b57cec5SDimitry Andric if (flags & MAP_PRIVATE)
700b57cec5SDimitry Andric dwDesiredAccess |= FILE_MAP_COPY;
710b57cec5SDimitry Andric void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
720b57cec5SDimitry Andric if (ret == NULL) {
730b57cec5SDimitry Andric CloseHandle(h);
740b57cec5SDimitry Andric ret = MAP_FAILED;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric return ret;
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric
790b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
munmap(void * addr,size_t length)800b57cec5SDimitry Andric void munmap(void *addr, size_t length)
810b57cec5SDimitry Andric {
820b57cec5SDimitry Andric UnmapViewOfFile(addr);
830b57cec5SDimitry Andric /* ruh-ro, we leaked handle from CreateFileMapping() ... */
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
msync(void * addr,size_t length,int flags)870b57cec5SDimitry Andric int msync(void *addr, size_t length, int flags)
880b57cec5SDimitry Andric {
890b57cec5SDimitry Andric if (flags & MS_INVALIDATE)
900b57cec5SDimitry Andric return -1; /* Not supported. */
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */
930b57cec5SDimitry Andric switch (flags & (MS_ASYNC | MS_SYNC)) {
940b57cec5SDimitry Andric case MS_SYNC:
950b57cec5SDimitry Andric case MS_ASYNC:
960b57cec5SDimitry Andric break;
970b57cec5SDimitry Andric default:
980b57cec5SDimitry Andric return -1;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric if (!FlushViewOfFile(addr, length))
1020b57cec5SDimitry Andric return -1;
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric if (flags & MS_SYNC) {
1050b57cec5SDimitry Andric /* FIXME: No longer have access to handle from CreateFileMapping(). */
1060b57cec5SDimitry Andric /*
1070b57cec5SDimitry Andric * if (!FlushFileBuffers(h))
1080b57cec5SDimitry Andric * return -1;
1090b57cec5SDimitry Andric */
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric return 0;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
madvise(void * addr,size_t length,int advice)116fe6060f1SDimitry Andric int madvise(void *addr, size_t length, int advice)
117fe6060f1SDimitry Andric {
118fe6060f1SDimitry Andric if (advice != MADV_DONTNEED)
119fe6060f1SDimitry Andric return -1; /* Not supported. */
120fe6060f1SDimitry Andric
121fe6060f1SDimitry Andric if (!VirtualUnlock(addr, length))
122fe6060f1SDimitry Andric return -1;
123fe6060f1SDimitry Andric
124fe6060f1SDimitry Andric return 0;
125fe6060f1SDimitry Andric }
126fe6060f1SDimitry Andric
lock(HANDLE handle,DWORD lockType,BOOL blocking)127*7a6dacacSDimitry Andric static int lock(HANDLE handle, DWORD lockType, BOOL blocking) {
1280b57cec5SDimitry Andric DWORD flags = lockType;
1290b57cec5SDimitry Andric if (!blocking)
1300b57cec5SDimitry Andric flags |= LOCKFILE_FAIL_IMMEDIATELY;
1310b57cec5SDimitry Andric
1320b57cec5SDimitry Andric OVERLAPPED overlapped;
1330b57cec5SDimitry Andric ZeroMemory(&overlapped, sizeof(OVERLAPPED));
1340b57cec5SDimitry Andric overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1350b57cec5SDimitry Andric BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped);
1360b57cec5SDimitry Andric if (!result) {
1370b57cec5SDimitry Andric DWORD dw = GetLastError();
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric // In non-blocking mode, return an error if the file is locked.
1400b57cec5SDimitry Andric if (!blocking && dw == ERROR_LOCK_VIOLATION)
1410b57cec5SDimitry Andric return -1; // EWOULDBLOCK
1420b57cec5SDimitry Andric
1430b57cec5SDimitry Andric // If the error is ERROR_IO_PENDING, we need to wait until the operation
1440b57cec5SDimitry Andric // finishes. Otherwise, we return an error.
1450b57cec5SDimitry Andric if (dw != ERROR_IO_PENDING)
1460b57cec5SDimitry Andric return -1;
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric DWORD dwNumBytes;
1490b57cec5SDimitry Andric if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE))
1500b57cec5SDimitry Andric return -1;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric return 0;
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric
1560b57cec5SDimitry Andric COMPILER_RT_VISIBILITY
flock(int fd,int operation)1570b57cec5SDimitry Andric int flock(int fd, int operation) {
1580b57cec5SDimitry Andric HANDLE handle = (HANDLE)_get_osfhandle(fd);
1590b57cec5SDimitry Andric if (handle == INVALID_HANDLE_VALUE)
1600b57cec5SDimitry Andric return -1;
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric BOOL blocking = (operation & LOCK_NB) == 0;
1630b57cec5SDimitry Andric int op = operation & ~LOCK_NB;
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric switch (op) {
1660b57cec5SDimitry Andric case LOCK_EX:
1670b57cec5SDimitry Andric return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking);
1680b57cec5SDimitry Andric
1690b57cec5SDimitry Andric case LOCK_SH:
1700b57cec5SDimitry Andric return lock(handle, 0, blocking);
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric case LOCK_UN:
1730b57cec5SDimitry Andric if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD))
1740b57cec5SDimitry Andric return -1;
1750b57cec5SDimitry Andric break;
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric default:
1780b57cec5SDimitry Andric return -1;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric return 0;
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric #undef DWORD_HI
1850b57cec5SDimitry Andric #undef DWORD_LO
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric #endif /* _WIN32 */
188