1293253Sdim/*
2293253Sdim * This code is derived from uClibc (original license follows).
3293253Sdim * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c
4293253Sdim */
5293253Sdim /* mmap() replacement for Windows
6293253Sdim *
7293253Sdim * Author: Mike Frysinger <vapier@gentoo.org>
8293253Sdim * Placed into the public domain
9293253Sdim */
10293253Sdim
11293253Sdim/* References:
12293253Sdim * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
13293253Sdim * CloseHandle:       http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
14293253Sdim * MapViewOfFile:     http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
15293253Sdim * UnmapViewOfFile:   http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
16293253Sdim */
17293253Sdim
18293253Sdim#if defined(_WIN32)
19293253Sdim
20293253Sdim#include "WindowsMMap.h"
21293253Sdim
22314564Sdim#define WIN32_LEAN_AND_MEAN
23314564Sdim#include <windows.h>
24314564Sdim
25327952Sdim#include "InstrProfiling.h"
26327952Sdim
27293253SdimCOMPILER_RT_VISIBILITY
28293253Sdimvoid *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
29293253Sdim{
30293253Sdim  if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
31293253Sdim    return MAP_FAILED;
32293253Sdim  if (fd == -1) {
33293253Sdim    if (!(flags & MAP_ANON) || offset)
34293253Sdim      return MAP_FAILED;
35293253Sdim  } else if (flags & MAP_ANON)
36293253Sdim    return MAP_FAILED;
37293253Sdim
38293253Sdim  DWORD flProtect;
39293253Sdim  if (prot & PROT_WRITE) {
40293253Sdim    if (prot & PROT_EXEC)
41293253Sdim      flProtect = PAGE_EXECUTE_READWRITE;
42293253Sdim    else
43293253Sdim      flProtect = PAGE_READWRITE;
44293253Sdim  } else if (prot & PROT_EXEC) {
45293253Sdim    if (prot & PROT_READ)
46293253Sdim      flProtect = PAGE_EXECUTE_READ;
47293253Sdim    else if (prot & PROT_EXEC)
48293253Sdim      flProtect = PAGE_EXECUTE;
49293253Sdim  } else
50293253Sdim    flProtect = PAGE_READONLY;
51293253Sdim
52293253Sdim  off_t end = length + offset;
53293253Sdim  HANDLE mmap_fd, h;
54293253Sdim  if (fd == -1)
55293253Sdim    mmap_fd = INVALID_HANDLE_VALUE;
56293253Sdim  else
57293253Sdim    mmap_fd = (HANDLE)_get_osfhandle(fd);
58293253Sdim  h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
59293253Sdim  if (h == NULL)
60293253Sdim    return MAP_FAILED;
61293253Sdim
62293253Sdim  DWORD dwDesiredAccess;
63293253Sdim  if (prot & PROT_WRITE)
64293253Sdim    dwDesiredAccess = FILE_MAP_WRITE;
65293253Sdim  else
66293253Sdim    dwDesiredAccess = FILE_MAP_READ;
67293253Sdim  if (prot & PROT_EXEC)
68293253Sdim    dwDesiredAccess |= FILE_MAP_EXECUTE;
69293253Sdim  if (flags & MAP_PRIVATE)
70293253Sdim    dwDesiredAccess |= FILE_MAP_COPY;
71293253Sdim  void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
72293253Sdim  if (ret == NULL) {
73293253Sdim    CloseHandle(h);
74293253Sdim    ret = MAP_FAILED;
75293253Sdim  }
76293253Sdim  return ret;
77293253Sdim}
78293253Sdim
79293253SdimCOMPILER_RT_VISIBILITY
80293253Sdimvoid munmap(void *addr, size_t length)
81293253Sdim{
82293253Sdim  UnmapViewOfFile(addr);
83293253Sdim  /* ruh-ro, we leaked handle from CreateFileMapping() ... */
84293253Sdim}
85293253Sdim
86293253SdimCOMPILER_RT_VISIBILITY
87293253Sdimint msync(void *addr, size_t length, int flags)
88293253Sdim{
89293253Sdim  if (flags & MS_INVALIDATE)
90293253Sdim    return -1; /* Not supported. */
91293253Sdim
92293253Sdim  /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */
93293253Sdim  switch (flags & (MS_ASYNC | MS_SYNC)) {
94293253Sdim    case MS_SYNC:
95293253Sdim    case MS_ASYNC:
96293253Sdim      break;
97293253Sdim    default:
98293253Sdim      return -1;
99293253Sdim  }
100293253Sdim
101293253Sdim  if (!FlushViewOfFile(addr, length))
102293253Sdim    return -1;
103293253Sdim
104293253Sdim  if (flags & MS_SYNC) {
105293253Sdim    /* FIXME: No longer have access to handle from CreateFileMapping(). */
106293253Sdim    /*
107293253Sdim     * if (!FlushFileBuffers(h))
108293253Sdim     *   return -1;
109293253Sdim     */
110293253Sdim  }
111293253Sdim
112293253Sdim  return 0;
113293253Sdim}
114293253Sdim
115293253SdimCOMPILER_RT_VISIBILITY
116327952Sdimint lock(HANDLE handle, DWORD lockType, BOOL blocking) {
117327952Sdim  DWORD flags = lockType;
118327952Sdim  if (!blocking)
119327952Sdim    flags |= LOCKFILE_FAIL_IMMEDIATELY;
120327952Sdim
121327952Sdim  OVERLAPPED overlapped;
122327952Sdim  ZeroMemory(&overlapped, sizeof(OVERLAPPED));
123327952Sdim  overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
124327952Sdim  BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped);
125327952Sdim  if (!result) {
126327952Sdim    DWORD dw = GetLastError();
127327952Sdim
128327952Sdim    // In non-blocking mode, return an error if the file is locked.
129327952Sdim    if (!blocking && dw == ERROR_LOCK_VIOLATION)
130327952Sdim      return -1; // EWOULDBLOCK
131327952Sdim
132327952Sdim    // If the error is ERROR_IO_PENDING, we need to wait until the operation
133327952Sdim    // finishes. Otherwise, we return an error.
134327952Sdim    if (dw != ERROR_IO_PENDING)
135327952Sdim      return -1;
136327952Sdim
137327952Sdim    DWORD dwNumBytes;
138327952Sdim    if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE))
139327952Sdim      return -1;
140327952Sdim  }
141327952Sdim
142327952Sdim  return 0;
143293253Sdim}
144293253Sdim
145327952SdimCOMPILER_RT_VISIBILITY
146327952Sdimint flock(int fd, int operation) {
147327952Sdim  HANDLE handle = (HANDLE)_get_osfhandle(fd);
148327952Sdim  if (handle == INVALID_HANDLE_VALUE)
149327952Sdim    return -1;
150327952Sdim
151327952Sdim  BOOL blocking = (operation & LOCK_NB) == 0;
152327952Sdim  int op = operation & ~LOCK_NB;
153327952Sdim
154327952Sdim  switch (op) {
155327952Sdim  case LOCK_EX:
156327952Sdim    return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking);
157327952Sdim
158327952Sdim  case LOCK_SH:
159327952Sdim    return lock(handle, 0, blocking);
160327952Sdim
161327952Sdim  case LOCK_UN:
162327952Sdim    if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD))
163327952Sdim      return -1;
164327952Sdim    break;
165327952Sdim
166327952Sdim  default:
167327952Sdim    return -1;
168327952Sdim  }
169327952Sdim
170327952Sdim  return 0;
171327952Sdim}
172327952Sdim
173293253Sdim#undef DWORD_HI
174293253Sdim#undef DWORD_LO
175293253Sdim
176293253Sdim#endif /* _WIN32 */
177