blob: dc87a888ae7b129c5bc96a0fe46b667823229369 [file] [log] [blame]
/*
* 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 */