WindowsMMap.c revision 327952
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
27#ifdef __USE_FILE_OFFSET64
28# define DWORD_HI(x) (x >> 32)
29# define DWORD_LO(x) ((x) & 0xffffffff)
30#else
31# define DWORD_HI(x) (0)
32# define DWORD_LO(x) (x)
33#endif
34
35COMPILER_RT_VISIBILITY
36void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
37{
38  if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
39    return MAP_FAILED;
40  if (fd == -1) {
41    if (!(flags & MAP_ANON) || offset)
42      return MAP_FAILED;
43  } else if (flags & MAP_ANON)
44    return MAP_FAILED;
45
46  DWORD flProtect;
47  if (prot & PROT_WRITE) {
48    if (prot & PROT_EXEC)
49      flProtect = PAGE_EXECUTE_READWRITE;
50    else
51      flProtect = PAGE_READWRITE;
52  } else if (prot & PROT_EXEC) {
53    if (prot & PROT_READ)
54      flProtect = PAGE_EXECUTE_READ;
55    else if (prot & PROT_EXEC)
56      flProtect = PAGE_EXECUTE;
57  } else
58    flProtect = PAGE_READONLY;
59
60  off_t end = length + offset;
61  HANDLE mmap_fd, h;
62  if (fd == -1)
63    mmap_fd = INVALID_HANDLE_VALUE;
64  else
65    mmap_fd = (HANDLE)_get_osfhandle(fd);
66  h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
67  if (h == NULL)
68    return MAP_FAILED;
69
70  DWORD dwDesiredAccess;
71  if (prot & PROT_WRITE)
72    dwDesiredAccess = FILE_MAP_WRITE;
73  else
74    dwDesiredAccess = FILE_MAP_READ;
75  if (prot & PROT_EXEC)
76    dwDesiredAccess |= FILE_MAP_EXECUTE;
77  if (flags & MAP_PRIVATE)
78    dwDesiredAccess |= FILE_MAP_COPY;
79  void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
80  if (ret == NULL) {
81    CloseHandle(h);
82    ret = MAP_FAILED;
83  }
84  return ret;
85}
86
87COMPILER_RT_VISIBILITY
88void munmap(void *addr, size_t length)
89{
90  UnmapViewOfFile(addr);
91  /* ruh-ro, we leaked handle from CreateFileMapping() ... */
92}
93
94COMPILER_RT_VISIBILITY
95int msync(void *addr, size_t length, int flags)
96{
97  if (flags & MS_INVALIDATE)
98    return -1; /* Not supported. */
99
100  /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */
101  switch (flags & (MS_ASYNC | MS_SYNC)) {
102    case MS_SYNC:
103    case MS_ASYNC:
104      break;
105    default:
106      return -1;
107  }
108
109  if (!FlushViewOfFile(addr, length))
110    return -1;
111
112  if (flags & MS_SYNC) {
113    /* FIXME: No longer have access to handle from CreateFileMapping(). */
114    /*
115     * if (!FlushFileBuffers(h))
116     *   return -1;
117     */
118  }
119
120  return 0;
121}
122
123COMPILER_RT_VISIBILITY
124int lock(HANDLE handle, DWORD lockType, BOOL blocking) {
125  DWORD flags = lockType;
126  if (!blocking)
127    flags |= LOCKFILE_FAIL_IMMEDIATELY;
128
129  OVERLAPPED overlapped;
130  ZeroMemory(&overlapped, sizeof(OVERLAPPED));
131  overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
132  BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped);
133  if (!result) {
134    DWORD dw = GetLastError();
135
136    // In non-blocking mode, return an error if the file is locked.
137    if (!blocking && dw == ERROR_LOCK_VIOLATION)
138      return -1; // EWOULDBLOCK
139
140    // If the error is ERROR_IO_PENDING, we need to wait until the operation
141    // finishes. Otherwise, we return an error.
142    if (dw != ERROR_IO_PENDING)
143      return -1;
144
145    DWORD dwNumBytes;
146    if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE))
147      return -1;
148  }
149
150  return 0;
151}
152
153COMPILER_RT_VISIBILITY
154int flock(int fd, int operation) {
155  HANDLE handle = (HANDLE)_get_osfhandle(fd);
156  if (handle == INVALID_HANDLE_VALUE)
157    return -1;
158
159  BOOL blocking = (operation & LOCK_NB) == 0;
160  int op = operation & ~LOCK_NB;
161
162  switch (op) {
163  case LOCK_EX:
164    return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking);
165
166  case LOCK_SH:
167    return lock(handle, 0, blocking);
168
169  case LOCK_UN:
170    if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD))
171      return -1;
172    break;
173
174  default:
175    return -1;
176  }
177
178  return 0;
179}
180
181#undef DWORD_HI
182#undef DWORD_LO
183
184#endif /* _WIN32 */
185