1/*
2 * This code is derived from uClibc (original license follows).
3 * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c
4 */
5 /* mmap() replacement for Windows
6 *
7 * Author: Mike Frysinger <vapier@gentoo.org>
8 * Placed into the public domain
9 */
10
11/* References:
12 * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
13 * CloseHandle:       http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
14 * MapViewOfFile:     http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
15 * UnmapViewOfFile:   http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
16 */
17
18#if defined(_WIN32)
19
20#include "WindowsMMap.h"
21
22#define WIN32_LEAN_AND_MEAN
23#include <windows.h>
24
25#include "InstrProfiling.h"
26
27COMPILER_RT_VISIBILITY
28void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
29{
30  if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
31    return MAP_FAILED;
32  if (fd == -1) {
33    if (!(flags & MAP_ANON) || offset)
34      return MAP_FAILED;
35  } else if (flags & MAP_ANON)
36    return MAP_FAILED;
37
38  DWORD flProtect;
39  if (prot & PROT_WRITE) {
40    if (prot & PROT_EXEC)
41      flProtect = PAGE_EXECUTE_READWRITE;
42    else
43      flProtect = PAGE_READWRITE;
44  } else if (prot & PROT_EXEC) {
45    if (prot & PROT_READ)
46      flProtect = PAGE_EXECUTE_READ;
47    else if (prot & PROT_EXEC)
48      flProtect = PAGE_EXECUTE;
49  } else
50    flProtect = PAGE_READONLY;
51
52  off_t end = length + offset;
53  HANDLE mmap_fd, h;
54  if (fd == -1)
55    mmap_fd = INVALID_HANDLE_VALUE;
56  else
57    mmap_fd = (HANDLE)_get_osfhandle(fd);
58  h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
59  if (h == NULL)
60    return MAP_FAILED;
61
62  DWORD dwDesiredAccess;
63  if (prot & PROT_WRITE)
64    dwDesiredAccess = FILE_MAP_WRITE;
65  else
66    dwDesiredAccess = FILE_MAP_READ;
67  if (prot & PROT_EXEC)
68    dwDesiredAccess |= FILE_MAP_EXECUTE;
69  if (flags & MAP_PRIVATE)
70    dwDesiredAccess |= FILE_MAP_COPY;
71  void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
72  if (ret == NULL) {
73    CloseHandle(h);
74    ret = MAP_FAILED;
75  }
76  return ret;
77}
78
79COMPILER_RT_VISIBILITY
80void munmap(void *addr, size_t length)
81{
82  UnmapViewOfFile(addr);
83  /* ruh-ro, we leaked handle from CreateFileMapping() ... */
84}
85
86COMPILER_RT_VISIBILITY
87int msync(void *addr, size_t length, int flags)
88{
89  if (flags & MS_INVALIDATE)
90    return -1; /* Not supported. */
91
92  /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */
93  switch (flags & (MS_ASYNC | MS_SYNC)) {
94    case MS_SYNC:
95    case MS_ASYNC:
96      break;
97    default:
98      return -1;
99  }
100
101  if (!FlushViewOfFile(addr, length))
102    return -1;
103
104  if (flags & MS_SYNC) {
105    /* FIXME: No longer have access to handle from CreateFileMapping(). */
106    /*
107     * if (!FlushFileBuffers(h))
108     *   return -1;
109     */
110  }
111
112  return 0;
113}
114
115COMPILER_RT_VISIBILITY
116int madvise(void *addr, size_t length, int advice)
117{
118  if (advice != MADV_DONTNEED)
119    return -1; /* Not supported. */
120
121  if (!VirtualUnlock(addr, length))
122    return -1;
123
124  return 0;
125}
126
127static int lock(HANDLE handle, DWORD lockType, BOOL blocking) {
128  DWORD flags = lockType;
129  if (!blocking)
130    flags |= LOCKFILE_FAIL_IMMEDIATELY;
131
132  OVERLAPPED overlapped;
133  ZeroMemory(&overlapped, sizeof(OVERLAPPED));
134  overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
135  BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped);
136  if (!result) {
137    DWORD dw = GetLastError();
138
139    // In non-blocking mode, return an error if the file is locked.
140    if (!blocking && dw == ERROR_LOCK_VIOLATION)
141      return -1; // EWOULDBLOCK
142
143    // If the error is ERROR_IO_PENDING, we need to wait until the operation
144    // finishes. Otherwise, we return an error.
145    if (dw != ERROR_IO_PENDING)
146      return -1;
147
148    DWORD dwNumBytes;
149    if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE))
150      return -1;
151  }
152
153  return 0;
154}
155
156COMPILER_RT_VISIBILITY
157int flock(int fd, int operation) {
158  HANDLE handle = (HANDLE)_get_osfhandle(fd);
159  if (handle == INVALID_HANDLE_VALUE)
160    return -1;
161
162  BOOL blocking = (operation & LOCK_NB) == 0;
163  int op = operation & ~LOCK_NB;
164
165  switch (op) {
166  case LOCK_EX:
167    return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking);
168
169  case LOCK_SH:
170    return lock(handle, 0, blocking);
171
172  case LOCK_UN:
173    if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD))
174      return -1;
175    break;
176
177  default:
178    return -1;
179  }
180
181  return 0;
182}
183
184#undef DWORD_HI
185#undef DWORD_LO
186
187#endif /* _WIN32 */
188