xref: /freebsd/contrib/llvm-project/compiler-rt/lib/profile/WindowsMMap.c (revision 5956d97f4b3204318ceb6aa9c77bd0bc6ea87a41)
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 COMPILER_RT_VISIBILITY
28 void *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 
79 COMPILER_RT_VISIBILITY
80 void munmap(void *addr, size_t length)
81 {
82   UnmapViewOfFile(addr);
83   /* ruh-ro, we leaked handle from CreateFileMapping() ... */
84 }
85 
86 COMPILER_RT_VISIBILITY
87 int 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 
115 COMPILER_RT_VISIBILITY
116 int 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 
127 COMPILER_RT_VISIBILITY
128 int lock(HANDLE handle, DWORD lockType, BOOL blocking) {
129   DWORD flags = lockType;
130   if (!blocking)
131     flags |= LOCKFILE_FAIL_IMMEDIATELY;
132 
133   OVERLAPPED overlapped;
134   ZeroMemory(&overlapped, sizeof(OVERLAPPED));
135   overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
136   BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped);
137   if (!result) {
138     DWORD dw = GetLastError();
139 
140     // In non-blocking mode, return an error if the file is locked.
141     if (!blocking && dw == ERROR_LOCK_VIOLATION)
142       return -1; // EWOULDBLOCK
143 
144     // If the error is ERROR_IO_PENDING, we need to wait until the operation
145     // finishes. Otherwise, we return an error.
146     if (dw != ERROR_IO_PENDING)
147       return -1;
148 
149     DWORD dwNumBytes;
150     if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE))
151       return -1;
152   }
153 
154   return 0;
155 }
156 
157 COMPILER_RT_VISIBILITY
158 int flock(int fd, int operation) {
159   HANDLE handle = (HANDLE)_get_osfhandle(fd);
160   if (handle == INVALID_HANDLE_VALUE)
161     return -1;
162 
163   BOOL blocking = (operation & LOCK_NB) == 0;
164   int op = operation & ~LOCK_NB;
165 
166   switch (op) {
167   case LOCK_EX:
168     return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking);
169 
170   case LOCK_SH:
171     return lock(handle, 0, blocking);
172 
173   case LOCK_UN:
174     if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD))
175       return -1;
176     break;
177 
178   default:
179     return -1;
180   }
181 
182   return 0;
183 }
184 
185 #undef DWORD_HI
186 #undef DWORD_LO
187 
188 #endif /* _WIN32 */
189